From 20b958301eb208fe9ed0ae8edfb14b6f3741d8f2 Mon Sep 17 00:00:00 2001 From: Cameron Mace Date: Fri, 16 Dec 2016 16:19:15 -0500 Subject: Adds checkstyle to CI (#7442) * adds checkstyle to CI * fixed gradlew path * resolved testapp checkstyle violations * added back mapboxMap variable for test * checkstyle annotations * checkstyle SDK round 1 * maps package checkstyle * rest of SDK checkstyle * checkstyle gesture library * checkstyle test * finished rest of test checkstyle * resolved all checkstyle errors * fixed class name * removed old test file * fixed camera postion test * fixed native crash --- platform/android/MapboxGLAndroidSDK/build.gradle | 3 +- .../MapboxGLAndroidSDK/gradle-checkstyle.gradle | 17 + .../gesturedetectors/BaseGestureDetector.java | 241 +- .../gesturedetectors/MoveGestureDetector.java | 260 +- .../gesturedetectors/RotateGestureDetector.java | 260 +- .../gesturedetectors/ShoveGestureDetector.java | 317 +- .../gesturedetectors/TwoFingerGestureDetector.java | 358 +- .../com/mapbox/mapboxsdk/MapboxAccountManager.java | 216 +- .../mapbox/mapboxsdk/annotations/Annotation.java | 214 +- .../mapboxsdk/annotations/BaseMarkerOptions.java | 186 +- .../annotations/BaseMarkerViewOptions.java | 473 +-- .../com/mapbox/mapboxsdk/annotations/Icon.java | 114 +- .../mapbox/mapboxsdk/annotations/IconFactory.java | 376 +- .../mapbox/mapboxsdk/annotations/InfoWindow.java | 503 +-- .../mapboxsdk/annotations/InfoWindowTipView.java | 94 +- .../mapboxsdk/annotations/InfoWindowView.java | 52 +- .../com/mapbox/mapboxsdk/annotations/Marker.java | 428 +-- .../mapboxsdk/annotations/MarkerOptions.java | 297 +- .../mapbox/mapboxsdk/annotations/MarkerView.java | 758 ++-- .../mapboxsdk/annotations/MarkerViewManager.java | 1089 +++--- .../mapboxsdk/annotations/MarkerViewOptions.java | 258 +- .../mapbox/mapboxsdk/annotations/MultiPoint.java | 102 +- .../com/mapbox/mapboxsdk/annotations/Polygon.java | 90 +- .../mapboxsdk/annotations/PolygonOptions.java | 418 +-- .../com/mapbox/mapboxsdk/annotations/Polyline.java | 90 +- .../mapboxsdk/annotations/PolylineOptions.java | 428 +-- .../mapbox/mapboxsdk/camera/CameraPosition.java | 506 +-- .../com/mapbox/mapboxsdk/camera/CameraUpdate.java | 2 +- .../mapboxsdk/camera/CameraUpdateFactory.java | 720 ++-- .../mapbox/mapboxsdk/constants/GeoConstants.java | 50 +- .../mapboxsdk/constants/MapboxConstants.java | 270 +- .../mapboxsdk/constants/MyBearingTracking.java | 51 +- .../mapboxsdk/constants/MyLocationTracking.java | 36 +- .../java/com/mapbox/mapboxsdk/constants/Style.java | 98 +- .../mapboxsdk/exceptions/ConversionException.java | 22 +- .../exceptions/IconBitmapChangedException.java | 8 +- .../exceptions/InvalidAccessTokenException.java | 15 +- .../exceptions/InvalidLatLngBoundsException.java | 6 +- .../exceptions/InvalidMarkerPositionException.java | 10 +- .../MapboxAccountManagerNotStartedException.java | 13 +- .../TelemetryServiceNotConfiguredException.java | 11 +- .../exceptions/TooManyIconsException.java | 6 +- .../com/mapbox/mapboxsdk/geometry/ILatLng.java | 6 +- .../mapboxsdk/geometry/IProjectedMeters.java | 4 +- .../java/com/mapbox/mapboxsdk/geometry/LatLng.java | 366 +- .../mapbox/mapboxsdk/geometry/LatLngBounds.java | 556 +-- .../com/mapbox/mapboxsdk/geometry/LatLngSpan.java | 156 +- .../mapbox/mapboxsdk/geometry/ProjectedMeters.java | 189 +- .../mapbox/mapboxsdk/geometry/VisibleRegion.java | 219 +- .../com/mapbox/mapboxsdk/http/HTTPRequest.java | 306 +- .../mapboxsdk/location/LocationListener.java | 11 +- .../mapboxsdk/location/LocationServices.java | 294 +- .../mapbox/mapboxsdk/maps/AnnotationManager.java | 1107 +++--- .../mapboxsdk/maps/FocalPointChangeListener.java | 2 +- .../com/mapbox/mapboxsdk/maps/IconManager.java | 232 +- .../mapbox/mapboxsdk/maps/InfoWindowManager.java | 99 +- .../com/mapbox/mapboxsdk/maps/MapFragment.java | 367 +- .../mapbox/mapboxsdk/maps/MapGestureDetector.java | 1040 +++--- .../com/mapbox/mapboxsdk/maps/MapKeyListener.java | 437 +-- .../java/com/mapbox/mapboxsdk/maps/MapView.java | 2321 ++++++------ .../java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 3585 +++++++++--------- .../mapbox/mapboxsdk/maps/MapboxMapOptions.java | 2160 +++++------ .../com/mapbox/mapboxsdk/maps/NativeMapView.java | 1233 +++---- .../mapbox/mapboxsdk/maps/OnMapReadyCallback.java | 17 +- .../java/com/mapbox/mapboxsdk/maps/Projection.java | 205 +- .../mapbox/mapboxsdk/maps/SupportMapFragment.java | 384 +- .../mapbox/mapboxsdk/maps/TrackingSettings.java | 565 +-- .../java/com/mapbox/mapboxsdk/maps/Transform.java | 437 +-- .../java/com/mapbox/mapboxsdk/maps/UiSettings.java | 1389 +++---- .../mapbox/mapboxsdk/maps/widgets/CompassView.java | 232 +- .../mapboxsdk/maps/widgets/MyLocationView.java | 1245 +++---- .../maps/widgets/MyLocationViewSettings.java | 548 +-- .../mapbox/mapboxsdk/net/ConnectivityListener.java | 2 +- .../mapbox/mapboxsdk/net/ConnectivityReceiver.java | 129 +- .../mapboxsdk/net/NativeConnectivityListener.java | 38 +- .../mapbox/mapboxsdk/offline/OfflineManager.java | 524 +-- .../mapbox/mapboxsdk/offline/OfflineRegion.java | 705 ++-- .../mapboxsdk/offline/OfflineRegionDefinition.java | 2 +- .../mapboxsdk/offline/OfflineRegionError.java | 83 +- .../mapboxsdk/offline/OfflineRegionStatus.java | 184 +- .../OfflineTilePyramidRegionDefinition.java | 80 +- .../mapboxsdk/style/layers/BackgroundLayer.java | 166 +- .../style/layers/CannotAddLayerException.java | 6 +- .../mapbox/mapboxsdk/style/layers/CircleLayer.java | 456 +-- .../mapbox/mapboxsdk/style/layers/CustomLayer.java | 35 +- .../mapbox/mapboxsdk/style/layers/FillLayer.java | 437 +-- .../com/mapbox/mapboxsdk/style/layers/Filter.java | 422 +-- .../mapbox/mapboxsdk/style/layers/Function.java | 210 +- .../com/mapbox/mapboxsdk/style/layers/Layer.java | 110 +- .../mapboxsdk/style/layers/LayoutProperty.java | 6 +- .../mapbox/mapboxsdk/style/layers/LineLayer.java | 569 +-- .../style/layers/NoSuchLayerException.java | 6 +- .../mapboxsdk/style/layers/PaintProperty.java | 6 +- .../mapbox/mapboxsdk/style/layers/Property.java | 919 ++--- .../mapboxsdk/style/layers/PropertyFactory.java | 3848 ++++++++++---------- .../mapboxsdk/style/layers/PropertyValue.java | 74 +- .../mapbox/mapboxsdk/style/layers/RasterLayer.java | 290 +- .../mapbox/mapboxsdk/style/layers/SymbolLayer.java | 1380 +++---- .../style/sources/CannotAddSourceException.java | 6 +- .../mapboxsdk/style/sources/GeoJsonOptions.java | 122 +- .../mapboxsdk/style/sources/GeoJsonSource.java | 318 +- .../style/sources/NoSuchSourceException.java | 6 +- .../mapboxsdk/style/sources/RasterSource.java | 118 +- .../com/mapbox/mapboxsdk/style/sources/Source.java | 94 +- .../mapbox/mapboxsdk/style/sources/TileSet.java | 575 +-- .../mapboxsdk/style/sources/VectorSource.java | 86 +- .../telemetry/GzipRequestInterceptor.java | 66 +- .../mapbox/mapboxsdk/telemetry/MapboxEvent.java | 248 +- .../mapboxsdk/telemetry/MapboxEventManager.java | 1354 +++---- .../telemetry/TelemetryLocationReceiver.java | 105 +- .../mapboxsdk/telemetry/TelemetryService.java | 263 +- .../com/mapbox/mapboxsdk/utils/AnimatorUtils.java | 160 +- .../com/mapbox/mapboxsdk/utils/ColorUtils.java | 183 +- .../java/com/mapbox/mapboxsdk/utils/MathUtils.java | 106 +- .../android/MapboxGLAndroidSDKTestApp/build.gradle | 1 + .../gradle-checkstyle.gradle | 17 + .../com/mapbox/mapboxsdk/maps/MapViewUtils.java | 36 +- .../com/mapbox/mapboxsdk/maps/MapboxMapTest.java | 1535 ++++---- .../testapp/activity/BaseActivityTest.java | 78 +- .../mapboxsdk/testapp/annotations/MarkerTest.java | 180 +- .../testapp/annotations/MarkerViewTest.java | 191 +- .../mapboxsdk/testapp/annotations/PolygonTest.java | 129 +- .../testapp/annotations/PolylineTest.java | 120 +- .../testapp/camera/CameraAnimateTest.java | 405 +- .../mapboxsdk/testapp/camera/CameraEaseTest.java | 404 +- .../testapp/camera/CameraInternalAPITest.java | 167 - .../testapp/camera/CameraInternalApiTest.java | 169 + .../mapboxsdk/testapp/camera/CameraMoveTest.java | 405 +- .../feature/QueryRenderedFeaturesBoxCountTest.java | 55 +- .../QueryRenderedFeaturesHighlightTest.java | 75 +- .../QueryRenderedFeaturesPropertiesTest.java | 73 +- .../feature/QueryRenderedSymbolBoxCountTest.java | 55 +- .../testapp/maps/widgets/AttributionTest.java | 218 +- .../testapp/maps/widgets/CompassViewTest.java | 200 +- .../mapboxsdk/testapp/maps/widgets/LogoTest.java | 84 +- .../testapp/maps/widgets/MyLocationViewTest.java | 318 +- .../testapp/style/BackgroundLayerStyleTest.java | 168 +- .../testapp/style/BackgroundLayerTest.java | 168 +- .../mapboxsdk/testapp/style/BaseStyleTest.java | 40 +- .../testapp/style/CircleLayerStyleTest.java | 432 +-- .../mapboxsdk/testapp/style/CircleLayerTest.java | 603 +-- .../testapp/style/FillLayerStyleTest.java | 473 +-- .../mapboxsdk/testapp/style/FillLayerTest.java | 473 +-- .../testapp/style/LineLayerStyleTest.java | 734 ++-- .../mapboxsdk/testapp/style/LineLayerTest.java | 734 ++-- .../testapp/style/RasterLayerStyleTest.java | 388 +- .../mapboxsdk/testapp/style/RasterLayerTest.java | 389 +- .../style/RuntimeStyleBackgroundLayerTest.java | 71 +- .../mapboxsdk/testapp/style/RuntimeStyleTests.java | 278 +- .../testapp/style/RuntimeStyleTimingTests.java | 43 +- .../testapp/style/SymbolLayerStyleTest.java | 2330 ++++++------ .../mapboxsdk/testapp/style/SymbolLayerTest.java | 2330 ++++++------ .../mapboxsdk/testapp/utils/DrawerUtils.java | 16 +- .../mapboxsdk/testapp/utils/GestureUtils.java | 6 +- .../testapp/utils/OnMapReadyIdlingResource.java | 75 +- .../mapboxsdk/testapp/utils/ScreenshotUtil.java | 189 +- .../mapboxsdk/testapp/utils/TestConstants.java | 18 +- .../mapbox/mapboxsdk/testapp/utils/ViewUtils.java | 16 +- .../mapboxsdk/testapp/MapboxApplication.java | 63 +- .../testapp/activity/FeatureOverviewActivity.java | 336 +- .../annotation/AddRemoveMarkerActivity.java | 270 +- .../annotation/AnimatedMarkerActivity.java | 434 ++- .../activity/annotation/BulkMarkerActivity.java | 446 +-- .../annotation/DynamicMarkerChangeActivity.java | 230 +- .../activity/annotation/MarkerViewActivity.java | 808 ++-- .../annotation/MarkerViewScaleActivity.java | 260 +- .../annotation/MarkerViewsInRectangleActivity.java | 210 +- .../activity/annotation/PolygonActivity.java | 299 +- .../activity/annotation/PolylineActivity.java | 376 +- .../annotation/PressForMarkerActivity.java | 229 +- .../camera/CameraAnimationTypeActivity.java | 342 +- .../activity/camera/CameraPositionActivity.java | 329 +- .../activity/camera/LatLngBoundsActivity.java | 220 +- .../activity/camera/ManualZoomActivity.java | 202 +- .../activity/camera/MaxMinZoomActivity.java | 152 +- .../testapp/activity/camera/ScrollByActivity.java | 228 +- .../activity/customlayer/CustomLayerActivity.java | 270 +- .../activity/directions/DirectionsActivity.java | 317 +- .../activity/espresso/EspressoTestActivity.java | 106 +- .../QueryRenderedFeaturesBoxCountActivity.java | 256 +- .../QueryRenderedFeaturesBoxHighlightActivity.java | 239 +- ...ueryRenderedFeaturesBoxSymbolCountActivity.java | 269 +- .../QueryRenderedFeaturesPropertiesActivity.java | 400 +- .../activity/fragment/MapFragmentActivity.java | 106 +- .../activity/fragment/MultiMapActivity.java | 10 +- .../fragment/SupportMapFragmentActivity.java | 109 +- .../activity/fragment/ViewPagerActivity.java | 138 +- .../activity/geocoding/GeocoderActivity.java | 308 +- .../activity/imagegenerator/PrintActivity.java | 182 +- .../activity/imagegenerator/SnapshotActivity.java | 192 +- .../DynamicInfoWindowAdapterActivity.java | 267 +- .../activity/infowindow/InfoWindowActivity.java | 348 +- .../infowindow/InfoWindowAdapterActivity.java | 250 +- .../activity/maplayout/DebugModeActivity.java | 222 +- .../activity/maplayout/DoubleMapActivity.java | 268 +- .../activity/maplayout/MapInDialogActivity.java | 199 +- .../activity/maplayout/MapPaddingActivity.java | 250 +- .../maplayout/NavigationDrawerActivity.java | 384 +- .../activity/maplayout/SimpleMapActivity.java | 126 +- .../activity/navigation/CarDrivingActivity.java | 294 +- .../navigation/LocationPickerActivity.java | 738 ++-- .../testapp/activity/offline/OfflineActivity.java | 602 +-- .../activity/offline/UpdateMetadataActivity.java | 264 +- .../activity/style/CircleLayerActivity.java | 222 +- .../activity/style/CustomSpriteActivity.java | 237 +- .../activity/style/GeoJsonClusteringActivity.java | 274 +- .../activity/style/RealTimeGeoJsonActivity.java | 198 +- .../activity/style/RuntimeStyleActivity.java | 922 ++--- .../activity/style/RuntimeStyleTestActivity.java | 108 +- .../style/RuntimeStyleTimingTestActivity.java | 152 +- .../testapp/activity/style/StyleFileActivity.java | 14 +- .../activity/style/SymbolLayerActivity.java | 321 +- .../userlocation/MyLocationDrawableActivity.java | 282 +- .../userlocation/MyLocationTintActivity.java | 390 +- .../userlocation/MyLocationToggleActivity.java | 265 +- .../MyLocationTrackingModeActivity.java | 586 +-- .../mapboxsdk/testapp/adapter/FeatureAdapter.java | 66 +- .../testapp/adapter/FeatureSectionAdapter.java | 265 +- .../mapboxsdk/testapp/model/activity/Feature.java | 112 +- .../testapp/model/annotations/CityStateMarker.java | 16 +- .../model/annotations/CityStateMarkerOptions.java | 88 +- .../testapp/model/annotations/CountryMarker.java | 26 +- .../model/annotations/CountryMarkerOptions.java | 98 +- .../model/annotations/CountryMarkerView.java | 26 +- .../annotations/CountryMarkerViewOptions.java | 166 +- .../testapp/model/annotations/PulseMarkerView.java | 6 +- .../model/annotations/PulseMarkerViewOptions.java | 110 +- .../testapp/model/annotations/TextMarkerView.java | 16 +- .../model/annotations/TextMarkerViewOptions.java | 130 +- .../testapp/model/constants/AppConstant.java | 2 +- .../model/customlayer/ExampleCustomLayer.java | 16 +- .../model/other/OfflineDownloadRegionDialog.java | 78 +- .../model/other/OfflineListRegionsDialog.java | 59 +- .../mapbox/mapboxsdk/testapp/utils/FontCache.java | 25 +- .../mapboxsdk/testapp/utils/GeoParseUtil.java | 88 +- .../mapboxsdk/testapp/utils/ItemClickSupport.java | 138 +- .../mapboxsdk/testapp/utils/OfflineUtils.java | 41 +- .../mapboxsdk/testapp/utils/TimingLogger.java | 209 +- .../mapboxsdk/testapp/utils/ToolbarComposer.java | 58 +- .../mapboxsdk/annotations/AnnotationTest.java | 122 +- .../com/mapbox/mapboxsdk/annotations/IconTest.java | 80 +- .../mapboxsdk/annotations/InfoWindowTest.java | 130 +- .../mapbox/mapboxsdk/annotations/MarkerTest.java | 282 +- .../mapboxsdk/annotations/MarkerViewTest.java | 517 +-- .../mapbox/mapboxsdk/annotations/PolygonTest.java | 106 +- .../mapbox/mapboxsdk/annotations/PolylineTest.java | 104 +- .../mapboxsdk/camera/CameraPositionTest.java | 211 +- .../mapboxsdk/constants/StyleVersionTest.java | 16 +- .../mapboxsdk/geometry/LatLngBoundsTest.java | 363 +- .../mapbox/mapboxsdk/geometry/LatLngSpanTest.java | 88 +- .../com/mapbox/mapboxsdk/geometry/LatLngTest.java | 356 +- .../mapboxsdk/geometry/ProjectedMetersTest.java | 88 +- .../mapboxsdk/geometry/VisibleRegionTest.java | 161 +- .../mapboxsdk/maps/MapboxMapOptionsTest.java | 336 +- .../mapboxsdk/maps/TrackingSettingsTest.java | 77 +- .../com/mapbox/mapboxsdk/maps/UiSettingsTest.java | 634 ++-- .../maps/widgets/MyLocationViewSettingsTest.java | 159 +- .../mapbox/mapboxsdk/style/layers/FilterTest.java | 170 +- .../mapboxsdk/style/layers/FunctionTest.java | 33 +- .../mapboxsdk/telemetry/HttpTransportTest.java | 15 +- .../com/mapbox/mapboxsdk/utils/MockParcel.java | 399 +- .../MapboxGLAndroidSDKWearTestApp/build.gradle | 1 + .../gradle-checkstyle.gradle | 17 + .../activity/FeatureOverviewActivity.java | 3 +- platform/android/bitrise.yml | 8 + platform/android/checkstyle.xml | 217 ++ 266 files changed, 41374 insertions(+), 40241 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/gradle-checkstyle.gradle delete mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalAPITest.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/camera/CameraInternalApiTest.java create mode 100644 platform/android/MapboxGLAndroidSDKWearTestApp/gradle-checkstyle.gradle create mode 100644 platform/android/checkstyle.xml diff --git a/platform/android/MapboxGLAndroidSDK/build.gradle b/platform/android/MapboxGLAndroidSDK/build.gradle index a03ef7e6e5..c5d92310e9 100644 --- a/platform/android/MapboxGLAndroidSDK/build.gradle +++ b/platform/android/MapboxGLAndroidSDK/build.gradle @@ -80,4 +80,5 @@ configurations { } apply from: 'gradle-javadoc.gradle' -apply from: 'gradle-publish.gradle' \ No newline at end of file +apply from: 'gradle-publish.gradle' +apply from: 'gradle-checkstyle.gradle' \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle b/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle new file mode 100644 index 0000000000..cdcc7f1e23 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDK/gradle-checkstyle.gradle @@ -0,0 +1,17 @@ +apply plugin: 'checkstyle' + +checkstyle { + toolVersion = "7.1.1" // 7.3 + configFile = "../checkstyle.xml" as File +} + +task checkstyle(type: Checkstyle) { + description 'Checks if the code adheres to coding standards' + group 'verification' + configFile file("../checkstyle.xml") + source 'src' + include '**/*.java' + exclude '**/gen/**' + classpath = files() + ignoreFailures = false +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/BaseGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/BaseGestureDetector.java index 622e8f759c..b7bcb925a1 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/BaseGestureDetector.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/BaseGestureDetector.java @@ -6,19 +6,19 @@ import android.view.MotionEvent; /** * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie * (code.almeros.com) - * + *

* All rights reserved. - * + *

* Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * + *

* Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + *

* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -33,129 +33,128 @@ import android.view.MotionEvent; * POSSIBILITY OF SUCH DAMAGE. */ public abstract class BaseGestureDetector { - protected final Context mContext; - protected boolean mGestureInProgress; - - protected MotionEvent mPrevEvent; - protected MotionEvent mCurrEvent; - - protected float mCurrPressure; - protected float mPrevPressure; - protected long mTimeDelta; - - /** - * This value is the threshold ratio between the previous combined pressure - * and the current combined pressure. When pressure decreases rapidly - * between events the position values can often be imprecise, as it usually - * indicates that the user is in the process of lifting a pointer off of the - * device. This value was tuned experimentally. - */ - protected static final float PRESSURE_THRESHOLD = 0.67f; - - public BaseGestureDetector(Context context) { - mContext = context; + protected final Context context; + protected boolean gestureInProgress; + + protected MotionEvent prevEvent; + protected MotionEvent currEvent; + + protected float currPressure; + protected float prevPressure; + protected long timeDelta; + + /** + * This value is the threshold ratio between the previous combined pressure + * and the current combined pressure. When pressure decreases rapidly + * between events the position values can often be imprecise, as it usually + * indicates that the user is in the process of lifting a pointer off of the + * device. This value was tuned experimentally. + */ + protected static final float PRESSURE_THRESHOLD = 0.67f; + + public BaseGestureDetector(Context context) { + this.context = context; + } + + /** + * All gesture detectors need to be called through this method to be able to + * detect gestures. This method delegates work to handler methods + * (handleStartProgressEvent, handleInProgressEvent) implemented in + * extending classes. + * + * @param event MotionEvent + * @return {@code true} as handled + */ + public boolean onTouchEvent(MotionEvent event) { + final int actionCode = event.getAction() & MotionEvent.ACTION_MASK; + if (!gestureInProgress) { + handleStartProgressEvent(actionCode, event); + } else { + handleInProgressEvent(actionCode, event); } - - /** - * All gesture detectors need to be called through this method to be able to - * detect gestures. This method delegates work to handler methods - * (handleStartProgressEvent, handleInProgressEvent) implemented in - * extending classes. - * - * @param event MotionEvent - * @return {@code true} as handled - */ - public boolean onTouchEvent(MotionEvent event) { - final int actionCode = event.getAction() & MotionEvent.ACTION_MASK; - if (!mGestureInProgress) { - handleStartProgressEvent(actionCode, event); - } else { - handleInProgressEvent(actionCode, event); - } - return true; - } - - /** - * Called when the current event occurred when NO gesture is in progress - * yet. The handling in this implementation may set the gesture in progress - * (via mGestureInProgress) or out of progress - * - * @param actionCode Action Code from MotionEvent - * @param event MotionEvent - */ - protected abstract void handleStartProgressEvent(int actionCode, - MotionEvent event); - - /** - * Called when the current event occurred when a gesture IS in progress. The - * handling in this implementation may set the gesture out of progress (via - * mGestureInProgress). - * - * - * @param actionCode Action Code from MotionEvent - * @param event MotionEvent - */ - protected abstract void handleInProgressEvent(int actionCode, - MotionEvent event); - - protected void updateStateByEvent(MotionEvent curr) { - final MotionEvent prev = mPrevEvent; - - // Reset mCurrEvent - if (mCurrEvent != null) { - mCurrEvent.recycle(); - mCurrEvent = null; - } - mCurrEvent = MotionEvent.obtain(curr); - - // Delta time - mTimeDelta = curr.getEventTime() - prev.getEventTime(); - - // Pressure - mCurrPressure = curr.getPressure(curr.getActionIndex()); - mPrevPressure = prev.getPressure(prev.getActionIndex()); + return true; + } + + /** + * Called when the current event occurred when NO gesture is in progress + * yet. The handling in this implementation may set the gesture in progress + * (via gestureInProgress) or out of progress + * + * @param actionCode Action Code from MotionEvent + * @param event MotionEvent + */ + protected abstract void handleStartProgressEvent(int actionCode, + MotionEvent event); + + /** + * Called when the current event occurred when a gesture IS in progress. The + * handling in this implementation may set the gesture out of progress (via + * gestureInProgress). + * + * @param actionCode Action Code from MotionEvent + * @param event MotionEvent + */ + protected abstract void handleInProgressEvent(int actionCode, + MotionEvent event); + + protected void updateStateByEvent(MotionEvent curr) { + final MotionEvent prev = prevEvent; + + // Reset currEvent + if (currEvent != null) { + currEvent.recycle(); + currEvent = null; } + currEvent = MotionEvent.obtain(curr); - protected void resetState() { - if (mPrevEvent != null) { - mPrevEvent.recycle(); - mPrevEvent = null; - } - if (mCurrEvent != null) { - mCurrEvent.recycle(); - mCurrEvent = null; - } - mGestureInProgress = false; - } + // Delta time + timeDelta = curr.getEventTime() - prev.getEventTime(); - /** - * Returns {@code true} if a gesture is currently in progress. - * - * @return {@code true} if a gesture is currently in progress, {@code false} - * otherwise. - */ - public boolean isInProgress() { - return mGestureInProgress; - } + // Pressure + currPressure = curr.getPressure(curr.getActionIndex()); + prevPressure = prev.getPressure(prev.getActionIndex()); + } - /** - * Return the time difference in milliseconds between the previous accepted - * GestureDetector event and the current GestureDetector event. - * - * @return Time difference since the last move event in milliseconds. - */ - public long getTimeDelta() { - return mTimeDelta; + protected void resetState() { + if (prevEvent != null) { + prevEvent.recycle(); + prevEvent = null; } - - /** - * Return the event time of the current GestureDetector event being - * processed. - * - * @return Current GestureDetector event time in milliseconds. - */ - public long getEventTime() { - return mCurrEvent.getEventTime(); + if (currEvent != null) { + currEvent.recycle(); + currEvent = null; } + gestureInProgress = false; + } + + /** + * Returns {@code true} if a gesture is currently in progress. + * + * @return {@code true} if a gesture is currently in progress, {@code false} + * otherwise. + */ + public boolean isInProgress() { + return gestureInProgress; + } + + /** + * Return the time difference in milliseconds between the previous accepted + * GestureDetector event and the current GestureDetector event. + * + * @return Time difference since the last move event in milliseconds. + */ + public long getTimeDelta() { + return timeDelta; + } + + /** + * Return the event time of the current GestureDetector event being + * processed. + * + * @return Current GestureDetector event time in milliseconds. + */ + public long getEventTime() { + return currEvent.getEventTime(); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/MoveGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/MoveGestureDetector.java index 2430f3f920..bc7dda6159 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/MoveGestureDetector.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/MoveGestureDetector.java @@ -7,19 +7,19 @@ import android.view.MotionEvent; /** * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie * (code.almeros.com) - * + *

* All rights reserved. - * + *

* Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * + *

* Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + *

* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -35,151 +35,151 @@ import android.view.MotionEvent; */ public class MoveGestureDetector extends BaseGestureDetector { - /** - * Listener which must be implemented which is used by MoveGestureDetector - * to perform callbacks to any implementing class which is registered to a - * MoveGestureDetector via the constructor. - * - * @see MoveGestureDetector.SimpleOnMoveGestureListener - */ - public interface OnMoveGestureListener { - public boolean onMove(MoveGestureDetector detector); - - public boolean onMoveBegin(MoveGestureDetector detector); - - public void onMoveEnd(MoveGestureDetector detector); + /** + * Listener which must be implemented which is used by MoveGestureDetector + * to perform callbacks to any implementing class which is registered to a + * MoveGestureDetector via the constructor. + * + * @see MoveGestureDetector.SimpleOnMoveGestureListener + */ + public interface OnMoveGestureListener { + public boolean onMove(MoveGestureDetector detector); + + public boolean onMoveBegin(MoveGestureDetector detector); + + public void onMoveEnd(MoveGestureDetector detector); + } + + /** + * Helper class which may be extended and where the methods may be + * implemented. This way it is not necessary to implement all methods of + * OnMoveGestureListener. + */ + public static class SimpleOnMoveGestureListener implements + OnMoveGestureListener { + public boolean onMove(MoveGestureDetector detector) { + return false; } - /** - * Helper class which may be extended and where the methods may be - * implemented. This way it is not necessary to implement all methods of - * OnMoveGestureListener. - */ - public static class SimpleOnMoveGestureListener implements - OnMoveGestureListener { - public boolean onMove(MoveGestureDetector detector) { - return false; - } - - public boolean onMoveBegin(MoveGestureDetector detector) { - return true; - } + public boolean onMoveBegin(MoveGestureDetector detector) { + return true; + } - public void onMoveEnd(MoveGestureDetector detector) { - // Do nothing, overridden implementation may be used - } + public void onMoveEnd(MoveGestureDetector detector) { + // Do nothing, overridden implementation may be used } + } - private static final PointF FOCUS_DELTA_ZERO = new PointF(); + private static final PointF FOCUS_DELTA_ZERO = new PointF(); - private final OnMoveGestureListener mListener; + private final OnMoveGestureListener listener; - private PointF mFocusExternal = new PointF(); - private PointF mFocusDeltaExternal = new PointF(); + private PointF focusExternal = new PointF(); + private PointF focusDeltaExternal = new PointF(); - public MoveGestureDetector(Context context, OnMoveGestureListener listener) { - super(context); - mListener = listener; - } + public MoveGestureDetector(Context context, OnMoveGestureListener listener) { + super(context); + this.listener = listener; + } - @Override - protected void handleStartProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_DOWN: - resetState(); // In case we missed an UP/CANCEL event + @Override + protected void handleStartProgressEvent(int actionCode, MotionEvent event) { + switch (actionCode) { + case MotionEvent.ACTION_DOWN: + resetState(); // In case we missed an UP/CANCEL event - mPrevEvent = MotionEvent.obtain(event); - mTimeDelta = 0; + prevEvent = MotionEvent.obtain(event); + timeDelta = 0; - updateStateByEvent(event); - break; + updateStateByEvent(event); + break; - case MotionEvent.ACTION_MOVE: - mGestureInProgress = mListener.onMoveBegin(this); - break; - } + case MotionEvent.ACTION_MOVE: + gestureInProgress = listener.onMoveBegin(this); + break; } - - @Override - protected void handleInProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - mListener.onMoveEnd(this); - resetState(); - break; - - case MotionEvent.ACTION_MOVE: - updateStateByEvent(event); - - // Only accept the event if our relative pressure is within - // a certain limit. This can help filter shaky data as a - // finger is lifted. - if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) { - final boolean updatePrevious = mListener.onMove(this); - if (updatePrevious) { - mPrevEvent.recycle(); - mPrevEvent = MotionEvent.obtain(event); - } - } - break; + } + + @Override + protected void handleInProgressEvent(int actionCode, MotionEvent event) { + switch (actionCode) { + case MotionEvent.ACTION_UP: + case MotionEvent.ACTION_CANCEL: + listener.onMoveEnd(this); + resetState(); + break; + + case MotionEvent.ACTION_MOVE: + updateStateByEvent(event); + + // Only accept the event if our relative pressure is within + // a certain limit. This can help filter shaky data as a + // finger is lifted. + if (currPressure / prevPressure > PRESSURE_THRESHOLD) { + final boolean updatePrevious = listener.onMove(this); + if (updatePrevious) { + prevEvent.recycle(); + prevEvent = MotionEvent.obtain(event); + } } + break; } - - protected void updateStateByEvent(MotionEvent curr) { - super.updateStateByEvent(curr); - - final MotionEvent prev = mPrevEvent; - - // Focus intenal - PointF mCurrFocusInternal = determineFocalPoint(curr); - PointF mPrevFocusInternal = determineFocalPoint(prev); - - // Focus external - // - Prevent skipping of focus delta when a finger is added or removed - boolean mSkipNextMoveEvent = prev.getPointerCount() != curr - .getPointerCount(); - mFocusDeltaExternal = mSkipNextMoveEvent ? FOCUS_DELTA_ZERO - : new PointF(mCurrFocusInternal.x - mPrevFocusInternal.x, - mCurrFocusInternal.y - mPrevFocusInternal.y); - - // - Don't directly use mFocusInternal (or skipping will occur). Add - // unskipped delta values to mFocusExternal instead. - mFocusExternal.x += mFocusDeltaExternal.x; - mFocusExternal.y += mFocusDeltaExternal.y; + } + + protected void updateStateByEvent(MotionEvent curr) { + super.updateStateByEvent(curr); + + final MotionEvent prev = prevEvent; + + // Focus intenal + PointF currFocusInternal = determineFocalPoint(curr); + PointF prevFocusInternal = determineFocalPoint(prev); + + // Focus external + // - Prevent skipping of focus delta when a finger is added or removed + boolean skipNextMoveEvent = prev.getPointerCount() != curr + .getPointerCount(); + focusDeltaExternal = skipNextMoveEvent ? FOCUS_DELTA_ZERO + : new PointF(currFocusInternal.x - prevFocusInternal.x, + currFocusInternal.y - prevFocusInternal.y); + + // - Don't directly use mFocusInternal (or skipping will occur). Add + // unskipped delta values to focusExternal instead. + focusExternal.x += focusDeltaExternal.x; + focusExternal.y += focusDeltaExternal.y; + } + + /** + * Determine (multi)finger focal point (a.k.a. center point between all + * fingers) + * + * @param motionEvent a {@link MotionEvent} object. + * @return PointF focal point + */ + private PointF determineFocalPoint(MotionEvent motionEvent) { + // Number of fingers on screen + final int pCount = motionEvent.getPointerCount(); + float x = 0.0f; + float y = 0.0f; + + for (int i = 0; i < pCount; i++) { + x += motionEvent.getX(i); + y += motionEvent.getY(i); } - /** - * Determine (multi)finger focal point (a.k.a. center point between all - * fingers) - * - * @param e - * @return PointF focal point - */ - private PointF determineFocalPoint(MotionEvent e) { - // Number of fingers on screen - final int pCount = e.getPointerCount(); - float x = 0.0f; - float y = 0.0f; - - for (int i = 0; i < pCount; i++) { - x += e.getX(i); - y += e.getY(i); - } - - return new PointF(x / pCount, y / pCount); - } + return new PointF(x / pCount, y / pCount); + } - public float getFocusX() { - return mFocusExternal.x; - } + public float getFocusX() { + return focusExternal.x; + } - public float getFocusY() { - return mFocusExternal.y; - } + public float getFocusY() { + return focusExternal.y; + } - public PointF getFocusDelta() { - return mFocusDeltaExternal; - } + public PointF getFocusDelta() { + return focusDeltaExternal; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/RotateGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/RotateGestureDetector.java index 124fe8509c..8c111a68df 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/RotateGestureDetector.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/RotateGestureDetector.java @@ -6,19 +6,19 @@ import android.view.MotionEvent; /** * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie * (code.almeros.com) - * + *

* All rights reserved. - * + *

* Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * + *

* Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + *

* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -34,147 +34,147 @@ import android.view.MotionEvent; */ public class RotateGestureDetector extends TwoFingerGestureDetector { - /** - * Listener which must be implemented which is used by RotateGestureDetector - * to perform callbacks to any implementing class which is registered to a - * RotateGestureDetector via the constructor. - * - * @see RotateGestureDetector.SimpleOnRotateGestureListener - */ - public interface OnRotateGestureListener { - public boolean onRotate(RotateGestureDetector detector); - - public boolean onRotateBegin(RotateGestureDetector detector); + /** + * Listener which must be implemented which is used by RotateGestureDetector + * to perform callbacks to any implementing class which is registered to a + * RotateGestureDetector via the constructor. + * + * @see RotateGestureDetector.SimpleOnRotateGestureListener + */ + public interface OnRotateGestureListener { + public boolean onRotate(RotateGestureDetector detector); + + public boolean onRotateBegin(RotateGestureDetector detector); + + public void onRotateEnd(RotateGestureDetector detector); + } + + /** + * Helper class which may be extended and where the methods may be + * implemented. This way it is not necessary to implement all methods of + * OnRotateGestureListener. + */ + public static class SimpleOnRotateGestureListener implements + OnRotateGestureListener { + public boolean onRotate(RotateGestureDetector detector) { + return false; + } - public void onRotateEnd(RotateGestureDetector detector); + public boolean onRotateBegin(RotateGestureDetector detector) { + return true; } - /** - * Helper class which may be extended and where the methods may be - * implemented. This way it is not necessary to implement all methods of - * OnRotateGestureListener. - */ - public static class SimpleOnRotateGestureListener implements - OnRotateGestureListener { - public boolean onRotate(RotateGestureDetector detector) { - return false; + public void onRotateEnd(RotateGestureDetector detector) { + // Do nothing, overridden implementation may be used + } + } + + private final OnRotateGestureListener listener; + private boolean sloppyGesture; + + public RotateGestureDetector(Context context, + OnRotateGestureListener listener) { + super(context); + this.listener = listener; + } + + @Override + protected void handleStartProgressEvent(int actionCode, MotionEvent event) { + switch (actionCode) { + case MotionEvent.ACTION_POINTER_DOWN: + // At least the second finger is on screen now + + resetState(); // In case we missed an UP/CANCEL event + prevEvent = MotionEvent.obtain(event); + timeDelta = 0; + + updateStateByEvent(event); + + // See if we have a sloppy gesture + sloppyGesture = isSloppyGesture(event); + if (!sloppyGesture) { + // No, start gesture now + gestureInProgress = listener.onRotateBegin(this); } + break; - public boolean onRotateBegin(RotateGestureDetector detector) { - return true; + case MotionEvent.ACTION_MOVE: + if (!sloppyGesture) { + break; } - public void onRotateEnd(RotateGestureDetector detector) { - // Do nothing, overridden implementation may be used + // See if we still have a sloppy gesture + sloppyGesture = isSloppyGesture(event); + if (!sloppyGesture) { + // No, start normal gesture now + gestureInProgress = listener.onRotateBegin(this); } - } - private final OnRotateGestureListener mListener; - private boolean mSloppyGesture; + break; - public RotateGestureDetector(Context context, - OnRotateGestureListener listener) { - super(context); - mListener = listener; - } - - @Override - protected void handleStartProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_POINTER_DOWN: - // At least the second finger is on screen now - - resetState(); // In case we missed an UP/CANCEL event - mPrevEvent = MotionEvent.obtain(event); - mTimeDelta = 0; - - updateStateByEvent(event); - - // See if we have a sloppy gesture - mSloppyGesture = isSloppyGesture(event); - if (!mSloppyGesture) { - // No, start gesture now - mGestureInProgress = mListener.onRotateBegin(this); - } - break; - - case MotionEvent.ACTION_MOVE: - if (!mSloppyGesture) { - break; - } - - // See if we still have a sloppy gesture - mSloppyGesture = isSloppyGesture(event); - if (!mSloppyGesture) { - // No, start normal gesture now - mGestureInProgress = mListener.onRotateBegin(this); - } - - break; - - case MotionEvent.ACTION_POINTER_UP: - if (!mSloppyGesture) { - break; - } - - break; + case MotionEvent.ACTION_POINTER_UP: + if (!sloppyGesture) { + break; } + + break; } + } - @Override - protected void handleInProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_POINTER_UP: - // Gesture ended but - updateStateByEvent(event); - - if (!mSloppyGesture) { - mListener.onRotateEnd(this); - } - - resetState(); - break; - - case MotionEvent.ACTION_CANCEL: - if (!mSloppyGesture) { - mListener.onRotateEnd(this); - } - - resetState(); - break; - - case MotionEvent.ACTION_MOVE: - updateStateByEvent(event); - - // Only accept the event if our relative pressure is within - // a certain limit. This can help filter shaky data as a - // finger is lifted. - if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) { - final boolean updatePrevious = mListener.onRotate(this); - if (updatePrevious) { - mPrevEvent.recycle(); - mPrevEvent = MotionEvent.obtain(event); - } - } - break; + @Override + protected void handleInProgressEvent(int actionCode, MotionEvent event) { + switch (actionCode) { + case MotionEvent.ACTION_POINTER_UP: + // Gesture ended but + updateStateByEvent(event); + + if (!sloppyGesture) { + listener.onRotateEnd(this); } - } - @Override - protected void resetState() { - super.resetState(); - mSloppyGesture = false; - } + resetState(); + break; - /** - * Return the rotation difference from the previous rotate event to the - * current event. - * - * @return The current rotation //difference in degrees. - */ - public float getRotationDegreesDelta() { - double diffRadians = Math.atan2(mPrevFingerDiffY, mPrevFingerDiffX) - - Math.atan2(mCurrFingerDiffY, mCurrFingerDiffX); - return (float) (diffRadians * 180.0 / Math.PI); + case MotionEvent.ACTION_CANCEL: + if (!sloppyGesture) { + listener.onRotateEnd(this); + } + + resetState(); + break; + + case MotionEvent.ACTION_MOVE: + updateStateByEvent(event); + + // Only accept the event if our relative pressure is within + // a certain limit. This can help filter shaky data as a + // finger is lifted. + if (currPressure / prevPressure > PRESSURE_THRESHOLD) { + final boolean updatePrevious = listener.onRotate(this); + if (updatePrevious) { + prevEvent.recycle(); + prevEvent = MotionEvent.obtain(event); + } + } + break; } + } + + @Override + protected void resetState() { + super.resetState(); + sloppyGesture = false; + } + + /** + * Return the rotation difference from the previous rotate event to the + * current event. + * + * @return The current rotation //difference in degrees. + */ + public float getRotationDegreesDelta() { + double diffRadians = Math.atan2(prevFingerDiffY, prevFingerDiffX) + - Math.atan2(currFingerDiffY, currFingerDiffX); + return (float) (diffRadians * 180.0 / Math.PI); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/ShoveGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/ShoveGestureDetector.java index 254597105b..9396578e48 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/ShoveGestureDetector.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/ShoveGestureDetector.java @@ -5,21 +5,21 @@ import android.view.MotionEvent; /** * @author Robert Nordan (robert.nordan@norkart.no) - * + *

* Copyright (c) 2013, Norkart AS - * + *

* All rights reserved. - * + *

* Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * + *

* Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + *

* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -35,179 +35,180 @@ import android.view.MotionEvent; */ public class ShoveGestureDetector extends TwoFingerGestureDetector { - /** - * Listener which must be implemented which is used by ShoveGestureDetector - * to perform callbacks to any implementing class which is registered to a - * ShoveGestureDetector via the constructor. - * - * @see ShoveGestureDetector.SimpleOnShoveGestureListener - */ - public interface OnShoveGestureListener { - public boolean onShove(ShoveGestureDetector detector); + /** + * Listener which must be implemented which is used by ShoveGestureDetector + * to perform callbacks to any implementing class which is registered to a + * ShoveGestureDetector via the constructor. + * + * @see ShoveGestureDetector.SimpleOnShoveGestureListener + */ + public interface OnShoveGestureListener { + public boolean onShove(ShoveGestureDetector detector); + + public boolean onShoveBegin(ShoveGestureDetector detector); + + public void onShoveEnd(ShoveGestureDetector detector); + } + + /** + * Helper class which may be extended and where the methods may be + * implemented. This way it is not necessary to implement all methods of + * OnShoveGestureListener. + */ + public static class SimpleOnShoveGestureListener implements + OnShoveGestureListener { + public boolean onShove(ShoveGestureDetector detector) { + return false; + } - public boolean onShoveBegin(ShoveGestureDetector detector); + public boolean onShoveBegin(ShoveGestureDetector detector) { + return true; + } - public void onShoveEnd(ShoveGestureDetector detector); + public void onShoveEnd(ShoveGestureDetector detector) { + // Do nothing, overridden implementation may be used } + } + + private float prevAverageY; + private float currAverageY; + + private final OnShoveGestureListener listener; + private boolean sloppyGesture; + + public ShoveGestureDetector(Context context, OnShoveGestureListener listener) { + super(context); + this.listener = listener; + } - /** - * Helper class which may be extended and where the methods may be - * implemented. This way it is not necessary to implement all methods of - * OnShoveGestureListener. - */ - public static class SimpleOnShoveGestureListener implements - OnShoveGestureListener { - public boolean onShove(ShoveGestureDetector detector) { - return false; + @Override + protected void handleStartProgressEvent(int actionCode, MotionEvent event) { + switch (actionCode) { + case MotionEvent.ACTION_POINTER_DOWN: + // At least the second finger is on screen now + + resetState(); // In case we missed an UP/CANCEL event + prevEvent = MotionEvent.obtain(event); + timeDelta = 0; + + updateStateByEvent(event); + + // See if we have a sloppy gesture + sloppyGesture = isSloppyGesture(event); + if (!sloppyGesture) { + // No, start gesture now + gestureInProgress = listener.onShoveBegin(this); } + break; - public boolean onShoveBegin(ShoveGestureDetector detector) { - return true; + case MotionEvent.ACTION_MOVE: + if (!sloppyGesture) { + break; } - public void onShoveEnd(ShoveGestureDetector detector) { - // Do nothing, overridden implementation may be used + // See if we still have a sloppy gesture + sloppyGesture = isSloppyGesture(event); + if (!sloppyGesture) { + // No, start normal gesture now + gestureInProgress = listener.onShoveBegin(this); } - } - private float mPrevAverageY; - private float mCurrAverageY; + break; - private final OnShoveGestureListener mListener; - private boolean mSloppyGesture; + case MotionEvent.ACTION_POINTER_UP: + if (!sloppyGesture) { + break; + } - public ShoveGestureDetector(Context context, OnShoveGestureListener listener) { - super(context); - mListener = listener; + break; } + } - @Override - protected void handleStartProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_POINTER_DOWN: - // At least the second finger is on screen now - - resetState(); // In case we missed an UP/CANCEL event - mPrevEvent = MotionEvent.obtain(event); - mTimeDelta = 0; - - updateStateByEvent(event); - - // See if we have a sloppy gesture - mSloppyGesture = isSloppyGesture(event); - if (!mSloppyGesture) { - // No, start gesture now - mGestureInProgress = mListener.onShoveBegin(this); - } - break; - - case MotionEvent.ACTION_MOVE: - if (!mSloppyGesture) { - break; - } - - // See if we still have a sloppy gesture - mSloppyGesture = isSloppyGesture(event); - if (!mSloppyGesture) { - // No, start normal gesture now - mGestureInProgress = mListener.onShoveBegin(this); - } - - break; - - case MotionEvent.ACTION_POINTER_UP: - if (!mSloppyGesture) { - break; - } - - break; - } - } + @Override + protected void handleInProgressEvent(int actionCode, MotionEvent event) { + switch (actionCode) { + case MotionEvent.ACTION_POINTER_UP: + // Gesture ended but + updateStateByEvent(event); - @Override - protected void handleInProgressEvent(int actionCode, MotionEvent event) { - switch (actionCode) { - case MotionEvent.ACTION_POINTER_UP: - // Gesture ended but - updateStateByEvent(event); - - if (!mSloppyGesture) { - mListener.onShoveEnd(this); - } - - resetState(); - break; - - case MotionEvent.ACTION_CANCEL: - if (!mSloppyGesture) { - mListener.onShoveEnd(this); - } - - resetState(); - break; - - case MotionEvent.ACTION_MOVE: - updateStateByEvent(event); - - // Only accept the event if our relative pressure is within - // a certain limit. This can help filter shaky data as a - // finger is lifted. Also check that shove is meaningful. - if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD - && Math.abs(getShovePixelsDelta()) > 0.5f) { - final boolean updatePrevious = mListener.onShove(this); - if (updatePrevious) { - mPrevEvent.recycle(); - mPrevEvent = MotionEvent.obtain(event); - } - } - break; + if (!sloppyGesture) { + listener.onShoveEnd(this); } - } - - @Override - protected void resetState() { - super.resetState(); - mSloppyGesture = false; - mPrevAverageY = 0.0f; - mCurrAverageY = 0.0f; - } - @Override - protected void updateStateByEvent(MotionEvent curr) { - super.updateStateByEvent(curr); + resetState(); + break; - final MotionEvent prev = mPrevEvent; - float py0 = prev.getY(0); - float py1 = prev.getY(1); - mPrevAverageY = (py0 + py1) / 2.0f; + case MotionEvent.ACTION_CANCEL: + if (!sloppyGesture) { + listener.onShoveEnd(this); + } - float cy0 = curr.getY(0); - float cy1 = curr.getY(1); - mCurrAverageY = (cy0 + cy1) / 2.0f; + resetState(); + break; + + case MotionEvent.ACTION_MOVE: + updateStateByEvent(event); + + // Only accept the event if our relative pressure is within + // a certain limit. This can help filter shaky data as a + // finger is lifted. Also check that shove is meaningful. + if (currPressure / prevPressure > PRESSURE_THRESHOLD + && Math.abs(getShovePixelsDelta()) > 0.5f) { + final boolean updatePrevious = listener.onShove(this); + if (updatePrevious) { + prevEvent.recycle(); + prevEvent = MotionEvent.obtain(event); + } + } + break; } - - @Override - protected boolean isSloppyGesture(MotionEvent event) { - boolean sloppy = super.isSloppyGesture(event); - if (sloppy) - return true; - - // If it's not traditionally sloppy, we check if the angle between - // fingers - // is acceptable. - double angle = Math.abs(Math.atan2(mCurrFingerDiffY, mCurrFingerDiffX)); - // about 20 degrees, left or right - return !((0.0f < angle && angle < 0.35f) || 2.79f < angle - && angle < Math.PI); + } + + @Override + protected void resetState() { + super.resetState(); + sloppyGesture = false; + prevAverageY = 0.0f; + currAverageY = 0.0f; + } + + @Override + protected void updateStateByEvent(MotionEvent curr) { + super.updateStateByEvent(curr); + + final MotionEvent prev = prevEvent; + float py0 = prev.getY(0); + float py1 = prev.getY(1); + prevAverageY = (py0 + py1) / 2.0f; + + float cy0 = curr.getY(0); + float cy1 = curr.getY(1); + currAverageY = (cy0 + cy1) / 2.0f; + } + + @Override + protected boolean isSloppyGesture(MotionEvent event) { + boolean sloppy = super.isSloppyGesture(event); + if (sloppy) { + return true; } - /** - * Return the distance in pixels from the previous shove event to the - * current event. - * - * @return The current distance in pixels. - */ - public float getShovePixelsDelta() { - return mCurrAverageY - mPrevAverageY; - } + // If it's not traditionally sloppy, we check if the angle between + // fingers + // is acceptable. + double angle = Math.abs(Math.atan2(currFingerDiffY, currFingerDiffX)); + // about 20 degrees, left or right + return !((0.0f < angle && angle < 0.35f) || 2.79f < angle + && angle < Math.PI); + } + + /** + * Return the distance in pixels from the previous shove event to the + * current event. + * + * @return The current distance in pixels. + */ + public float getShovePixelsDelta() { + return currAverageY - prevAverageY; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java index 694bea9f30..71fb9aa168 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/almeros/android/multitouch/gesturedetectors/TwoFingerGestureDetector.java @@ -9,19 +9,19 @@ import android.view.ViewConfiguration; /** * @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie * (code.almeros.com) - * + *

* All rights reserved. - * + *

* Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: - * + *

* Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * + *

* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR @@ -37,189 +37,189 @@ import android.view.ViewConfiguration; */ public abstract class TwoFingerGestureDetector extends BaseGestureDetector { - private final float mEdgeSlop; - - protected float mPrevFingerDiffX; - protected float mPrevFingerDiffY; - protected float mCurrFingerDiffX; - protected float mCurrFingerDiffY; - - private float mCurrLen; - private float mPrevLen; - - private PointF mFocus; - - public TwoFingerGestureDetector(Context context) { - super(context); - - ViewConfiguration config = ViewConfiguration.get(context); - - // We divide edge slop by 2 to make rotation gesture happen more easily #6870 - mEdgeSlop = config.getScaledEdgeSlop() / 2; - } - - @Override - protected abstract void handleStartProgressEvent(int actionCode, - MotionEvent event); - - @Override - protected abstract void handleInProgressEvent(int actionCode, - MotionEvent event); - - protected void updateStateByEvent(MotionEvent curr) { - super.updateStateByEvent(curr); - - final MotionEvent prev = mPrevEvent; - - mCurrLen = -1; - mPrevLen = -1; - - // Previous - final float px0 = prev.getX(0); - final float py0 = prev.getY(0); - final float px1 = prev.getX(1); - final float py1 = prev.getY(1); - final float pvx = px1 - px0; - final float pvy = py1 - py0; - mPrevFingerDiffX = pvx; - mPrevFingerDiffY = pvy; - - // Current - final float cx0 = curr.getX(0); - final float cy0 = curr.getY(0); - final float cx1 = curr.getX(1); - final float cy1 = curr.getY(1); - final float cvx = cx1 - cx0; - final float cvy = cy1 - cy0; - mCurrFingerDiffX = cvx; - mCurrFingerDiffY = cvy; - mFocus = determineFocalPoint(curr); + private final float edgeSlop; + + protected float prevFingerDiffX; + protected float prevFingerDiffY; + protected float currFingerDiffX; + protected float currFingerDiffY; + + private float currLen; + private float prevLen; + + private PointF focus; + + public TwoFingerGestureDetector(Context context) { + super(context); + + ViewConfiguration config = ViewConfiguration.get(context); + + // We divide edge slop by 2 to make rotation gesture happen more easily #6870 + edgeSlop = config.getScaledEdgeSlop() / 2; + } + + @Override + protected abstract void handleStartProgressEvent(int actionCode, + MotionEvent event); + + @Override + protected abstract void handleInProgressEvent(int actionCode, + MotionEvent event); + + protected void updateStateByEvent(MotionEvent curr) { + super.updateStateByEvent(curr); + + final MotionEvent prev = prevEvent; + + currLen = -1; + prevLen = -1; + + // Previous + final float px0 = prev.getX(0); + final float py0 = prev.getY(0); + final float px1 = prev.getX(1); + final float py1 = prev.getY(1); + final float pvx = px1 - px0; + final float pvy = py1 - py0; + prevFingerDiffX = pvx; + prevFingerDiffY = pvy; + + // Current + final float cx0 = curr.getX(0); + final float cy0 = curr.getY(0); + final float cx1 = curr.getX(1); + final float cy1 = curr.getY(1); + final float cvx = cx1 - cx0; + final float cvy = cy1 - cy0; + currFingerDiffX = cvx; + currFingerDiffY = cvy; + focus = determineFocalPoint(curr); + } + + /** + * Return the current distance between the two pointers forming the gesture + * in progress. + * + * @return Distance between pointers in pixels. + */ + public float getCurrentSpan() { + if (currLen == -1) { + final float cvx = currFingerDiffX; + final float cvy = currFingerDiffY; + currLen = (float) Math.sqrt(cvx * cvx + cvy * cvy); } - - /** - * Return the current distance between the two pointers forming the gesture - * in progress. - * - * @return Distance between pointers in pixels. - */ - public float getCurrentSpan() { - if (mCurrLen == -1) { - final float cvx = mCurrFingerDiffX; - final float cvy = mCurrFingerDiffY; - mCurrLen = (float) Math.sqrt(cvx * cvx + cvy * cvy); - } - return mCurrLen; + return currLen; + } + + /** + * Return the previous distance between the two pointers forming the gesture + * in progress. + * + * @return Previous distance between pointers in pixels. + */ + public float getPreviousSpan() { + if (prevLen == -1) { + final float pvx = prevFingerDiffX; + final float pvy = prevFingerDiffY; + prevLen = (float) Math.sqrt(pvx * pvx + pvy * pvy); } - - /** - * Return the previous distance between the two pointers forming the gesture - * in progress. - * - * @return Previous distance between pointers in pixels. - */ - public float getPreviousSpan() { - if (mPrevLen == -1) { - final float pvx = mPrevFingerDiffX; - final float pvy = mPrevFingerDiffY; - mPrevLen = (float) Math.sqrt(pvx * pvx + pvy * pvy); - } - return mPrevLen; + return prevLen; + } + + /** + * MotionEvent has no getRawX(int) method; simulate it pending future API + * approval. + * + * @param event Motion Event + * @param pointerIndex Pointer Index + * @return Raw x value or 0 + */ + protected static float getRawX(MotionEvent event, int pointerIndex) { + float offset = event.getRawX() - event.getX(); + if (pointerIndex < event.getPointerCount()) { + return event.getX(pointerIndex) + offset; } - - /** - * MotionEvent has no getRawX(int) method; simulate it pending future API - * approval. - * - * @param event Motion Event - * @param pointerIndex Pointer Index - * @return Raw x value or 0 - */ - protected static float getRawX(MotionEvent event, int pointerIndex) { - float offset = event.getRawX() - event.getX(); - if (pointerIndex < event.getPointerCount()) { - return event.getX(pointerIndex) + offset; - } - return 0.0f; + return 0.0f; + } + + /** + * MotionEvent has no getRawY(int) method; simulate it pending future API + * approval. + * + * @param event Motion Event + * @param pointerIndex Pointer Index + * @return Raw y value or 0 + */ + protected static float getRawY(MotionEvent event, int pointerIndex) { + float offset = event.getRawY() - event.getY(); + if (pointerIndex < event.getPointerCount()) { + return event.getY(pointerIndex) + offset; } - - /** - * MotionEvent has no getRawY(int) method; simulate it pending future API - * approval. - * - * @param event Motion Event - * @param pointerIndex Pointer Index - * @return Raw y value or 0 - */ - protected static float getRawY(MotionEvent event, int pointerIndex) { - float offset = event.getRawY() - event.getY(); - if (pointerIndex < event.getPointerCount()) { - return event.getY(pointerIndex) + offset; - } - return 0.0f; + return 0.0f; + } + + /** + * Check if we have a sloppy gesture. Sloppy gestures can happen if the edge + * of the user's hand is touching the screen, for example. + * + * @param event Motion Event + * @return {@code true} if is sloppy gesture, {@code false} if not + */ + protected boolean isSloppyGesture(MotionEvent event) { + // As orientation can change, query the metrics in touch down + DisplayMetrics metrics = context.getResources().getDisplayMetrics(); + float rightSlopEdge = metrics.widthPixels - edgeSlop; + float bottomSlopEdge = metrics.heightPixels - edgeSlop; + + final float edgeSlop = this.edgeSlop; + + final float x0 = event.getRawX(); + final float y0 = event.getRawY(); + final float x1 = getRawX(event, 1); + final float y1 = getRawY(event, 1); + + boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop || x0 > rightSlopEdge + || y0 > bottomSlopEdge; + boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > rightSlopEdge + || y1 > bottomSlopEdge; + + if (p0sloppy && p1sloppy) { + return true; + } else if (p0sloppy) { + return true; + } else if (p1sloppy) { + return true; } - - /** - * Check if we have a sloppy gesture. Sloppy gestures can happen if the edge - * of the user's hand is touching the screen, for example. - * - * @param event Motion Event - * @return {@code true} if is sloppy gesture, {@code false} if not - */ - protected boolean isSloppyGesture(MotionEvent event) { - // As orientation can change, query the metrics in touch down - DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); - float mRightSlopEdge = metrics.widthPixels - mEdgeSlop; - float mBottomSlopEdge = metrics.heightPixels - mEdgeSlop; - - final float edgeSlop = mEdgeSlop; - - final float x0 = event.getRawX(); - final float y0 = event.getRawY(); - final float x1 = getRawX(event, 1); - final float y1 = getRawY(event, 1); - - boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop || x0 > mRightSlopEdge - || y0 > mBottomSlopEdge; - boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > mRightSlopEdge - || y1 > mBottomSlopEdge; - - if (p0sloppy && p1sloppy) { - return true; - } else if (p0sloppy) { - return true; - } else if (p1sloppy) { - return true; - } - return false; + return false; + } + + /** + * Determine (multi)finger focal point (a.k.a. center point between all + * fingers) + * + * @param motionEvent Motion Event + * @return PointF focal point + */ + public static PointF determineFocalPoint(MotionEvent motionEvent) { + // Number of fingers on screen + final int pCount = motionEvent.getPointerCount(); + float x = 0.0f; + float y = 0.0f; + + for (int i = 0; i < pCount; i++) { + x += motionEvent.getX(i); + y += motionEvent.getY(i); } - /** - * Determine (multi)finger focal point (a.k.a. center point between all - * fingers) - * - * @param e Motion Event - * @return PointF focal point - */ - public static PointF determineFocalPoint(MotionEvent e) { - // Number of fingers on screen - final int pCount = e.getPointerCount(); - float x = 0.0f; - float y = 0.0f; - - for (int i = 0; i < pCount; i++) { - x += e.getX(i); - y += e.getY(i); - } - - return new PointF(x / pCount, y / pCount); - } + return new PointF(x / pCount, y / pCount); + } - public float getFocusX() { - return mFocus.x; - } + public float getFocusX() { + return focus.x; + } - public float getFocusY() { - return mFocus.y; - } + public float getFocusY() { + return focus.y; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapboxAccountManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapboxAccountManager.java index b33d01a105..5f26228c5d 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapboxAccountManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/MapboxAccountManager.java @@ -13,119 +13,121 @@ import com.mapbox.mapboxsdk.telemetry.MapboxEventManager; public class MapboxAccountManager { - private static MapboxAccountManager mapboxAccountManager = null; - - private final String accessToken; - private final Context applicationContext; - - private Boolean connected = null; - - /** - * MapboxAccountManager should NOT be instantiated directly. - * Use @see MapboxAccountManager#getInstance() instead. - * - * @param applicationContext Context used to get ApplicationContext - * @param accessToken Mapbox Access Token - */ - private MapboxAccountManager(Context applicationContext, String accessToken) { - super(); - this.applicationContext = applicationContext.getApplicationContext(); - this.accessToken = accessToken; + private static MapboxAccountManager mapboxAccountManager = null; + + private final String accessToken; + private final Context applicationContext; + + private Boolean connected = null; + + /** + * MapboxAccountManager should NOT be instantiated directly. + * Use @see MapboxAccountManager#getInstance() instead. + * + * @param applicationContext Context used to get ApplicationContext + * @param accessToken Mapbox Access Token + */ + private MapboxAccountManager(Context applicationContext, String accessToken) { + super(); + this.applicationContext = applicationContext.getApplicationContext(); + this.accessToken = accessToken; + } + + /** + * Primary entry point to Mapbox for implementing developers. + * Must be configured in either Application.onCreate() or Launch Activity.onCreate() + * + * @param context Context used to get Application Context + * @param accessToken Mapbox Access Token. You can get one on the Mapbox Web site. + * @return MapboxAccountManager instance for app + */ + public static MapboxAccountManager start(Context context, String accessToken) { + if (mapboxAccountManager == null) { + //Create a new account manager + mapboxAccountManager = new MapboxAccountManager(context, accessToken); + + //Initialize the event manager + MapboxEventManager.getMapboxEventManager().initialize(context, accessToken); + + //Register a receiver to listen for connectivity updates + ConnectivityReceiver.instance(context); } - /** - * Primary entry point to Mapbox for implementing developers. - * Must be configured in either Application.onCreate() or Launch Activity.onCreate() - * - * @param context Context used to get Application Context - * @param accessToken Mapbox Access Token. You can get one on the Mapbox Web site. - * @return MapboxAccountManager instance for app - */ - public static MapboxAccountManager start(Context context, String accessToken) { - if (mapboxAccountManager == null) { - //Create a new account manager - mapboxAccountManager = new MapboxAccountManager(context, accessToken); - - //Initialize the event manager - MapboxEventManager.getMapboxEventManager().initialize(context, accessToken); - - //Register a receiver to listen for connectivity updates - ConnectivityReceiver.instance(context); - } - - return mapboxAccountManager; + return mapboxAccountManager; + } + + /** + * Internal Use Only + * Get an instance of MapboxAccountManager configured with the app's Access Token + * + * @return MapboxAccountManager instance for app. May be NULL if not configured yet. + */ + public static MapboxAccountManager getInstance() { + if (mapboxAccountManager == null) { + throw new MapboxAccountManagerNotStartedException(); } - /** - * Internal Use Only - * Get an instance of MapboxAccountManager configured with the app's Access Token - * - * @return MapboxAccountManager instance for app. May be NULL if not configured yet. - */ - public static MapboxAccountManager getInstance() { - if (mapboxAccountManager == null) { - throw new MapboxAccountManagerNotStartedException(); - } - - return mapboxAccountManager; + return mapboxAccountManager; + } + + /** + * Access Token for this application. + * + * @return Mapbox Access Token + */ + public String getAccessToken() { + return accessToken; + } + + /** + * Runtime validation of Access Token. + * + * @param accessToken Access Token to check + * @throws InvalidAccessTokenException the exception thrown + */ + public static void validateAccessToken(String accessToken) throws InvalidAccessTokenException { + if (TextUtils.isEmpty(accessToken) || (!accessToken.toLowerCase(MapboxConstants.MAPBOX_LOCALE).startsWith("pk.") + && !accessToken.toLowerCase(MapboxConstants.MAPBOX_LOCALE).startsWith("sk."))) { + throw new InvalidAccessTokenException(); } - - /** - * Access Token for this application. - * - * @return Mapbox Access Token - */ - public String getAccessToken() { - return accessToken; - } - - /** - * Runtime validation of Access Token. - * - * @param accessToken Access Token to check - * @throws InvalidAccessTokenException the exception thrown - */ - public static void validateAccessToken(String accessToken) throws InvalidAccessTokenException { - if (TextUtils.isEmpty(accessToken) || (!accessToken.toLowerCase(MapboxConstants.MAPBOX_LOCALE).startsWith("pk.") && !accessToken.toLowerCase(MapboxConstants.MAPBOX_LOCALE).startsWith("sk."))) { - throw new InvalidAccessTokenException(); - } - } - - /** - * Manually sets the connectivity state of the app. This is useful for apps that control their - * own connectivity state and want to bypass any checks to the ConnectivityManager. - * - * @param connected flag to determine the connectivity state, true for connected, false for - * disconnected, null for ConnectivityManager to determine. - */ - public void setConnected(Boolean connected) { - // Connectivity state overridden by app - this.connected = connected; - } - - /** - * Determines whether we have an Internet connection available. Please do not rely on this - * method in your apps, this method is used internally by the SDK. - * - * @return true if there is an Internet connection, false otherwise - */ - public Boolean isConnected() { - if (connected != null) { - // Connectivity state overridden by app - return connected; - } - - ConnectivityManager cm = (ConnectivityManager) applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); - return (activeNetwork != null && activeNetwork.isConnected()); + } + + /** + * Manually sets the connectivity state of the app. This is useful for apps that control their + * own connectivity state and want to bypass any checks to the ConnectivityManager. + * + * @param connected flag to determine the connectivity state, true for connected, false for + * disconnected, null for ConnectivityManager to determine. + */ + public void setConnected(Boolean connected) { + // Connectivity state overridden by app + this.connected = connected; + } + + /** + * Determines whether we have an Internet connection available. Please do not rely on this + * method in your apps, this method is used internally by the SDK. + * + * @return true if there is an Internet connection, false otherwise + */ + public Boolean isConnected() { + if (connected != null) { + // Connectivity state overridden by app + return connected; } - /** - * Not public API - * @return the Application Context - */ - public Context getApplicationContext() { - return applicationContext; - } + ConnectivityManager cm = (ConnectivityManager) applicationContext.getSystemService(Context.CONNECTIVITY_SERVICE); + NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); + return (activeNetwork != null && activeNetwork.isConnected()); + } + + /** + * Not public API + * + * @return the Application Context + */ + public Context getApplicationContext() { + return applicationContext; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java index 40b330b8c2..831c1db5a3 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Annotation.java @@ -15,123 +15,127 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; */ public abstract class Annotation implements Comparable { - /** - *

- * The annotation id - *

- * Internal C++ id is stored as unsigned int. - */ - private long id = -1; // -1 unless added to a MapView - protected MapboxMap mapboxMap; - protected MapView mapView; + /** + *

+ * The annotation id + *

+ * Internal C++ id is stored as unsigned int. + */ + private long id = -1; // -1 unless added to a MapView + protected MapboxMap mapboxMap; + protected MapView mapView; - protected Annotation() { - } + protected Annotation() { + } - /** - *

- * Gets the annotation's unique ID. - *

- * This ID is unique for a MapView instance and is suitable for associating your own extra - * data with. - * - * @return the assigned id. - */ - public long getId() { - return id; - } + /** + *

+ * Gets the annotation's unique ID. + *

+ * This ID is unique for a MapView instance and is suitable for associating your own extra + * data with. + * + * @return the assigned id. + */ + public long getId() { + return id; + } - /** - * Do not use this method, used internally by the SDK. - */ - public void remove() { - if (mapboxMap == null) { - return; - } - mapboxMap.removeAnnotation(this); + /** + * Do not use this method, used internally by the SDK. + */ + public void remove() { + if (mapboxMap == null) { + return; } + mapboxMap.removeAnnotation(this); + } - /** - * Do not use this method, used internally by the SDK. - * - * @param id the assigned id - */ - public void setId(long id) { - this.id = id; - } + /** + * Do not use this method, used internally by the SDK. + * + * @param id the assigned id + */ + public void setId(long id) { + this.id = id; + } - /** - * Do not use this method, used internally by the SDK. - * - * @param mapboxMap the hosting mapbox map - */ - public void setMapboxMap(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; - } + /** + * Do not use this method, used internally by the SDK. + * + * @param mapboxMap the hosting mapbox map + */ + public void setMapboxMap(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + } - /** - * Gets the hosting mapbox map. - * - * @return the MapboxMap - */ - protected MapboxMap getMapboxMap() { - return mapboxMap; - } + /** + * Gets the hosting mapbox map. + * + * @return the MapboxMap + */ + protected MapboxMap getMapboxMap() { + return mapboxMap; + } - /** - * Do not use this method, used internally by the SDK. - * - * @param mapView the hosting map view - */ - public void setMapView(MapView mapView) { - this.mapView = mapView; - } + /** + * Do not use this method, used internally by the SDK. + * + * @param mapView the hosting map view + */ + public void setMapView(MapView mapView) { + this.mapView = mapView; + } - /** - * Gets the hosting map view. - * - * @return The MapView - */ - protected MapView getMapView() { - return mapView; - } + /** + * Gets the hosting map view. + * + * @return The MapView + */ + protected MapView getMapView() { + return mapView; + } - @Override - public int compareTo(@NonNull Annotation annotation) { - if (id < annotation.getId()) { - return 1; - } else if (id > annotation.getId()) { - return -1; - } - return 0; + @Override + public int compareTo(@NonNull Annotation annotation) { + if (id < annotation.getId()) { + return 1; + } else if (id > annotation.getId()) { + return -1; } + return 0; + } - /** - * Compares this {@link PolylineOptions} object with another {@link PolylineOptions} and - * determines if their color, alpha, width, and vertices match. - * - * @param o Another {@link PolylineOptions} to compare with this object. - * @return True if color, alpha, width, and vertices match this {@link PolylineOptions} object. - * Else, false. - */ - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || !(o instanceof Annotation)) return false; - Annotation that = (Annotation) o; - return id == that.getId(); + /** + * Compares this {@link PolylineOptions} object with another {@link PolylineOptions} and + * determines if their color, alpha, width, and vertices match. + * + * @param object Another {@link PolylineOptions} to compare with this object. + * @return True if color, alpha, width, and vertices match this {@link PolylineOptions} object. + * Else, false. + */ + @Override + public boolean equals(Object object) { + if (this == object) { + return true; } - - /** - * Gives an integer which can be used as the bucket number for storing elements of the set/map. - * This bucket number is the address of the element inside the set/map. There's no guarantee - * that this hash value will be consistent between different Java implementations, or even - * between different execution runs of the same program. - * - * @return integer value you can use for storing element. - */ - @Override - public int hashCode() { - return (int) (getId() ^ (getId() >>> 32)); + if (object == null || !(object instanceof Annotation)) { + return false; } + Annotation that = (Annotation) object; + return id == that.getId(); + } + + /** + * Gives an integer which can be used as the bucket number for storing elements of the set/map. + * This bucket number is the address of the element inside the set/map. There's no guarantee + * that this hash value will be consistent between different Java implementations, or even + * between different execution runs of the same program. + * + * @return integer value you can use for storing element. + */ + @Override + public int hashCode() { + return (int) (getId() ^ (getId() >>> 32)); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java index 4e56531a7f..82868e2888 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerOptions.java @@ -6,7 +6,7 @@ import com.mapbox.mapboxsdk.geometry.LatLng; /** * Abstract builder class for composing custom Marker objects. - * + *

* Extending this class requires implementing Parceable interface. * * @param Type of the marker to be composed @@ -14,107 +14,107 @@ import com.mapbox.mapboxsdk.geometry.LatLng; */ public abstract class BaseMarkerOptions> implements Parcelable { - protected LatLng position; - protected String snippet; - protected String title; - protected Icon icon; + protected LatLng position; + protected String snippet; + protected String title; + protected Icon icon; - /** - * Set the geographical location of the Marker. - * - * @param position the location to position the {@link Marker}. - * @return the object for which the method was called. - */ - public T position(LatLng position) { - this.position = position; - return getThis(); - } + /** + * Set the geographical location of the Marker. + * + * @param position the location to position the {@link Marker}. + * @return the object for which the method was called. + */ + public T position(LatLng position) { + this.position = position; + return getThis(); + } - /** - * Set the snippet of the Marker. - * - * @param snippet the snippet of the {@link Marker}. - * @return the object for which the method was called. - */ - public T snippet(String snippet) { - this.snippet = snippet; - return getThis(); - } + /** + * Set the snippet of the Marker. + * + * @param snippet the snippet of the {@link Marker}. + * @return the object for which the method was called. + */ + public T snippet(String snippet) { + this.snippet = snippet; + return getThis(); + } - /** - * Set the title of the Marker. - * - * @param title the title of the {@link Marker}. - * @return the object for which the method was called. - */ - public T title(String title) { - this.title = title; - return getThis(); - } + /** + * Set the title of the Marker. + * + * @param title the title of the {@link Marker}. + * @return the object for which the method was called. + */ + public T title(String title) { + this.title = title; + return getThis(); + } - /** - * Set the icon of the Marker. - * - * @param icon the icon of the {@link Marker}. - * @return the object for which the method was called. - */ - public T icon(Icon icon) { - this.icon = icon; - return getThis(); - } + /** + * Set the icon of the Marker. + * + * @param icon the icon of the {@link Marker}. + * @return the object for which the method was called. + */ + public T icon(Icon icon) { + this.icon = icon; + return getThis(); + } - /** - * Set the icon of the Marker. - * - * @param icon the icon of the {@link Marker}. - * @return the object for which the method was called. - */ - public T setIcon(Icon icon) { - return icon(icon); - } + /** + * Set the icon of the Marker. + * + * @param icon the icon of the {@link Marker}. + * @return the object for which the method was called. + */ + public T setIcon(Icon icon) { + return icon(icon); + } - /** - * Set the geographical location of the Marker. - * - * @param position the location to position the {@link Marker}. - * @return the object for which the method was called. - */ - public T setPosition(LatLng position) { - return position(position); - } + /** + * Set the geographical location of the Marker. + * + * @param position the location to position the {@link Marker}. + * @return the object for which the method was called. + */ + public T setPosition(LatLng position) { + return position(position); + } - /** - * Set the snippet of the Marker. - * - * @param snippet the snippet of the {@link Marker}. - * @return the object for which the method was called. - */ - public T setSnippet(String snippet) { - return snippet(snippet); - } + /** + * Set the snippet of the Marker. + * + * @param snippet the snippet of the {@link Marker}. + * @return the object for which the method was called. + */ + public T setSnippet(String snippet) { + return snippet(snippet); + } - /** - * Set the title of the Marker. - * - * @param title the title of the {@link Marker}. - * @return the object for which the method was called. - */ - public T setTitle(String title) { - return title(title); - } + /** + * Set the title of the Marker. + * + * @param title the title of the {@link Marker}. + * @return the object for which the method was called. + */ + public T setTitle(String title) { + return title(title); + } - /** - * Get the instance of the object for which this method was called. - * - * @return the object for which the this method was called. - */ - public abstract T getThis(); + /** + * Get the instance of the object for which this method was called. + * + * @return the object for which the this method was called. + */ + public abstract T getThis(); - /** - * Get the Marker. - * - * @return the Marker created from this builder. - */ - public abstract U getMarker(); + /** + * Get the Marker. + * + * @return the Marker created from this builder. + */ + public abstract U getMarker(); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java index e93f2c801d..ddedf3debf 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/BaseMarkerViewOptions.java @@ -15,267 +15,268 @@ import com.mapbox.mapboxsdk.geometry.LatLng; * @param Type of the marker view to be composed. * @param Type of the builder to be used for composing. */ -public abstract class BaseMarkerViewOptions> implements Parcelable { +public abstract class BaseMarkerViewOptions> + implements Parcelable { - protected LatLng position; - protected String snippet; - protected String title; - protected Icon icon; - protected boolean flat; - protected float anchorU = 0.5f; - protected float anchorV = 1f; - protected float infoWindowAnchorU = 0.5f; - protected float infoWindowAnchorV = 0.0f; - protected float rotation; - protected boolean visible = true; - protected boolean selected; - protected float alpha = 1.0f; + protected LatLng position; + protected String snippet; + protected String title; + protected Icon icon; + protected boolean flat; + protected float anchorU = 0.5f; + protected float anchorV = 1f; + protected float infoWindowAnchorU = 0.5f; + protected float infoWindowAnchorV = 0.0f; + protected float rotation; + protected boolean visible = true; + protected boolean selected; + protected float alpha = 1.0f; - /** - * Default constructor - */ - public BaseMarkerViewOptions() { - } + /** + * Default constructor + */ + public BaseMarkerViewOptions() { + } - /** - * Set the geographical location of the MarkerView. - * - * @param position the location to position the {@link MarkerView}. - * @return the object for which the method was called. - */ - public T position(@NonNull LatLng position) { - this.position = position; - return getThis(); - } + /** + * Set the geographical location of the MarkerView. + * + * @param position the location to position the {@link MarkerView}. + * @return the object for which the method was called. + */ + public T position(@NonNull LatLng position) { + this.position = position; + return getThis(); + } - /** - * Set the snippet of the MarkerView. - * - * @param snippet the snippet of the {@link MarkerView}. - * @return the object for which the method was called. - */ - public T snippet(String snippet) { - this.snippet = snippet; - return getThis(); - } + /** + * Set the snippet of the MarkerView. + * + * @param snippet the snippet of the {@link MarkerView}. + * @return the object for which the method was called. + */ + public T snippet(String snippet) { + this.snippet = snippet; + return getThis(); + } - /** - * Set the title of the MarkerView. - * - * @param title the title of the {@link MarkerView}. - * @return the object for which the method was called. - */ - public T title(String title) { - this.title = title; - return getThis(); - } + /** + * Set the title of the MarkerView. + * + * @param title the title of the {@link MarkerView}. + * @return the object for which the method was called. + */ + public T title(String title) { + this.title = title; + return getThis(); + } - /** - * Set the icon of the MarkerView. - * - * @param icon the icon of the {@link MarkerView}. - * @return the object for which the method was called. - */ - public T icon(Icon icon) { - this.icon = icon; - return getThis(); - } + /** + * Set the icon of the MarkerView. + * + * @param icon the icon of the {@link MarkerView}. + * @return the object for which the method was called. + */ + public T icon(Icon icon) { + this.icon = icon; + return getThis(); + } - /** - * Set the flat state of the MarkerView. - * - * @param flat the flat state of the {@link MarkerView}. - * @return the object for which the method was called. - */ - public T flat(boolean flat) { - this.flat = flat; - return getThis(); - } + /** + * Set the flat state of the MarkerView. + * + * @param flat the flat state of the {@link MarkerView}. + * @return the object for which the method was called. + */ + public T flat(boolean flat) { + this.flat = flat; + return getThis(); + } - /** - * Set the anchor of the {@link MarkerView}. - * - * @param u the u-value. - * @param v the v-value. - * @return the object for which the method was called. - */ - public T anchor(@FloatRange(from = 0.0, to = 1.0) float u, @FloatRange(from = 0.0, to = 1.0) float v) { - this.anchorU = u; - this.anchorV = v; - return getThis(); - } + /** + * Set the anchor of the {@link MarkerView}. + * + * @param u the u-value. + * @param v the v-value. + * @return the object for which the method was called. + */ + public T anchor(@FloatRange(from = 0.0, to = 1.0) float u, @FloatRange(from = 0.0, to = 1.0) float v) { + this.anchorU = u; + this.anchorV = v; + return getThis(); + } - /** - * Set the InfoWindow anchor of the {@link MarkerView}. - * - * @param u the u-value. - * @param v the v-values. - * @return the object for which the method was called. - */ - public T infoWindowAnchor(@FloatRange(from = 0.0, to = 1.0) float u, @FloatRange(from = 0.0, to = 1.0) float v) { - this.infoWindowAnchorU = u; - this.infoWindowAnchorV = v; - return getThis(); - } + /** + * Set the InfoWindow anchor of the {@link MarkerView}. + * + * @param u the u-value. + * @param v the v-values. + * @return the object for which the method was called. + */ + public T infoWindowAnchor(@FloatRange(from = 0.0, to = 1.0) float u, @FloatRange(from = 0.0, to = 1.0) float v) { + this.infoWindowAnchorU = u; + this.infoWindowAnchorV = v; + return getThis(); + } - /** - * Set the rotation of the {@link MarkerView}. - * - * @param rotation the rotation value. - * @return the object for which the method was called. - */ - public T rotation(float rotation) { - this.rotation = rotation; - while (this.rotation > 360) { - this.rotation -= 360; - } - while (this.rotation < 0) { - this.rotation += 360; - } - return getThis(); + /** + * Set the rotation of the {@link MarkerView}. + * + * @param rotation the rotation value. + * @return the object for which the method was called. + */ + public T rotation(float rotation) { + this.rotation = rotation; + while (this.rotation > 360) { + this.rotation -= 360; } - - /** - * Set the visibility state of the {@link MarkerView}. - * - * @param visible the visible state. - * @return the object for which the method was called. - */ - public T visible(boolean visible) { - this.visible = visible; - return getThis(); + while (this.rotation < 0) { + this.rotation += 360; } + return getThis(); + } - /** - * Set the alpha of the {@link MarkerView}. - * - * @param alpha the alpha value. - * @return the object for which the method was called. - */ - public T alpha(float alpha) { - this.alpha = alpha; - return getThis(); - } + /** + * Set the visibility state of the {@link MarkerView}. + * + * @param visible the visible state. + * @return the object for which the method was called. + */ + public T visible(boolean visible) { + this.visible = visible; + return getThis(); + } - /** - * Get the geographical location of the {@link MarkerView}. - * - * @return the geographical location. - */ - public LatLng getPosition() { - return position; - } + /** + * Set the alpha of the {@link MarkerView}. + * + * @param alpha the alpha value. + * @return the object for which the method was called. + */ + public T alpha(float alpha) { + this.alpha = alpha; + return getThis(); + } - /** - * Get the snippet of the {@link MarkerView}. - * - * @return the snippet. - */ - public String getSnippet() { - return snippet; - } + /** + * Get the geographical location of the {@link MarkerView}. + * + * @return the geographical location. + */ + public LatLng getPosition() { + return position; + } - /** - * Get the title of the {@link MarkerView}. - * - * @return the title. - */ - public String getTitle() { - return title; - } + /** + * Get the snippet of the {@link MarkerView}. + * + * @return the snippet. + */ + public String getSnippet() { + return snippet; + } - /** - * Get the icon of the {@link MarkerView}. - * - * @return the icon. - */ - public Icon getIcon() { - return icon; - } + /** + * Get the title of the {@link MarkerView}. + * + * @return the title. + */ + public String getTitle() { + return title; + } - /** - * Get the flat state of the {@link MarkerView}. - * - * @return the flat state. - */ - public boolean isFlat() { - return flat; - } + /** + * Get the icon of the {@link MarkerView}. + * + * @return the icon. + */ + public Icon getIcon() { + return icon; + } - /** - * Get the u-value of the {@link MarkerView} anchor. - * - * @return the u-value. - */ - public float getAnchorU() { - return anchorU; - } + /** + * Get the flat state of the {@link MarkerView}. + * + * @return the flat state. + */ + public boolean isFlat() { + return flat; + } - /** - * Get the v-value of the {@link MarkerView} anchor. - * - * @return the v-value. - */ - public float getAnchorV() { - return anchorV; - } + /** + * Get the u-value of the {@link MarkerView} anchor. + * + * @return the u-value. + */ + public float getAnchorU() { + return anchorU; + } - /** - * Get the u-value of the MarkerView InfoWindow anchor. - * - * @return the u-value. - */ - public float getInfoWindowAnchorU() { - return infoWindowAnchorU; - } + /** + * Get the v-value of the {@link MarkerView} anchor. + * + * @return the v-value. + */ + public float getAnchorV() { + return anchorV; + } - /** - * Get the v-value of the MarkerView InfoWindow anchor. - * - * @return the v-value. - */ - public float getInfoWindowAnchorV() { - return infoWindowAnchorV; - } + /** + * Get the u-value of the MarkerView InfoWindow anchor. + * + * @return the u-value. + */ + public float getInfoWindowAnchorU() { + return infoWindowAnchorU; + } - /** - * Get the rotation of the MarkerView. - * - * @return the rotation value. - */ - public float getRotation() { - return rotation; - } + /** + * Get the v-value of the MarkerView InfoWindow anchor. + * + * @return the v-value. + */ + public float getInfoWindowAnchorV() { + return infoWindowAnchorV; + } - /** - * Get the visibility state of the MarkerView. - * - * @return the visibility state. - */ - public boolean isVisible() { - return visible; - } + /** + * Get the rotation of the MarkerView. + * + * @return the rotation value. + */ + public float getRotation() { + return rotation; + } - /** - * Get the alpha of the MarkerView. - * - * @return the alpha value. - */ - public float getAlpha() { - return alpha; - } + /** + * Get the visibility state of the MarkerView. + * + * @return the visibility state. + */ + public boolean isVisible() { + return visible; + } + + /** + * Get the alpha of the MarkerView. + * + * @return the alpha value. + */ + public float getAlpha() { + return alpha; + } - /** - * Get the instance of the object for which this method was called. - * - * @return the object for which the this method was called. - */ - public abstract T getThis(); + /** + * Get the instance of the object for which this method was called. + * + * @return the object for which the this method was called. + */ + public abstract T getThis(); - /** - * Get the MarkerView. - * - * @return the MarkerView created from this builder. - */ - public abstract U getMarker(); + /** + * Get the MarkerView. + * + * @return the MarkerView created from this builder. + */ + public abstract U getMarker(); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java index ae7cf6eb8c..b1a05ec436 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Icon.java @@ -10,67 +10,73 @@ import com.mapbox.mapboxsdk.maps.MapView; * @see Marker */ public class Icon { - private Bitmap mBitmap; - private String mId; + private Bitmap mBitmap; + private String mId; - Icon(String id, Bitmap bitmap) { - mId = id; - mBitmap = bitmap; - } + Icon(String id, Bitmap bitmap) { + mId = id; + mBitmap = bitmap; + } - /** - * {@link String} identifier for this {@link Icon}. - * - * @return {@link String} identifier for this {@link Icon}. - */ - public String getId() { - return mId; - } + /** + * {@link String} identifier for this {@link Icon}. + * + * @return {@link String} identifier for this {@link Icon}. + */ + public String getId() { + return mId; + } - /** - * Get the {@link Bitmap} being used for this {@link Icon}. - * - * @return The {@link Bitmap} being used for the {@link Icon}. - */ - public Bitmap getBitmap() { - return mBitmap; - } + /** + * Get the {@link Bitmap} being used for this {@link Icon}. + * + * @return The {@link Bitmap} being used for the {@link Icon}. + */ + public Bitmap getBitmap() { + return mBitmap; + } - /** - * Compares this {@link Icon} object with another {@link Icon} and determines if they match. - * - * @param o Another {@link Icon} to compare with this object. - * @return True if the {@link Icon} being passed in matches this {@link Icon} object. Else, - * false. - */ - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; + /** + * Compares this {@link Icon} object with another {@link Icon} and determines if they match. + * + * @param object Another {@link Icon} to compare with this object. + * @return True if the {@link Icon} being passed in matches this {@link Icon} object. Else, + * false. + */ + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } - Icon icon = (Icon) o; + Icon icon = (Icon) object; - if (!mBitmap.equals(icon.mBitmap)) return false; - return mId.equals(icon.mId); + if (!mBitmap.equals(icon.mBitmap)) { + return false; } + return mId.equals(icon.mId); + } - /** - * Gives an integer which can be used as the bucket number for storing elements of the set/map. - * This bucket number is the address of the element inside the set/map. There's no guarantee - * that this hash value will be consistent between different Java implementations, or even - * between different execution runs of the same program. - * - * @return integer value you can use for storing element. - */ - @Override - public int hashCode() { - int result = 0; - if (mBitmap != null) { - result = mBitmap.hashCode(); - } - if (mId != null) { - result = 31 * result + mId.hashCode(); - } - return result; + /** + * Gives an integer which can be used as the bucket number for storing elements of the set/map. + * This bucket number is the address of the element inside the set/map. There's no guarantee + * that this hash value will be consistent between different Java implementations, or even + * between different execution runs of the same program. + * + * @return integer value you can use for storing element. + */ + @Override + public int hashCode() { + int result = 0; + if (mBitmap != null) { + result = mBitmap.hashCode(); + } + if (mId != null) { + result = 31 * result + mId.hashCode(); } + return result; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java index 9427501bb8..052d5592e4 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/IconFactory.java @@ -29,205 +29,207 @@ import java.io.InputStream; */ public final class IconFactory { - private static final String ICON_ID_PREFIX = "com.mapbox.icons.icon_"; - public static final Bitmap ICON_MARKERVIEW_BITMAP = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8); - public static final String ICON_MARKERVIEW_ID = ICON_ID_PREFIX + "marker_view"; - - private Context mContext; - private static IconFactory sInstance; - private Icon mDefaultMarker; - private Icon mDefaultMarkerView; - private BitmapFactory.Options mOptions; - - private int mNextId = 0; - - public static synchronized IconFactory getInstance(@NonNull Context context) { - if (sInstance == null) { - sInstance = new IconFactory(context.getApplicationContext()); - } - return sInstance; - } + private static final String ICON_ID_PREFIX = "com.mapbox.icons.icon_"; + public static final Bitmap ICON_MARKERVIEW_BITMAP = Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8); + public static final String ICON_MARKERVIEW_ID = ICON_ID_PREFIX + "marker_view"; - private IconFactory(@NonNull Context context) { - mContext = context; - DisplayMetrics realMetrics = null; - DisplayMetrics metrics = new DisplayMetrics(); - WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - realMetrics = new DisplayMetrics(); - wm.getDefaultDisplay().getRealMetrics(realMetrics); - } - wm.getDefaultDisplay().getMetrics(metrics); - - mOptions = new BitmapFactory.Options(); - mOptions.inScaled = true; - mOptions.inDensity = DisplayMetrics.DENSITY_DEFAULT; - mOptions.inTargetDensity = metrics.densityDpi; - if (realMetrics != null) { - mOptions.inScreenDensity = realMetrics.densityDpi; - } - } + private Context mContext; + private static IconFactory sInstance; + private Icon mDefaultMarker; + private Icon mDefaultMarkerView; + private BitmapFactory.Options mOptions; - /** - * Creates an {@link Icon} from a given Bitmap image. - * - * @param bitmap image used for creating the Icon. - * @return The {@link Icon} using the given Bitmap image. - */ - public Icon fromBitmap(@NonNull Bitmap bitmap) { - if (mNextId < 0) { - throw new TooManyIconsException(); - } - String id = ICON_ID_PREFIX + ++mNextId; - return new Icon(id, bitmap); - } + private int mNextId = 0; - /** - * Create an {@link Icon} from a given {@link Drawable}. - * - * @param drawable A {@link Drawable} object used for creating the {@link Icon}. - * @return {@link Icon} with the provided {@link Drawable}. - */ - public Icon fromDrawable(@NonNull Drawable drawable) { - int width = drawable.getIntrinsicWidth(); - int height = drawable.getIntrinsicHeight(); - return fromDrawable(drawable, width, height); + public static synchronized IconFactory getInstance(@NonNull Context context) { + if (sInstance == null) { + sInstance = new IconFactory(context.getApplicationContext()); } - - /** - * Create an {@link Icon} from a given {@link Drawable}. - * - * @param drawable A {@link Drawable} object used for creating the {@link Icon}. - * @param width An integer greater then zero defining the {@link Icon} width. - * @param height An integer greater then zero defining the {@link Icon} height. - * @return {@link Icon} with the provided {@link Drawable}. - */ - public Icon fromDrawable(@NonNull Drawable drawable, int width, int height) { - if ((width < 0) || (height < 0)) { - return null; - } - - Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - Rect temp = drawable.getBounds(); - Rect bounds = new Rect(0, 0, width, height); - drawable.setBounds(bounds); - drawable.draw(canvas); - drawable.setBounds(temp); - return fromBitmap(bitmap); + return sInstance; + } + + private IconFactory(@NonNull Context context) { + mContext = context; + DisplayMetrics realMetrics = null; + DisplayMetrics metrics = new DisplayMetrics(); + WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { + realMetrics = new DisplayMetrics(); + wm.getDefaultDisplay().getRealMetrics(realMetrics); } - - /** - * Create an {@link Icon} using the resource ID of a Bitmap image. - * - * @param resourceId The resource ID of a Bitmap image. - * @return The {@link Icon} that was loaded from the asset or {@code null} if failed to load. - */ - public Icon fromResource(@DrawableRes int resourceId) { - Drawable drawable = ContextCompat.getDrawable(mContext, resourceId); - Bitmap bitmap; - if (drawable instanceof BitmapDrawable) { - BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; - bitmap = bitmapDrawable.getBitmap(); - } else { - if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) { - bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); - } else { - bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); - } - - Canvas canvas = new Canvas(bitmap); - drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - drawable.draw(canvas); - } - return fromBitmap(bitmap); + wm.getDefaultDisplay().getMetrics(metrics); + + mOptions = new BitmapFactory.Options(); + mOptions.inScaled = true; + mOptions.inDensity = DisplayMetrics.DENSITY_DEFAULT; + mOptions.inTargetDensity = metrics.densityDpi; + if (realMetrics != null) { + mOptions.inScreenDensity = realMetrics.densityDpi; } - - /** - * Provides an {@link Icon} using the default marker icon used for {@link Marker}. - * - * @return An {@link Icon} with the default {@link Marker} icon. - */ - public Icon defaultMarker() { - if (mDefaultMarker == null) { - mDefaultMarker = fromResource(R.drawable.mapbox_marker_icon_default); - } - return mDefaultMarker; + } + + /** + * Creates an {@link Icon} from a given Bitmap image. + * + * @param bitmap image used for creating the Icon. + * @return The {@link Icon} using the given Bitmap image. + */ + public Icon fromBitmap(@NonNull Bitmap bitmap) { + if (mNextId < 0) { + throw new TooManyIconsException(); } - - /** - * Provides an {@link Icon} using the default marker icon used for {@link MarkerView}. - * - * @return An {@link Icon} with the default {@link MarkerView} icon. - */ - public Icon defaultMarkerView() { - if (mDefaultMarkerView == null) { - mDefaultMarkerView = fromResource(R.drawable.mapbox_markerview_icon_default); - } - return mDefaultMarkerView; + String id = ICON_ID_PREFIX + ++mNextId; + return new Icon(id, bitmap); + } + + /** + * Create an {@link Icon} from a given {@link Drawable}. + * + * @param drawable A {@link Drawable} object used for creating the {@link Icon}. + * @return {@link Icon} with the provided {@link Drawable}. + */ + public Icon fromDrawable(@NonNull Drawable drawable) { + int width = drawable.getIntrinsicWidth(); + int height = drawable.getIntrinsicHeight(); + return fromDrawable(drawable, width, height); + } + + /** + * Create an {@link Icon} from a given {@link Drawable}. + * + * @param drawable A {@link Drawable} object used for creating the {@link Icon}. + * @param width An integer greater then zero defining the {@link Icon} width. + * @param height An integer greater then zero defining the {@link Icon} height. + * @return {@link Icon} with the provided {@link Drawable}. + */ + public Icon fromDrawable(@NonNull Drawable drawable, int width, int height) { + if ((width < 0) || (height < 0)) { + return null; } - private Icon fromInputStream(@NonNull InputStream is) { - Bitmap bitmap = BitmapFactory.decodeStream(is, null, mOptions); - return fromBitmap(bitmap); + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + Rect temp = drawable.getBounds(); + Rect bounds = new Rect(0, 0, width, height); + drawable.setBounds(bounds); + drawable.draw(canvas); + drawable.setBounds(temp); + return fromBitmap(bitmap); + } + + /** + * Create an {@link Icon} using the resource ID of a Bitmap image. + * + * @param resourceId The resource ID of a Bitmap image. + * @return The {@link Icon} that was loaded from the asset or {@code null} if failed to load. + */ + public Icon fromResource(@DrawableRes int resourceId) { + Drawable drawable = ContextCompat.getDrawable(mContext, resourceId); + Bitmap bitmap; + if (drawable instanceof BitmapDrawable) { + BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable; + bitmap = bitmapDrawable.getBitmap(); + } else { + if (drawable.getIntrinsicWidth() <= 0 || drawable.getIntrinsicHeight() <= 0) { + bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888); + } else { + bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), + Bitmap.Config.ARGB_8888); + } + + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + drawable.draw(canvas); } - - /** - * Creates an {@link Icon} using the name of a Bitmap image in the assets directory. - * - * @param assetName The name of a Bitmap image in the assets directory. - * @return The {@link Icon} that was loaded from the asset or {@code null} if failed to load. - */ - public Icon fromAsset(@NonNull String assetName) { - InputStream is; - try { - is = mContext.getAssets().open(assetName); - } catch (IOException e) { - return null; - } - return fromInputStream(is); + return fromBitmap(bitmap); + } + + /** + * Provides an {@link Icon} using the default marker icon used for {@link Marker}. + * + * @return An {@link Icon} with the default {@link Marker} icon. + */ + public Icon defaultMarker() { + if (mDefaultMarker == null) { + mDefaultMarker = fromResource(R.drawable.mapbox_marker_icon_default); } - - /** - * Creates an {@link Icon} using the absolute file path of a Bitmap image. - * - * @param absolutePath The absolute path of the Bitmap image. - * @return The {@link Icon} that was loaded from the absolute path or {@code null} if failed to - * load. - */ - public Icon fromPath(@NonNull String absolutePath) { - Bitmap bitmap = BitmapFactory.decodeFile(absolutePath, mOptions); - return fromBitmap(bitmap); + return mDefaultMarker; + } + + /** + * Provides an {@link Icon} using the default marker icon used for {@link MarkerView}. + * + * @return An {@link Icon} with the default {@link MarkerView} icon. + */ + public Icon defaultMarkerView() { + if (mDefaultMarkerView == null) { + mDefaultMarkerView = fromResource(R.drawable.mapbox_markerview_icon_default); } - - /** - * Create an {@link Icon} using the name of a Bitmap image file located in the internal storage. - * In particular, this calls {@link Context#openFileInput(String)}. - * - * @param fileName The name of the Bitmap image file. - * @return The {@link Icon} that was loaded from the asset or {@code null} if failed to load. - * @see Using the Internal Storage - */ - public Icon fromFile(@NonNull String fileName) { - FileInputStream is; - try { - is = mContext.openFileInput(fileName); - } catch (FileNotFoundException e) { - return null; - } - return fromInputStream(is); + return mDefaultMarkerView; + } + + private Icon fromInputStream(@NonNull InputStream is) { + Bitmap bitmap = BitmapFactory.decodeStream(is, null, mOptions); + return fromBitmap(bitmap); + } + + /** + * Creates an {@link Icon} using the name of a Bitmap image in the assets directory. + * + * @param assetName The name of a Bitmap image in the assets directory. + * @return The {@link Icon} that was loaded from the asset or {@code null} if failed to load. + */ + public Icon fromAsset(@NonNull String assetName) { + InputStream is; + try { + is = mContext.getAssets().open(assetName); + } catch (IOException ioException) { + return null; } - - /** - * Create an {@link Icon} using a previously created icon identifier along with a provided - * Bitmap. - * - * @param iconId The {@link Icon} identifier you'd like to recreate. - * @param bitmap a Bitmap used to replace the current one. - * @return The {@link Icon} using the new Bitmap. - */ - public static Icon recreate(@NonNull String iconId, @NonNull Bitmap bitmap) { - return new Icon(iconId, bitmap); + return fromInputStream(is); + } + + /** + * Creates an {@link Icon} using the absolute file path of a Bitmap image. + * + * @param absolutePath The absolute path of the Bitmap image. + * @return The {@link Icon} that was loaded from the absolute path or {@code null} if failed to + * load. + */ + public Icon fromPath(@NonNull String absolutePath) { + Bitmap bitmap = BitmapFactory.decodeFile(absolutePath, mOptions); + return fromBitmap(bitmap); + } + + /** + * Create an {@link Icon} using the name of a Bitmap image file located in the internal storage. + * In particular, this calls {@link Context#openFileInput(String)}. + * + * @param fileName The name of the Bitmap image file. + * @return The {@link Icon} that was loaded from the asset or {@code null} if failed to load. + * @see + * Using the Internal Storage + */ + public Icon fromFile(@NonNull String fileName) { + FileInputStream is; + try { + is = mContext.openFileInput(fileName); + } catch (FileNotFoundException fileNotFoundException) { + return null; } + return fromInputStream(is); + } + + /** + * Create an {@link Icon} using a previously created icon identifier along with a provided + * Bitmap. + * + * @param iconId The {@link Icon} identifier you'd like to recreate. + * @param bitmap a Bitmap used to replace the current one. + * @return The {@link Icon} using the new Bitmap. + */ + public static Icon recreate(@NonNull String iconId, @NonNull Bitmap bitmap) { + return new Icon(iconId, bitmap); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java index b33d489da2..34d2c31139 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindow.java @@ -31,270 +31,271 @@ import java.lang.ref.WeakReference; */ public class InfoWindow { - private WeakReference mBoundMarker; - private WeakReference mMapboxMap; - protected WeakReference mView; - - private float mMarkerHeightOffset; - private float mMarkerWidthOffset; - private float mViewWidthOffset; - private PointF mCoordinates; - private boolean mIsVisible; - - @LayoutRes - private int mLayoutRes; - - InfoWindow(MapView mapView, int layoutResId, MapboxMap mapboxMap) { - mLayoutRes = layoutResId; - View view = LayoutInflater.from(mapView.getContext()).inflate(layoutResId, mapView, false); - initialize(view, mapboxMap); - } + private WeakReference boundMarker; + private WeakReference mapboxMap; + protected WeakReference view; + + private float markerHeightOffset; + private float markerWidthOffset; + private float viewWidthOffset; + private PointF coordinates; + private boolean isVisible; + + @LayoutRes + private int layoutRes; + + InfoWindow(MapView mapView, int layoutResId, MapboxMap mapboxMap) { + layoutRes = layoutResId; + View view = LayoutInflater.from(mapView.getContext()).inflate(layoutResId, mapView, false); + initialize(view, mapboxMap); + } + + InfoWindow(View view, MapboxMap mapboxMap) { + initialize(view, mapboxMap); + } + + private void initialize(View view, MapboxMap mapboxMap) { + this.mapboxMap = new WeakReference<>(mapboxMap); + isVisible = false; + this.view = new WeakReference<>(view); + + view.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + MapboxMap mapboxMap = InfoWindow.this.mapboxMap.get(); + if (mapboxMap != null) { + MapboxMap.OnInfoWindowClickListener onInfoWindowClickListener = mapboxMap.getOnInfoWindowClickListener(); + boolean handledDefaultClick = false; + if (onInfoWindowClickListener != null) { + handledDefaultClick = onInfoWindowClickListener.onInfoWindowClick(getBoundMarker()); + } + + if (!handledDefaultClick) { + // default behavior: close it when clicking on the tooltip: + close(); + } + } + } + }); + + view.setOnLongClickListener(new View.OnLongClickListener() { + @Override + public boolean onLongClick(View v) { + MapboxMap mapboxMap = InfoWindow.this.mapboxMap.get(); + if (mapboxMap != null) { + MapboxMap.OnInfoWindowLongClickListener listener = mapboxMap.getOnInfoWindowLongClickListener(); + if (listener != null) { + listener.onInfoWindowLongClick(getBoundMarker()); + } + } + return true; + } + }); + } + + + /** + * Open the info window at the specified position. + * + * @param boundMarker The marker on which is hooked the view. + * @param position to place the window on the map. + * @param offsetX The offset of the view to the position, in pixels. This allows to offset + * the view from the object position. + * @param offsetY The offset of the view to the position, in pixels. This allows to offset + * the view from the object position. + * @return this {@link InfoWindow}. + */ + InfoWindow open(MapView mapView, Marker boundMarker, LatLng position, int offsetX, int offsetY) { + setBoundMarker(boundMarker); + + MapView.LayoutParams lp = new MapView.LayoutParams(MapView.LayoutParams.WRAP_CONTENT, + MapView.LayoutParams.WRAP_CONTENT); + + MapboxMap mapboxMap = this.mapboxMap.get(); + View view = this.view.get(); + if (view != null && mapboxMap != null) { + view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + + // Calculate y-offset for update method + markerHeightOffset = -view.getMeasuredHeight() + offsetY; + markerWidthOffset = -offsetX; + + // Calculate default Android x,y coordinate + coordinates = mapboxMap.getProjection().toScreenLocation(position); + float x = coordinates.x - (view.getMeasuredWidth() / 2) + offsetX; + float y = coordinates.y - view.getMeasuredHeight() + offsetY; + + if (view instanceof InfoWindowView) { + // only apply repositioning/margin for InfoWindowView + Resources resources = mapView.getContext().getResources(); + + // get right/left popup window + float rightSideInfowWindow = x + view.getMeasuredWidth(); + float leftSideInfoWindow = x; + + // get right/left map view + final float mapRight = mapView.getRight(); + final float mapLeft = mapView.getLeft(); + + float marginHorizontal = resources.getDimension(R.dimen.mapbox_infowindow_margin); + float tipViewOffset = resources.getDimension(R.dimen.mapbox_infowindow_tipview_width) / 2; + float tipViewMarginLeft = view.getMeasuredWidth() / 2 - tipViewOffset; + + boolean outOfBoundsLeft = false; + boolean outOfBoundsRight = false; + + // only optimise margins if view is inside current viewport + if (coordinates.x >= 0 && coordinates.x <= mapView.getWidth() + && coordinates.y >= 0 && coordinates.y <= mapView.getHeight()) { + + // if out of bounds right + if (rightSideInfowWindow > mapRight) { + outOfBoundsRight = true; + x -= rightSideInfowWindow - mapRight; + tipViewMarginLeft += rightSideInfowWindow - mapRight + tipViewOffset; + rightSideInfowWindow = x + view.getMeasuredWidth(); + } + + // fit screen left + if (leftSideInfoWindow < mapLeft) { + outOfBoundsLeft = true; + x += mapLeft - leftSideInfoWindow; + tipViewMarginLeft -= mapLeft - leftSideInfoWindow + tipViewOffset; + leftSideInfoWindow = x; + } + + // Add margin right + if (outOfBoundsRight && mapRight - rightSideInfowWindow < marginHorizontal) { + x -= marginHorizontal - (mapRight - rightSideInfowWindow); + tipViewMarginLeft += marginHorizontal - (mapRight - rightSideInfowWindow) - tipViewOffset; + leftSideInfoWindow = x; + } + + // Add margin left + if (outOfBoundsLeft && leftSideInfoWindow - mapLeft < marginHorizontal) { + x += marginHorizontal - (leftSideInfoWindow - mapLeft); + tipViewMarginLeft -= (marginHorizontal - (leftSideInfoWindow - mapLeft)) - tipViewOffset; + } + } - InfoWindow(View view, MapboxMap mapboxMap) { - initialize(view, mapboxMap); - } + // Adjust tipView + InfoWindowView infoWindowView = (InfoWindowView) view; + infoWindowView.setTipViewMarginLeft((int) tipViewMarginLeft); + } - private void initialize(View view, MapboxMap mapboxMap) { - mMapboxMap = new WeakReference<>(mapboxMap); - mIsVisible = false; - mView = new WeakReference<>(view); - - view.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - MapboxMap mapboxMap = mMapboxMap.get(); - if (mapboxMap != null) { - MapboxMap.OnInfoWindowClickListener onInfoWindowClickListener = mapboxMap.getOnInfoWindowClickListener(); - boolean handledDefaultClick = false; - if (onInfoWindowClickListener != null) { - handledDefaultClick = onInfoWindowClickListener.onInfoWindowClick(getBoundMarker()); - } - - if (!handledDefaultClick) { - // default behavior: close it when clicking on the tooltip: - close(); - } - } - } - }); - - view.setOnLongClickListener(new View.OnLongClickListener() { - @Override - public boolean onLongClick(View v) { - MapboxMap mapboxMap = mMapboxMap.get(); - if (mapboxMap != null) { - MapboxMap.OnInfoWindowLongClickListener listener = mapboxMap.getOnInfoWindowLongClickListener(); - if (listener != null) { - listener.onInfoWindowLongClick(getBoundMarker()); - } - } - return true; - } - }); - } + // set anchor popupwindowview + view.setX(x); + view.setY(y); + // Calculate x-offset for update method + viewWidthOffset = x - coordinates.x - offsetX; - /** - * Open the info window at the specified position. - * - * @param boundMarker The marker on which is hooked the view. - * @param position to place the window on the map. - * @param offsetX The offset of the view to the position, in pixels. This allows to offset - * the view from the object position. - * @param offsetY The offset of the view to the position, in pixels. This allows to offset - * the view from the object position. - * @return this {@link InfoWindow}. - */ - InfoWindow open(MapView mapView, Marker boundMarker, LatLng position, int offsetX, int offsetY) { - setBoundMarker(boundMarker); - - MapView.LayoutParams lp = new MapView.LayoutParams(MapView.LayoutParams.WRAP_CONTENT, MapView.LayoutParams.WRAP_CONTENT); - - MapboxMap mapboxMap = mMapboxMap.get(); - View view = mView.get(); - if (view != null && mapboxMap != null) { - view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); - - // Calculate y-offset for update method - mMarkerHeightOffset = -view.getMeasuredHeight() + offsetY; - mMarkerWidthOffset = -offsetX; - - // Calculate default Android x,y coordinate - mCoordinates = mapboxMap.getProjection().toScreenLocation(position); - float x = mCoordinates.x - (view.getMeasuredWidth() / 2) + offsetX; - float y = mCoordinates.y - view.getMeasuredHeight() + offsetY; - - if (view instanceof InfoWindowView) { - // only apply repositioning/margin for InfoWindowView - Resources resources = mapView.getContext().getResources(); - - // get right/left popup window - float rightSideInfowWindow = x + view.getMeasuredWidth(); - float leftSideInfoWindow = x; - - // get right/left map view - final float mapRight = mapView.getRight(); - final float mapLeft = mapView.getLeft(); - - float marginHorizontal = resources.getDimension(R.dimen.mapbox_infowindow_margin); - float tipViewOffset = resources.getDimension(R.dimen.mapbox_infowindow_tipview_width) / 2; - float tipViewMarginLeft = view.getMeasuredWidth() / 2 - tipViewOffset; - - boolean outOfBoundsLeft = false; - boolean outOfBoundsRight = false; - - // only optimise margins if view is inside current viewport - if (mCoordinates.x >= 0 && mCoordinates.x <= mapView.getWidth() - && mCoordinates.y >= 0 && mCoordinates.y <= mapView.getHeight()) { - - // if out of bounds right - if (rightSideInfowWindow > mapRight) { - outOfBoundsRight = true; - x -= rightSideInfowWindow - mapRight; - tipViewMarginLeft += rightSideInfowWindow - mapRight + tipViewOffset; - rightSideInfowWindow = x + view.getMeasuredWidth(); - } - - // fit screen left - if (leftSideInfoWindow < mapLeft) { - outOfBoundsLeft = true; - x += mapLeft - leftSideInfoWindow; - tipViewMarginLeft -= mapLeft - leftSideInfoWindow + tipViewOffset; - leftSideInfoWindow = x; - } - - // Add margin right - if (outOfBoundsRight && mapRight - rightSideInfowWindow < marginHorizontal) { - x -= marginHorizontal - (mapRight - rightSideInfowWindow); - tipViewMarginLeft += marginHorizontal - (mapRight - rightSideInfowWindow) - tipViewOffset; - leftSideInfoWindow = x; - } - - // Add margin left - if (outOfBoundsLeft && leftSideInfoWindow - mapLeft < marginHorizontal) { - x += marginHorizontal - (leftSideInfoWindow - mapLeft); - tipViewMarginLeft -= (marginHorizontal - (leftSideInfoWindow - mapLeft)) - tipViewOffset; - } - } - - // Adjust tipView - InfoWindowView infoWindowView = (InfoWindowView) view; - infoWindowView.setTipViewMarginLeft((int) tipViewMarginLeft); - } - - // set anchor popupwindowview - view.setX(x); - view.setY(y); - - // Calculate x-offset for update method - mViewWidthOffset = x - mCoordinates.x - offsetX; - - close(); //if it was already opened - mapView.addView(view, lp); - mIsVisible = true; - } - return this; + close(); //if it was already opened + mapView.addView(view, lp); + isVisible = true; } - - /** - * Close this {@link InfoWindow} if it is visible, otherwise calling this will do nothing. - * - * @return This {@link InfoWindow} - */ - InfoWindow close() { - MapboxMap mapboxMap = mMapboxMap.get(); - if (mIsVisible && mapboxMap != null) { - mIsVisible = false; - View view = mView.get(); - if (view != null && view.getParent() != null) { - ((ViewGroup) view.getParent()).removeView(view); - } - - Marker marker = getBoundMarker(); - MapboxMap.OnInfoWindowCloseListener listener = mapboxMap.getOnInfoWindowCloseListener(); - if (listener != null) { - listener.onInfoWindowClose(marker); - } - - setBoundMarker(null); - } - return this; + return this; + } + + /** + * Close this {@link InfoWindow} if it is visible, otherwise calling this will do nothing. + * + * @return This {@link InfoWindow} + */ + InfoWindow close() { + MapboxMap mapboxMap = this.mapboxMap.get(); + if (isVisible && mapboxMap != null) { + isVisible = false; + View view = this.view.get(); + if (view != null && view.getParent() != null) { + ((ViewGroup) view.getParent()).removeView(view); + } + + Marker marker = getBoundMarker(); + MapboxMap.OnInfoWindowCloseListener listener = mapboxMap.getOnInfoWindowCloseListener(); + if (listener != null) { + listener.onInfoWindowClose(marker); + } + + setBoundMarker(null); } - - /** - * Constructs the view that is displayed when the InfoWindow opens. This retrieves data from - * overlayItem and shows it in the tooltip. - * - * @param overlayItem the tapped overlay item - */ - void adaptDefaultMarker(Marker overlayItem, MapboxMap mapboxMap, MapView mapView) { - View view = mView.get(); - if (view == null) { - view = LayoutInflater.from(mapView.getContext()).inflate(mLayoutRes, mapView, false); - initialize(view, mapboxMap); - } - mMapboxMap = new WeakReference<>(mapboxMap); - String title = overlayItem.getTitle(); - TextView titleTextView = ((TextView) view.findViewById(R.id.infowindow_title)); - if (!TextUtils.isEmpty(title)) { - titleTextView.setText(title); - titleTextView.setVisibility(View.VISIBLE); - } else { - titleTextView.setVisibility(View.GONE); - } - - String snippet = overlayItem.getSnippet(); - TextView snippetTextView = ((TextView) view.findViewById(R.id.infowindow_description)); - if (!TextUtils.isEmpty(snippet)) { - snippetTextView.setText(snippet); - snippetTextView.setVisibility(View.VISIBLE); - } else { - snippetTextView.setVisibility(View.GONE); - } + return this; + } + + /** + * Constructs the view that is displayed when the InfoWindow opens. This retrieves data from + * overlayItem and shows it in the tooltip. + * + * @param overlayItem the tapped overlay item + */ + void adaptDefaultMarker(Marker overlayItem, MapboxMap mapboxMap, MapView mapView) { + View view = this.view.get(); + if (view == null) { + view = LayoutInflater.from(mapView.getContext()).inflate(layoutRes, mapView, false); + initialize(view, mapboxMap); } - - InfoWindow setBoundMarker(Marker boundMarker) { - mBoundMarker = new WeakReference<>(boundMarker); - return this; + this.mapboxMap = new WeakReference<>(mapboxMap); + String title = overlayItem.getTitle(); + TextView titleTextView = ((TextView) view.findViewById(R.id.infowindow_title)); + if (!TextUtils.isEmpty(title)) { + titleTextView.setText(title); + titleTextView.setVisibility(View.VISIBLE); + } else { + titleTextView.setVisibility(View.GONE); } - Marker getBoundMarker() { - if (mBoundMarker == null) { - return null; - } - return mBoundMarker.get(); + String snippet = overlayItem.getSnippet(); + TextView snippetTextView = ((TextView) view.findViewById(R.id.infowindow_description)); + if (!TextUtils.isEmpty(snippet)) { + snippetTextView.setText(snippet); + snippetTextView.setVisibility(View.VISIBLE); + } else { + snippetTextView.setVisibility(View.GONE); } + } - /** - * Will result in getting this {@link InfoWindow} and updating the view being displayed. - */ - public void update() { - MapboxMap mapboxMap = mMapboxMap.get(); - Marker marker = mBoundMarker.get(); - View view = mView.get(); - if (mapboxMap != null && marker != null && view != null) { - mCoordinates = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); - - if (view instanceof InfoWindowView) { - view.setX(mCoordinates.x + mViewWidthOffset - mMarkerWidthOffset); - } else { - view.setX(mCoordinates.x - (view.getMeasuredWidth() / 2) - mMarkerWidthOffset); - } - view.setY(mCoordinates.y + mMarkerHeightOffset); - } - } + InfoWindow setBoundMarker(Marker boundMarker) { + this.boundMarker = new WeakReference<>(boundMarker); + return this; + } - /** - * Retrieve this {@link InfoWindow}'s current view being used. - * - * @return This {@link InfoWindow}'s current View. - */ - public View getView() { - return mView != null ? mView.get() : null; + Marker getBoundMarker() { + if (boundMarker == null) { + return null; } - - boolean isVisible() { - return mIsVisible; + return boundMarker.get(); + } + + /** + * Will result in getting this {@link InfoWindow} and updating the view being displayed. + */ + public void update() { + MapboxMap mapboxMap = this.mapboxMap.get(); + Marker marker = boundMarker.get(); + View view = this.view.get(); + if (mapboxMap != null && marker != null && view != null) { + coordinates = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); + + if (view instanceof InfoWindowView) { + view.setX(coordinates.x + viewWidthOffset - markerWidthOffset); + } else { + view.setX(coordinates.x - (view.getMeasuredWidth() / 2) - markerWidthOffset); + } + view.setY(coordinates.y + markerHeightOffset); } + } + + /** + * Retrieve this {@link InfoWindow}'s current view being used. + * + * @return This {@link InfoWindow}'s current View. + */ + public View getView() { + return view != null ? view.get() : null; + } + + boolean isVisible() { + return isVisible; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowTipView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowTipView.java index 41c7fc9e97..abcebfec83 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowTipView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowTipView.java @@ -12,51 +12,51 @@ import com.mapbox.mapboxsdk.R; final class InfoWindowTipView extends View { - private Paint mPaint; - private Path mPath; - private int mLineWidth; - - public InfoWindowTipView(Context context, AttributeSet attrs) { - super(context, attrs); - - mPath = new Path(); - mLineWidth = (int) context.getResources().getDimension(R.dimen.mapbox_infowindow_line_width); - mPaint = new Paint(); - mPaint.setColor(Color.WHITE); - mPaint.setAntiAlias(true); - mPaint.setStrokeWidth(0.0f); - mPaint.setStyle(Paint.Style.FILL); - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - int height = getMeasuredHeight(); - int width = getMeasuredWidth(); - - mPath.rewind(); - - this.mPaint.setColor(Color.WHITE); - this.mPaint.setAntiAlias(true); - this.mPaint.setStrokeWidth(0.0f); - this.mPaint.setStyle(Paint.Style.FILL); - - mPath.moveTo(0, 0); - mPath.lineTo(width, 0); - mPath.lineTo((width / 2), height); - mPath.lineTo(0, 0); - canvas.drawPath(mPath, this.mPaint); - - mPath.rewind(); - - this.mPaint.setColor(Color.parseColor("#C2C2C2")); - this.mPaint.setAntiAlias(true); - this.mPaint.setStrokeWidth(mLineWidth); - this.mPaint.setStyle(Paint.Style.STROKE); - - mPath.moveTo(0, 0); - mPath.lineTo(width / 2, height); - mPath.lineTo(width, 0); - canvas.drawPath(mPath, this.mPaint); - } + private Paint mPaint; + private Path mPath; + private int mLineWidth; + + public InfoWindowTipView(Context context, AttributeSet attrs) { + super(context, attrs); + + mPath = new Path(); + mLineWidth = (int) context.getResources().getDimension(R.dimen.mapbox_infowindow_line_width); + mPaint = new Paint(); + mPaint.setColor(Color.WHITE); + mPaint.setAntiAlias(true); + mPaint.setStrokeWidth(0.0f); + mPaint.setStyle(Paint.Style.FILL); + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + int height = getMeasuredHeight(); + int width = getMeasuredWidth(); + + mPath.rewind(); + + this.mPaint.setColor(Color.WHITE); + this.mPaint.setAntiAlias(true); + this.mPaint.setStrokeWidth(0.0f); + this.mPaint.setStyle(Paint.Style.FILL); + + mPath.moveTo(0, 0); + mPath.lineTo(width, 0); + mPath.lineTo((width / 2), height); + mPath.lineTo(0, 0); + canvas.drawPath(mPath, this.mPaint); + + mPath.rewind(); + + this.mPaint.setColor(Color.parseColor("#C2C2C2")); + this.mPaint.setAntiAlias(true); + this.mPaint.setStrokeWidth(mLineWidth); + this.mPaint.setStyle(Paint.Style.STROKE); + + mPath.moveTo(0, 0); + mPath.lineTo(width / 2, height); + mPath.lineTo(width, 0); + canvas.drawPath(mPath, this.mPaint); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowView.java index 7595073aa2..d1a59aae4e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/InfoWindowView.java @@ -9,30 +9,30 @@ import com.mapbox.mapboxsdk.R; class InfoWindowView extends RelativeLayout { - private InfoWindowTipView mTipView; - - public InfoWindowView(Context context) { - this(context, null); - } - - public InfoWindowView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public InfoWindowView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - initialize(context); - } - - private void initialize(Context context) { - LayoutInflater.from(context).inflate(R.layout.mapbox_infowindow_content, this); - mTipView = (InfoWindowTipView) findViewById(R.id.infowindow_tipview); - } - - void setTipViewMarginLeft(int marginLeft) { - RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mTipView.getLayoutParams(); - layoutParams.leftMargin = marginLeft; - // This is a bit of a hack but prevents an occasional gap between the InfoWindow - layoutParams.topMargin = (int) getResources().getDimension(R.dimen.mapbox_infowindow_offset); - } + private InfoWindowTipView mTipView; + + public InfoWindowView(Context context) { + this(context, null); + } + + public InfoWindowView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public InfoWindowView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initialize(context); + } + + private void initialize(Context context) { + LayoutInflater.from(context).inflate(R.layout.mapbox_infowindow_content, this); + mTipView = (InfoWindowTipView) findViewById(R.id.infowindow_tipview); + } + + void setTipViewMarginLeft(int marginLeft) { + RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mTipView.getLayoutParams(); + layoutParams.leftMargin = marginLeft; + // This is a bit of a hack but prevents an occasional gap between the InfoWindow + layoutParams.topMargin = (int) getResources().getDimension(R.dimen.mapbox_infowindow_offset); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java index c4d1090194..edf118205b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Marker.java @@ -27,249 +27,249 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; */ public class Marker extends Annotation { - private LatLng position; - private String snippet; - private Icon icon; - private String title; + private LatLng position; + private String snippet; + private Icon icon; + private String title; - private InfoWindow infoWindow; - private boolean infoWindowShown; + private InfoWindow infoWindow; + private boolean infoWindowShown; - private int topOffsetPixels; - private int rightOffsetPixels; + private int topOffsetPixels; + private int rightOffsetPixels; - /** - * Constructor - */ - Marker() { - super(); - } + /** + * Constructor + */ + Marker() { + super(); + } - /** - * Creates a instance of {@link Marker} using the builder of Marker. - * - * @param baseMarkerOptions The builder used to construct the Marker. - */ - public Marker(BaseMarkerOptions baseMarkerOptions) { - position = baseMarkerOptions.position; - snippet = baseMarkerOptions.snippet; - icon = baseMarkerOptions.icon; - title = baseMarkerOptions.title; - } + /** + * Creates a instance of {@link Marker} using the builder of Marker. + * + * @param baseMarkerOptions The builder used to construct the Marker. + */ + public Marker(BaseMarkerOptions baseMarkerOptions) { + position = baseMarkerOptions.position; + snippet = baseMarkerOptions.snippet; + icon = baseMarkerOptions.icon; + title = baseMarkerOptions.title; + } - Marker(BaseMarkerViewOptions baseMarkerViewOptions) { - position = baseMarkerViewOptions.position; - snippet = baseMarkerViewOptions.snippet; - icon = baseMarkerViewOptions.icon; - title = baseMarkerViewOptions.title; - } + Marker(BaseMarkerViewOptions baseMarkerViewOptions) { + position = baseMarkerViewOptions.position; + snippet = baseMarkerViewOptions.snippet; + icon = baseMarkerViewOptions.icon; + title = baseMarkerViewOptions.title; + } - Marker(LatLng position, Icon icon, String title, String snippet) { - this.position = position; - this.icon = icon; - this.title = title; - this.snippet = snippet; - } + Marker(LatLng position, Icon icon, String title, String snippet) { + this.position = position; + this.icon = icon; + this.title = title; + this.snippet = snippet; + } - /** - * Returns the position of the marker. - * - * @return A {@link LatLng} object specifying the marker's current position. - */ - public LatLng getPosition() { - return position; - } + /** + * Returns the position of the marker. + * + * @return A {@link LatLng} object specifying the marker's current position. + */ + public LatLng getPosition() { + return position; + } - /** - * Gets the snippet of the marker. - * - * @return A string containing the marker's snippet. - */ - public String getSnippet() { - return snippet; - } + /** + * Gets the snippet of the marker. + * + * @return A string containing the marker's snippet. + */ + public String getSnippet() { + return snippet; + } - /** - * Gets the snippet of the marker. - * - * @return A string containing the marker's snippet. - */ - public String getTitle() { - return title; - } + /** + * Gets the snippet of the marker. + * + * @return A string containing the marker's snippet. + */ + public String getTitle() { + return title; + } - /** - * Do not use this method, used internally by the SDK. - */ - public void hideInfoWindow() { - if (infoWindow != null) { - infoWindow.close(); - } - infoWindowShown = false; + /** + * Do not use this method, used internally by the SDK. + */ + public void hideInfoWindow() { + if (infoWindow != null) { + infoWindow.close(); } + infoWindowShown = false; + } - /** - * Do not use this method, used internally by the SDK. - * - * @return true if the infoWindow is shown - */ - public boolean isInfoWindowShown() { - return infoWindowShown; - } + /** + * Do not use this method, used internally by the SDK. + * + * @return true if the infoWindow is shown + */ + public boolean isInfoWindowShown() { + return infoWindowShown; + } - /** - * Sets the location of the marker. - * - * @param position A {@link LatLng} defining the marker position. - */ - public void setPosition(LatLng position) { - this.position = position; - MapboxMap map = getMapboxMap(); - if (map != null) { - map.updateMarker(this); - } + /** + * Sets the location of the marker. + * + * @param position A {@link LatLng} defining the marker position. + */ + public void setPosition(LatLng position) { + this.position = position; + MapboxMap map = getMapboxMap(); + if (map != null) { + map.updateMarker(this); } + } - /** - * Sets the snippet of the marker. - * - * @param snippet A String used in the marker info window. If {@code null}, the snippet is - * cleared. - */ - public void setSnippet(String snippet) { - this.snippet = snippet; - refreshInfoWindowContent(); - } + /** + * Sets the snippet of the marker. + * + * @param snippet A String used in the marker info window. If {@code null}, the snippet is + * cleared. + */ + public void setSnippet(String snippet) { + this.snippet = snippet; + refreshInfoWindowContent(); + } - /** - * Sets the icon of the marker. - * - * @param icon The {@link Icon} to be used as Marker image - */ - public void setIcon(@Nullable Icon icon) { - this.icon = icon; - MapboxMap map = getMapboxMap(); - if (map != null) { - map.updateMarker(this); - } + /** + * Sets the icon of the marker. + * + * @param icon The {@link Icon} to be used as Marker image + */ + public void setIcon(@Nullable Icon icon) { + this.icon = icon; + MapboxMap map = getMapboxMap(); + if (map != null) { + map.updateMarker(this); } + } - /** - * Gets the {@link Icon} currently used for the marker. If no Icon was set for the marker, the - * default icon will be returned. - * - * @return The {@link Icon} the marker is using. - */ - public Icon getIcon() { - return icon; - } + /** + * Gets the {@link Icon} currently used for the marker. If no Icon was set for the marker, the + * default icon will be returned. + * + * @return The {@link Icon} the marker is using. + */ + public Icon getIcon() { + return icon; + } - /** - * Sets the title of the marker. - * - * @param title A String used in the marker info window. If {@code null}, the title is - * cleared. - */ - public void setTitle(String title) { - this.title = title; - refreshInfoWindowContent(); - } + /** + * Sets the title of the marker. + * + * @param title A String used in the marker info window. If {@code null}, the title is + * cleared. + */ + public void setTitle(String title) { + this.title = title; + refreshInfoWindowContent(); + } - /** - * Gets the {@link InfoWindow} the marker is using. If the marker hasn't had an info window - * defined, this will return {@code null}. - * - * @return - */ - @Nullable - public InfoWindow getInfoWindow() { - return infoWindow; - } + /** + * Gets the {@link InfoWindow} the marker is using. If the marker hasn't had an info window + * defined, this will return {@code null}. + * + * @return The info window the marker is using. + */ + @Nullable + public InfoWindow getInfoWindow() { + return infoWindow; + } - /** - * Update only for default Marker's InfoWindow content for Title and Snippet - */ - private void refreshInfoWindowContent() { - if (isInfoWindowShown() && mapView != null && mapboxMap != null && mapboxMap.getInfoWindowAdapter() == null) { - InfoWindow infoWindow = getInfoWindow(mapView); - if (mapView.getContext() != null) { - infoWindow.adaptDefaultMarker(this, mapboxMap, mapView); - } - MapboxMap map = getMapboxMap(); - if (map != null) { - map.updateMarker(this); - } - infoWindow.update(); - } + /** + * Update only for default Marker's InfoWindow content for Title and Snippet + */ + private void refreshInfoWindowContent() { + if (isInfoWindowShown() && mapView != null && mapboxMap != null && mapboxMap.getInfoWindowAdapter() == null) { + InfoWindow infoWindow = getInfoWindow(mapView); + if (mapView.getContext() != null) { + infoWindow.adaptDefaultMarker(this, mapboxMap, mapView); + } + MapboxMap map = getMapboxMap(); + if (map != null) { + map.updateMarker(this); + } + infoWindow.update(); } + } - /** - * Do not use this method, used internally by the SDK. Use {@link MapboxMap#selectMarker(Marker)} - * if you want to programmatically display the markers info window. - * - * @param mapboxMap The hosting mapbox map. - * @param mapView The hosting map view. - * @return The info window that was shown. - */ - public InfoWindow showInfoWindow(@NonNull MapboxMap mapboxMap, @NonNull MapView mapView) { - setMapboxMap(mapboxMap); - setMapView(mapView); - MapboxMap.InfoWindowAdapter infoWindowAdapter = getMapboxMap().getInfoWindowAdapter(); - if (infoWindowAdapter != null) { - // end developer is using a custom InfoWindowAdapter - View content = infoWindowAdapter.getInfoWindow(this); - if (content != null) { - infoWindow = new InfoWindow(content, mapboxMap); - showInfoWindow(infoWindow, mapView); - return infoWindow; - } - } - - InfoWindow infoWindow = getInfoWindow(mapView); - if (mapView.getContext() != null) { - infoWindow.adaptDefaultMarker(this, mapboxMap, mapView); - } - return showInfoWindow(infoWindow, mapView); + /** + * Do not use this method, used internally by the SDK. Use {@link MapboxMap#selectMarker(Marker)} + * if you want to programmatically display the markers info window. + * + * @param mapboxMap The hosting mapbox map. + * @param mapView The hosting map view. + * @return The info window that was shown. + */ + public InfoWindow showInfoWindow(@NonNull MapboxMap mapboxMap, @NonNull MapView mapView) { + setMapboxMap(mapboxMap); + setMapView(mapView); + MapboxMap.InfoWindowAdapter infoWindowAdapter = getMapboxMap().getInfoWindowAdapter(); + if (infoWindowAdapter != null) { + // end developer is using a custom InfoWindowAdapter + View content = infoWindowAdapter.getInfoWindow(this); + if (content != null) { + infoWindow = new InfoWindow(content, mapboxMap); + showInfoWindow(infoWindow, mapView); + return infoWindow; + } } - private InfoWindow showInfoWindow(InfoWindow iw, MapView mapView) { - iw.open(mapView, this, getPosition(), rightOffsetPixels, topOffsetPixels); - infoWindowShown = true; - return iw; + InfoWindow infoWindow = getInfoWindow(mapView); + if (mapView.getContext() != null) { + infoWindow.adaptDefaultMarker(this, mapboxMap, mapView); } + return showInfoWindow(infoWindow, mapView); + } - private InfoWindow getInfoWindow(@NonNull MapView mapView) { - if (infoWindow == null && mapView.getContext() != null) { - infoWindow = new InfoWindow(mapView, R.layout.mapbox_infowindow_view, getMapboxMap()); - } - return infoWindow; - } + private InfoWindow showInfoWindow(InfoWindow iw, MapView mapView) { + iw.open(mapView, this, getPosition(), rightOffsetPixels, topOffsetPixels); + infoWindowShown = true; + return iw; + } - /** - * Do not use this method, used internally by the SDK. - * - * @param topOffsetPixels the top offset pixels. - */ - public void setTopOffsetPixels(int topOffsetPixels) { - this.topOffsetPixels = topOffsetPixels; + private InfoWindow getInfoWindow(@NonNull MapView mapView) { + if (infoWindow == null && mapView.getContext() != null) { + infoWindow = new InfoWindow(mapView, R.layout.mapbox_infowindow_view, getMapboxMap()); } + return infoWindow; + } - /** - * Do not use this method, used internally by the SDK. - * - * @param rightOffsetPixels the right offset pixels. - */ - public void setRightOffsetPixels(int rightOffsetPixels) { - this.rightOffsetPixels = rightOffsetPixels; - } + /** + * Do not use this method, used internally by the SDK. + * + * @param topOffsetPixels the top offset pixels. + */ + public void setTopOffsetPixels(int topOffsetPixels) { + this.topOffsetPixels = topOffsetPixels; + } - /** - * Returns a String with the marker position. - * - * @return A String with the marker position. - */ - @Override - public String toString() { - return "Marker [position[" + getPosition() + "]]"; - } + /** + * Do not use this method, used internally by the SDK. + * + * @param rightOffsetPixels the right offset pixels. + */ + public void setRightOffsetPixels(int rightOffsetPixels) { + this.rightOffsetPixels = rightOffsetPixels; + } + + /** + * Returns a String with the marker position. + * + * @return A String with the marker position. + */ + @Override + public String toString() { + return "Marker [position[" + getPosition() + "]]"; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java index 282da6407e..49d4867801 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerOptions.java @@ -21,161 +21,168 @@ import com.mapbox.mapboxsdk.geometry.LatLng; */ public final class MarkerOptions extends BaseMarkerOptions implements Parcelable { - /** - * Defines options for a Marker. - */ - public MarkerOptions() { + /** + * Defines options for a Marker. + */ + public MarkerOptions() { + } + + protected MarkerOptions(Parcel in) { + position((LatLng) in.readParcelable(LatLng.class.getClassLoader())); + snippet(in.readString()); + title(in.readString()); + if (in.readByte() != 0) { + // this means we have an icon + String iconId = in.readString(); + Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader()); + Icon icon = new Icon(iconId, iconBitmap); + icon(icon); } - - protected MarkerOptions(Parcel in) { - position((LatLng) in.readParcelable(LatLng.class.getClassLoader())); - snippet(in.readString()); - title(in.readString()); - if (in.readByte() != 0) { - // this means we have an icon - String iconId = in.readString(); - Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader()); - Icon icon = new Icon(iconId, iconBitmap); - icon(icon); - } + } + + @Override + public MarkerOptions getThis() { + return this; + } + + /** + * Describe the kinds of special objects contained in this Parcelable's + * marshalled representation. + * + * @return integer 0. + */ + @Override + public int describeContents() { + return 0; + } + + /** + * Flatten this object in to a Parcel. + * + * @param out The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written. May be 0 or + * {@link #PARCELABLE_WRITE_RETURN_VALUE}. + */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeParcelable(getPosition(), flags); + out.writeString(getSnippet()); + out.writeString(getTitle()); + Icon icon = getIcon(); + out.writeByte((byte) (icon != null ? 1 : 0)); + if (icon != null) { + out.writeString(getIcon().getId()); + out.writeParcelable(getIcon().getBitmap(), flags); } - - @Override - public MarkerOptions getThis() { - return this; + } + + /** + * Do not use this method. Used internally by the SDK. + * + * @return Marker The build marker + */ + public Marker getMarker() { + if (position == null) { + throw new InvalidMarkerPositionException(); } - /** - * Describe the kinds of special objects contained in this Parcelable's - * marshalled representation. - * - * @return integer 0. - */ - @Override - public int describeContents() { - return 0; - } + return new Marker(position, icon, title, snippet); + } + + /** + * Returns the position set for this {@link MarkerOptions} object. + * + * @return A {@link LatLng} object specifying the marker's current position. + */ + public LatLng getPosition() { + return position; + } + + /** + * Gets the snippet set for this {@link MarkerOptions} object. + * + * @return A string containing the marker's snippet. + */ + public String getSnippet() { + return snippet; + } + + /** + * Gets the title set for this {@link MarkerOptions} object. + * + * @return A string containing the marker's title. + */ + public String getTitle() { + return title; + } + + /** + * Gets the custom icon set for this {@link MarkerOptions} object. + * + * @return A {@link Icon} object that the marker is using. If the icon wasn't set, default icon + * will return. + */ + public Icon getIcon() { + return icon; + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public MarkerOptions createFromParcel(Parcel in) { + return new MarkerOptions(in); + } + + public MarkerOptions[] newArray(int size) { + return new MarkerOptions[size]; + } + }; - /** - * Flatten this object in to a Parcel. - * - * @param out The Parcel in which the object should be written. - * @param flags Additional flags about how the object should be written. May be 0 or - * {@link #PARCELABLE_WRITE_RETURN_VALUE}. - */ - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeParcelable(getPosition(), flags); - out.writeString(getSnippet()); - out.writeString(getTitle()); - Icon icon = getIcon(); - out.writeByte((byte) (icon != null ? 1 : 0)); - if (icon != null) { - out.writeString(getIcon().getId()); - out.writeParcelable(getIcon().getBitmap(), flags); - } + /** + * Compares this {@link MarkerOptions} object with another {@link MarkerOptions} and + * determines if their properties match. + * + * @param o Another {@link MarkerOptions} to compare with this object. + * @return True if marker properties match this {@link MarkerOptions} object. + * Else, false. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - - /** - * Do not use this method. Used internally by the SDK. - * - * @return Marker The build marker - */ - public Marker getMarker() { - if (position == null) { - throw new InvalidMarkerPositionException(); - } - - return new Marker(position, icon, title, snippet); + if (o == null || getClass() != o.getClass()) { + return false; } - /** - * Returns the position set for this {@link MarkerOptions} object. - * - * @return A {@link LatLng} object specifying the marker's current position. - */ - public LatLng getPosition() { - return position; - } + MarkerOptions marker = (MarkerOptions) o; - /** - * Gets the snippet set for this {@link MarkerOptions} object. - * - * @return A string containing the marker's snippet. - */ - public String getSnippet() { - return snippet; + if (getPosition() != null ? !getPosition().equals(marker.getPosition()) : marker.getPosition() != null) { + return false; } - - /** - * Gets the title set for this {@link MarkerOptions} object. - * - * @return A string containing the marker's title. - */ - public String getTitle() { - return title; + if (getSnippet() != null ? !getSnippet().equals(marker.getSnippet()) : marker.getSnippet() != null) { + return false; } - - /** - * Gets the custom icon set for this {@link MarkerOptions} object. - * - * @return A {@link Icon} object that the marker is using. If the icon wasn't set, default icon - * will return. - */ - public Icon getIcon() { - return icon; - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public MarkerOptions createFromParcel(Parcel in) { - return new MarkerOptions(in); - } - - public MarkerOptions[] newArray(int size) { - return new MarkerOptions[size]; - } - }; - - /** - * Compares this {@link MarkerOptions} object with another {@link MarkerOptions} and - * determines if their properties match. - * - * @param o Another {@link MarkerOptions} to compare with this object. - * @return True if marker properties match this {@link MarkerOptions} object. - * Else, false. - */ - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - MarkerOptions marker = (MarkerOptions) o; - - if (getPosition() != null ? !getPosition().equals(marker.getPosition()) : marker.getPosition() != null) - return false; - if (getSnippet() != null ? !getSnippet().equals(marker.getSnippet()) : marker.getSnippet() != null) - return false; - if (getIcon() != null ? !getIcon().equals(marker.getIcon()) : marker.getIcon() != null) - return false; - return !(getTitle() != null ? !getTitle().equals(marker.getTitle()) : marker.getTitle() != null); - } - - /** - * Gives an integer which can be used as the bucket number for storing elements of the set/map. - * This bucket number is the address of the element inside the set/map. There's no guarantee - * that this hash value will be consistent between different Java implementations, or even - * between different execution runs of the same program. - * - * @return integer value you can use for storing element. - */ - @Override - public int hashCode() { - int result = 1; - result = 31 * result + (getPosition() != null ? getPosition().hashCode() : 0); - result = 31 * result + (getSnippet() != null ? getSnippet().hashCode() : 0); - result = 31 * result + (getIcon() != null ? getIcon().hashCode() : 0); - result = 31 * result + (getTitle() != null ? getTitle().hashCode() : 0); - return result; + if (getIcon() != null ? !getIcon().equals(marker.getIcon()) : marker.getIcon() != null) { + return false; } + return !(getTitle() != null ? !getTitle().equals(marker.getTitle()) : marker.getTitle() != null); + } + + /** + * Gives an integer which can be used as the bucket number for storing elements of the set/map. + * This bucket number is the address of the element inside the set/map. There's no guarantee + * that this hash value will be consistent between different Java implementations, or even + * between different execution runs of the same program. + * + * @return integer value you can use for storing element. + */ + @Override + public int hashCode() { + int result = 1; + result = 31 * result + (getPosition() != null ? getPosition().hashCode() : 0); + result = 31 * result + (getSnippet() != null ? getSnippet().hashCode() : 0); + result = 31 * result + (getIcon() != null ? getIcon().hashCode() : 0); + result = 31 * result + (getTitle() != null ? getTitle().hashCode() : 0); + return result; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java index a32186b52e..c1b643eb4c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerView.java @@ -26,382 +26,384 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; */ public class MarkerView extends Marker { - private MarkerViewManager markerViewManager; - - private float width; - private float height; - - private float anchorU; - private float anchorV; - - private float offsetX = MapboxConstants.UNMEASURED; - private float offsetY = MapboxConstants.UNMEASURED; - - private float infoWindowAnchorU; - private float infoWindowAnchorV; - - private boolean flat; - private boolean visible = true; - - private float tiltValue; - private float rotation; - private float alpha = 1; - - private Icon markerViewIcon; - - private boolean selected; - - - /** - * Publicly hidden default constructor - */ - MarkerView() { - } - - /** - * Creates a instance of MarkerView using the builder of MarkerView - * - * @param baseMarkerViewOptions the builder used to construct the MarkerView - */ - public MarkerView(BaseMarkerViewOptions baseMarkerViewOptions) { - super(baseMarkerViewOptions); - this.alpha = baseMarkerViewOptions.getAlpha(); - this.anchorU = baseMarkerViewOptions.getAnchorU(); - this.anchorV = baseMarkerViewOptions.getAnchorV(); - this.infoWindowAnchorU = baseMarkerViewOptions.getInfoWindowAnchorU(); - this.infoWindowAnchorV = baseMarkerViewOptions.getInfoWindowAnchorV(); - this.flat = baseMarkerViewOptions.isFlat(); - this.rotation = baseMarkerViewOptions.getRotation(); - this.selected = baseMarkerViewOptions.selected; - } - - float getWidth() { - return width; - } - - void setWidth(float width) { - this.width = width; - } - - float getHeight() { - return height; - } - - void setHeight(float height) { - this.height = height; - } - - /** - * Specifies the anchor being set on a particular point of the MarkerView. - *

- * The anchor point is specified in the continuous space [0.0, 1.0] x [0.0, 1.0], where (0, 0) - * is the top-left corner of the image, and (1, 1) is the bottom-right corner. - *

- * - * @param u u-coordinate of the anchor, as a ratio of the image width (in the range [0, 1]). - * @param v v-coordinate of the anchor, as a ratio of the image height (in the range [0, 1]). - */ - public void setAnchor(@FloatRange(from = 0.0, to = 1.0) float u, @FloatRange(from = 0.0, to = 1.0) float v) { - this.anchorU = u; - this.anchorV = v; - setOffset(-1, -1); - } - - /** - * Get the horizontal distance, normalized to [0, 1], of the anchor from the left edge. - * - * @return The u-value of the anchor. - */ - public float getAnchorU() { - return anchorU; - } - - /** - * Get the vertical distance, normalized to [0, 1], of the anchor from the top edge. - * - * @return the v-value of the anchor. - */ - public float getAnchorV() { - return anchorV; - } - - /** - * Internal method to set the calculated offset. - *

- * These are calculated based on the View bounds and the provided anchor. - *

- * - * @param x the x-value of the offset. - * @param y the y-value of the offset. - */ - void setOffset(float x, float y) { - offsetX = x; - offsetY = y; - } - - /** - * Internal method to get the horizontal calculated offset. - * - * @return the calculated horizontal offset. - */ - float getOffsetX() { - return offsetX; - } - - /** - * Internal method to get the vertical calculated offset. - * - * @return the calculated vertical offset. - */ - float getOffsetY() { - return offsetY; - } - - /** - * Specifies the anchor point of the info window on the View of the MarkerView. - *

- * The anchor point is specified in the continuous space [0.0, 1.0] x [0.0, 1.0], where (0, 0) - * is the top-left corner of the image, and (1, 1) is the bottom-right corner. - *

- *

- * The default is the top middle of the View. - *

- * - * @param u u-coordinate of the info window anchor, as a ratio of the image width (in the range [0, 1]). - * @param v v-coordinate of the info window anchor, as a ratio of the image height (in the range [0, 1]). - * @see #setAnchor(float, float) for more details. - */ - public void setInfoWindowAnchor(@FloatRange(from = 0.0, to = 1.0) float u, @FloatRange(from = 0.0, to = 1.0) float v) { - this.infoWindowAnchorU = u; - this.infoWindowAnchorV = v; - } - - /** - * Get the horizontal distance, normalized to [0, 1], of the info window anchor from the left edge. - * - * @return the u value of the InfoWindow anchor. - */ - public float getInfoWindowAnchorU() { - return infoWindowAnchorU; - } - - /** - * Get the vertical distance, normalized to [0, 1], of the info window anchor from the top edge. - * - * @return the v value of the InfoWindow anchor. - */ - public float getInfoWindowAnchorV() { - return infoWindowAnchorV; - } - - /** - * Get the flat state of a MarkerView. - * - * @return true if the MarkerView is flat; false if the MarkerView is billboard. - */ - public boolean isFlat() { - return flat; - } - - /** - * Sets whether this MarkerView should be flat against the map (true) or a billboard facing the - * camera (false). - * - * @param flat the flat state of the MarkerView. - */ - public void setFlat(boolean flat) { - this.flat = flat; - } - - /** - * Internal method to get the current tilted value of a MarkerView. - * - * @return the tilted value. - */ - float getTilt() { - return tiltValue; - } - - /** - * Internal method to set the current titled value of a MarkerView. - * - * @param tiltValue the tilted value to set. - */ - void setTilt(@FloatRange(from = 0.0, to = MapboxConstants.MAXIMUM_TILT) float tiltValue) { - this.tiltValue = tiltValue; - } - - /** - * Set the visible state of a MarkerView. - * - * @param visible true will make the MarkerView visible, false will hide the MarkerView. - */ - public void setVisible(boolean visible) { - this.visible = visible; - if (markerViewManager != null) { - markerViewManager.animateVisible(this, visible); - } - } - - /** - * Returns the visible state of the MarkerView. - * - * @return the visible state. - */ - public boolean isVisible() { - return visible; - } - - /** - * Set the rotation value of the MarkerView in degrees. - *

- * Input will be limited to 0 - 360 degrees. - *

- *

- * This will result in animating the rotation of the MarkerView using an rotation animator - * from current value to the provided parameter value. - *

- * - * @param rotation the rotation value to animate to. - */ - public void setRotation(float rotation) { - // limit to 0 - 360 degrees - float newRotation = rotation; - while (newRotation > 360) { - newRotation -= 360; - } - while (newRotation < 0) { - newRotation += 360; - } - - this.rotation = newRotation; - if (markerViewManager != null) { - markerViewManager.animateRotationBy(this, newRotation); - } - } - - /** - * Get the rotation value of the MarkerView. - * - * @return the rotation value. - */ - public float getRotation() { - return rotation; - } - - /** - * Get the alpha value of the MarkerView. - * - * @return the alpha value. - */ - public float getAlpha() { - return alpha; - } - - /** - * Set the alpha value of the MarkerView. - *

- * This will result in animating the alpha of the MarkerView using an alpha animator - * from current value to the provided parameter value. - *

- * - * @param alpha the alpha value to animate to. - */ - public void setAlpha(@FloatRange(from = 0.0, to = 255.0) float alpha) { - this.alpha = alpha; - if (markerViewManager != null) { - markerViewManager.animateAlpha(this, alpha); - } - } - - /** - * Set the icon of the MarkerView. - * - * @param icon the {@link Icon} to be used as Marker image. - */ - @Override - public void setIcon(@Nullable Icon icon) { - if (icon != null) { - markerViewIcon = IconFactory.recreate(IconFactory.ICON_MARKERVIEW_ID, icon.getBitmap()); - } - Icon transparentIcon = IconFactory.recreate(IconFactory.ICON_MARKERVIEW_ID, - IconFactory.ICON_MARKERVIEW_BITMAP); - if (markerViewManager != null) { - markerViewManager.updateIcon(this); - } - super.setIcon(transparentIcon); - } - - /** - * Sets the location of the marker. - * - * @param position A {@link LatLng} defining the marker position. - */ - @Override - public void setPosition(LatLng position) { - super.setPosition(position); - if (markerViewManager != null) { - markerViewManager.update(); - } - } - - /** - * Determine if the {@link MarkerView} is selected or not. - * - * @return True if the MarkerView's selected, else false. - */ - public boolean isSelected() { - return selected; - } - - /** - * For internal use only, use {@link MapboxMap#selectMarker(Marker)} instead. - */ - void setSelected(boolean selected) { - this.selected = selected; - } - - /** - * Get the icon of the MarkerView. - * - * @return the icon use as Marker image. - */ - @Override - public Icon getIcon() { - return markerViewIcon; - } - - /** - * Set the MapboxMap associated tot the MapView containing the MarkerView. - *

- * This method is used to instantiate the MarkerView and provide an instance of {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter} - *

- *

- * This method is used to notify that a MarkerView is no longer active by setting a null value. - *

- * - * @param mapboxMap the MapboxMap instances. - */ - @Override - public void setMapboxMap(MapboxMap mapboxMap) { - super.setMapboxMap(mapboxMap); - if (mapboxMap != null) { - if (isFlat()) { - // initial tilt value if MapboxMap is started with a tilt attribute - tiltValue = (float) mapboxMap.getCameraPosition().tilt; - } - - markerViewManager = mapboxMap.getMarkerViewManager(); - } - } - - /** - * Get the String representation of a MarkerView. - * - * @return the String representation. - */ - @Override - public String toString() { - return "MarkerView [position[" + getPosition() + "]]"; - } + private MarkerViewManager markerViewManager; + + private float width; + private float height; + + private float anchorU; + private float anchorV; + + private float offsetX = MapboxConstants.UNMEASURED; + private float offsetY = MapboxConstants.UNMEASURED; + + private float infoWindowAnchorU; + private float infoWindowAnchorV; + + private boolean flat; + private boolean visible = true; + + private float tiltValue; + private float rotation; + private float alpha = 1; + + private Icon markerViewIcon; + + private boolean selected; + + + /** + * Publicly hidden default constructor + */ + MarkerView() { + } + + /** + * Creates a instance of MarkerView using the builder of MarkerView + * + * @param baseMarkerViewOptions the builder used to construct the MarkerView + */ + public MarkerView(BaseMarkerViewOptions baseMarkerViewOptions) { + super(baseMarkerViewOptions); + this.alpha = baseMarkerViewOptions.getAlpha(); + this.anchorU = baseMarkerViewOptions.getAnchorU(); + this.anchorV = baseMarkerViewOptions.getAnchorV(); + this.infoWindowAnchorU = baseMarkerViewOptions.getInfoWindowAnchorU(); + this.infoWindowAnchorV = baseMarkerViewOptions.getInfoWindowAnchorV(); + this.flat = baseMarkerViewOptions.isFlat(); + this.rotation = baseMarkerViewOptions.getRotation(); + this.selected = baseMarkerViewOptions.selected; + } + + float getWidth() { + return width; + } + + void setWidth(float width) { + this.width = width; + } + + float getHeight() { + return height; + } + + void setHeight(float height) { + this.height = height; + } + + /** + * Specifies the anchor being set on a particular point of the MarkerView. + *

+ * The anchor point is specified in the continuous space [0.0, 1.0] x [0.0, 1.0], where (0, 0) + * is the top-left corner of the image, and (1, 1) is the bottom-right corner. + *

+ * + * @param u u-coordinate of the anchor, as a ratio of the image width (in the range [0, 1]). + * @param v v-coordinate of the anchor, as a ratio of the image height (in the range [0, 1]). + */ + public void setAnchor(@FloatRange(from = 0.0, to = 1.0) float u, @FloatRange(from = 0.0, to = 1.0) float v) { + this.anchorU = u; + this.anchorV = v; + setOffset(-1, -1); + } + + /** + * Get the horizontal distance, normalized to [0, 1], of the anchor from the left edge. + * + * @return The u-value of the anchor. + */ + public float getAnchorU() { + return anchorU; + } + + /** + * Get the vertical distance, normalized to [0, 1], of the anchor from the top edge. + * + * @return the v-value of the anchor. + */ + public float getAnchorV() { + return anchorV; + } + + /** + * Internal method to set the calculated offset. + *

+ * These are calculated based on the View bounds and the provided anchor. + *

+ * + * @param x the x-value of the offset. + * @param y the y-value of the offset. + */ + void setOffset(float x, float y) { + offsetX = x; + offsetY = y; + } + + /** + * Internal method to get the horizontal calculated offset. + * + * @return the calculated horizontal offset. + */ + float getOffsetX() { + return offsetX; + } + + /** + * Internal method to get the vertical calculated offset. + * + * @return the calculated vertical offset. + */ + float getOffsetY() { + return offsetY; + } + + /** + * Specifies the anchor point of the info window on the View of the MarkerView. + *

+ * The anchor point is specified in the continuous space [0.0, 1.0] x [0.0, 1.0], where (0, 0) + * is the top-left corner of the image, and (1, 1) is the bottom-right corner. + *

+ *

+ * The default is the top middle of the View. + *

+ * + * @param u u-coordinate of the info window anchor, as a ratio of the image width (in the range [0, 1]). + * @param v v-coordinate of the info window anchor, as a ratio of the image height (in the range [0, 1]). + * @see #setAnchor(float, float) for more details. + */ + public void setInfoWindowAnchor(@FloatRange(from = 0.0, to = 1.0) float u, + @FloatRange(from = 0.0, to = 1.0) float v) { + this.infoWindowAnchorU = u; + this.infoWindowAnchorV = v; + } + + /** + * Get the horizontal distance, normalized to [0, 1], of the info window anchor from the left edge. + * + * @return the u value of the InfoWindow anchor. + */ + public float getInfoWindowAnchorU() { + return infoWindowAnchorU; + } + + /** + * Get the vertical distance, normalized to [0, 1], of the info window anchor from the top edge. + * + * @return the v value of the InfoWindow anchor. + */ + public float getInfoWindowAnchorV() { + return infoWindowAnchorV; + } + + /** + * Get the flat state of a MarkerView. + * + * @return true if the MarkerView is flat; false if the MarkerView is billboard. + */ + public boolean isFlat() { + return flat; + } + + /** + * Sets whether this MarkerView should be flat against the map (true) or a billboard facing the + * camera (false). + * + * @param flat the flat state of the MarkerView. + */ + public void setFlat(boolean flat) { + this.flat = flat; + } + + /** + * Internal method to get the current tilted value of a MarkerView. + * + * @return the tilted value. + */ + float getTilt() { + return tiltValue; + } + + /** + * Internal method to set the current titled value of a MarkerView. + * + * @param tiltValue the tilted value to set. + */ + void setTilt(@FloatRange(from = 0.0, to = MapboxConstants.MAXIMUM_TILT) float tiltValue) { + this.tiltValue = tiltValue; + } + + /** + * Set the visible state of a MarkerView. + * + * @param visible true will make the MarkerView visible, false will hide the MarkerView. + */ + public void setVisible(boolean visible) { + this.visible = visible; + if (markerViewManager != null) { + markerViewManager.animateVisible(this, visible); + } + } + + /** + * Returns the visible state of the MarkerView. + * + * @return the visible state. + */ + public boolean isVisible() { + return visible; + } + + /** + * Set the rotation value of the MarkerView in degrees. + *

+ * Input will be limited to 0 - 360 degrees. + *

+ *

+ * This will result in animating the rotation of the MarkerView using an rotation animator + * from current value to the provided parameter value. + *

+ * + * @param rotation the rotation value to animate to. + */ + public void setRotation(float rotation) { + // limit to 0 - 360 degrees + float newRotation = rotation; + while (newRotation > 360) { + newRotation -= 360; + } + while (newRotation < 0) { + newRotation += 360; + } + + this.rotation = newRotation; + if (markerViewManager != null) { + markerViewManager.animateRotationBy(this, newRotation); + } + } + + /** + * Get the rotation value of the MarkerView. + * + * @return the rotation value. + */ + public float getRotation() { + return rotation; + } + + /** + * Get the alpha value of the MarkerView. + * + * @return the alpha value. + */ + public float getAlpha() { + return alpha; + } + + /** + * Set the alpha value of the MarkerView. + *

+ * This will result in animating the alpha of the MarkerView using an alpha animator + * from current value to the provided parameter value. + *

+ * + * @param alpha the alpha value to animate to. + */ + public void setAlpha(@FloatRange(from = 0.0, to = 255.0) float alpha) { + this.alpha = alpha; + if (markerViewManager != null) { + markerViewManager.animateAlpha(this, alpha); + } + } + + /** + * Set the icon of the MarkerView. + * + * @param icon the {@link Icon} to be used as Marker image. + */ + @Override + public void setIcon(@Nullable Icon icon) { + if (icon != null) { + markerViewIcon = IconFactory.recreate(IconFactory.ICON_MARKERVIEW_ID, icon.getBitmap()); + } + Icon transparentIcon = IconFactory.recreate(IconFactory.ICON_MARKERVIEW_ID, + IconFactory.ICON_MARKERVIEW_BITMAP); + if (markerViewManager != null) { + markerViewManager.updateIcon(this); + } + super.setIcon(transparentIcon); + } + + /** + * Sets the location of the marker. + * + * @param position A {@link LatLng} defining the marker position. + */ + @Override + public void setPosition(LatLng position) { + super.setPosition(position); + if (markerViewManager != null) { + markerViewManager.update(); + } + } + + /** + * Determine if the {@link MarkerView} is selected or not. + * + * @return True if the MarkerView's selected, else false. + */ + public boolean isSelected() { + return selected; + } + + /** + * For internal use only, use {@link MapboxMap#selectMarker(Marker)} instead. + */ + void setSelected(boolean selected) { + this.selected = selected; + } + + /** + * Get the icon of the MarkerView. + * + * @return the icon use as Marker image. + */ + @Override + public Icon getIcon() { + return markerViewIcon; + } + + /** + * Set the MapboxMap associated tot the MapView containing the MarkerView. + *

+ * This method is used to instantiate the MarkerView and provide an instance of + * {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter} + *

+ *

+ * This method is used to notify that a MarkerView is no longer active by setting a null value. + *

+ * + * @param mapboxMap the MapboxMap instances. + */ + @Override + public void setMapboxMap(MapboxMap mapboxMap) { + super.setMapboxMap(mapboxMap); + if (mapboxMap != null) { + if (isFlat()) { + // initial tilt value if MapboxMap is started with a tilt attribute + tiltValue = (float) mapboxMap.getCameraPosition().tilt; + } + + markerViewManager = mapboxMap.getMarkerViewManager(); + } + } + + /** + * Get the String representation of a MarkerView. + * + * @return the String representation. + */ + @Override + public String toString() { + return "MarkerView [position[" + getPosition() + "]]"; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java index 8989bb22d7..d953bfca0c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewManager.java @@ -32,609 +32,610 @@ import java.util.Map; */ public class MarkerViewManager implements MapView.OnMapChangedListener { - private final ViewGroup markerViewContainer; - private final Map markerViewMap = new HashMap<>(); - private final LongSparseArray markerViewAddedListenerMap = new LongSparseArray<>(); - private final List markerViewAdapters = new ArrayList<>(); - - // TODO refactor MapboxMap out for Projection and Transform - // Requires removing MapboxMap from Annotations by using Peer model from #6912 - private MapboxMap mapboxMap; - - private long viewMarkerBoundsUpdateTime; - private MapboxMap.OnMarkerViewClickListener onMarkerViewClickListener; - private boolean isWaitingForRenderInvoke; - - /** - * Creates an instance of MarkerViewManager. - * - * @param container the ViewGroup associated with the MarkerViewManager - */ - public MarkerViewManager(@NonNull ViewGroup container) { - this.markerViewContainer = container; - this.markerViewAdapters.add(new ImageMarkerViewAdapter(container.getContext())); + private final ViewGroup markerViewContainer; + private final Map markerViewMap = new HashMap<>(); + private final LongSparseArray markerViewAddedListenerMap = new LongSparseArray<>(); + private final List markerViewAdapters = new ArrayList<>(); + + // TODO refactor MapboxMap out for Projection and Transform + // Requires removing MapboxMap from Annotations by using Peer model from #6912 + private MapboxMap mapboxMap; + + private long viewMarkerBoundsUpdateTime; + private MapboxMap.OnMarkerViewClickListener onMarkerViewClickListener; + private boolean isWaitingForRenderInvoke; + + /** + * Creates an instance of MarkerViewManager. + * + * @param container the ViewGroup associated with the MarkerViewManager + */ + public MarkerViewManager(@NonNull ViewGroup container) { + this.markerViewContainer = container; + this.markerViewAdapters.add(new ImageMarkerViewAdapter(container.getContext())); + } + + // TODO refactor MapboxMap out for Projection and Transform + // Requires removing MapboxMap from Annotations by using Peer model from #6912 + public void bind(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + } + + + @Override + public void onMapChanged(@MapView.MapChange int change) { + if (isWaitingForRenderInvoke && change == MapView.DID_FINISH_RENDERING_FRAME_FULLY_RENDERED) { + isWaitingForRenderInvoke = false; + invalidateViewMarkersInVisibleRegion(); } - - // TODO refactor MapboxMap out for Projection and Transform - // Requires removing MapboxMap from Annotations by using Peer model from #6912 - public void bind(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; + } + + public void setWaitingForRenderInvoke(boolean waitingForRenderInvoke) { + isWaitingForRenderInvoke = waitingForRenderInvoke; + } + + /** + * Animate a MarkerView to a given rotation. + *

+ * The {@link MarkerView} will be rotated from its current rotation to the given rotation. + *

+ * + * @param marker the MarkerView to rotate. + * @param rotation the rotation value. + */ + public void animateRotation(@NonNull MarkerView marker, float rotation) { + View convertView = markerViewMap.get(marker); + if (convertView != null) { + AnimatorUtils.rotate(convertView, rotation); } - - - @Override - public void onMapChanged(@MapView.MapChange int change) { - if (isWaitingForRenderInvoke && change == MapView.DID_FINISH_RENDERING_FRAME_FULLY_RENDERED) { - isWaitingForRenderInvoke = false; - invalidateViewMarkersInVisibleRegion(); - } + } + + /** + * Animate a MarkerView with a given rotation. + * + * @param marker the MarkerView to rotate by. + * @param rotation the rotation by value, limited to 0 - 360 degrees. + */ + public void animateRotationBy(@NonNull MarkerView marker, float rotation) { + View convertView = markerViewMap.get(marker); + if (convertView != null) { + convertView.animate().cancel(); + // calculate new direction + float diff = rotation - convertView.getRotation(); + if (diff > 180.0f) { + diff -= 360.0f; + } else if (diff < -180.0f) { + diff += 360.f; + } + AnimatorUtils.rotateBy(convertView, diff); } - - public void setWaitingForRenderInvoke(boolean waitingForRenderInvoke) { - isWaitingForRenderInvoke = waitingForRenderInvoke; + } + + /** + * Animate a MarkerView to a given alpha value. + *

+ * The {@link MarkerView} will be transformed from its current alpha value to the given value. + *

+ * + * @param marker the MarkerView to change its alpha value. + * @param alpha the alpha value. + */ + public void animateAlpha(@NonNull MarkerView marker, float alpha) { + View convertView = markerViewMap.get(marker); + if (convertView != null) { + AnimatorUtils.alpha(convertView, alpha); } - - /** - * Animate a MarkerView to a given rotation. - *

- * The {@link MarkerView} will be rotated from its current rotation to the given rotation. - *

- * - * @param marker the MarkerView to rotate. - * @param rotation the rotation value. - */ - public void animateRotation(@NonNull MarkerView marker, float rotation) { - View convertView = markerViewMap.get(marker); - if (convertView != null) { - AnimatorUtils.rotate(convertView, rotation); - } + } + + /** + * Animate a MarkerVIew to be visible or invisible + *

+ * The {@link MarkerView} will be made {@link View#VISIBLE} or {@link View#GONE}. + *

+ * + * @param marker the MarkerView to change its visibility + * @param visible the flag indicating if MarkerView is visible + */ + public void animateVisible(@NonNull MarkerView marker, boolean visible) { + View convertView = markerViewMap.get(marker); + if (convertView != null) { + convertView.setVisibility(visible ? View.VISIBLE : View.GONE); } - - /** - * Animate a MarkerView with a given rotation. - * - * @param marker the MarkerView to rotate by. - * @param rotation the rotation by value, limited to 0 - 360 degrees. - */ - public void animateRotationBy(@NonNull MarkerView marker, float rotation) { - View convertView = markerViewMap.get(marker); - if (convertView != null) { - convertView.animate().cancel(); - // calculate new direction - float diff = rotation - convertView.getRotation(); - if (diff > 180.0f) { - diff -= 360.0f; - } else if (diff < -180.0f) { - diff += 360.f; + } + + /** + * Updates the position of MarkerViews currently found in the viewport. + *

+ * The collection of {@link MarkerView} will be iterated and each item position will be updated. + * If an item is View state is not visible and its related flag is set to visible, the + * {@link MarkerView} will be animated to visible using alpha animation. + *

+ */ + public void update() { + for (final MarkerView marker : markerViewMap.keySet()) { + final View convertView = markerViewMap.get(marker); + if (convertView != null) { + PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); + if (marker.getOffsetX() == MapboxConstants.UNMEASURED) { + // ensure view is measured first + if (marker.getWidth() == 0) { + convertView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); + if (convertView.getMeasuredWidth() != 0) { + marker.setWidth(convertView.getMeasuredWidth()); + marker.setHeight(convertView.getMeasuredHeight()); } - AnimatorUtils.rotateBy(convertView, diff); + } + } + if (marker.getWidth() != 0) { + int x = (int) (marker.getAnchorU() * marker.getWidth()); + int y = (int) (marker.getAnchorV() * marker.getHeight()); + marker.setOffset(x, y); } - } - /** - * Animate a MarkerView to a given alpha value. - *

- * The {@link MarkerView} will be transformed from its current alpha value to the given value. - *

- * - * @param marker the MarkerView to change its alpha value. - * @param alpha the alpha value. - */ - public void animateAlpha(@NonNull MarkerView marker, float alpha) { - View convertView = markerViewMap.get(marker); - if (convertView != null) { - AnimatorUtils.alpha(convertView, alpha); + convertView.setX(point.x - marker.getOffsetX()); + convertView.setY(point.y - marker.getOffsetY()); + + // animate visibility + if (marker.isVisible() && convertView.getVisibility() == View.GONE) { + animateVisible(marker, true); } + } } - - /** - * Animate a MarkerVIew to be visible or invisible - *

- * The {@link MarkerView} will be made {@link View#VISIBLE} or {@link View#GONE}. - *

- * - * @param marker the MarkerView to change its visibility - * @param visible the flag indicating if MarkerView is visible - */ - public void animateVisible(@NonNull MarkerView marker, boolean visible) { - View convertView = markerViewMap.get(marker); + } + + /** + * Set tilt on every non flat MarkerView currently shown in the Viewport. + * + * @param tilt the tilt value. + */ + public void setTilt(float tilt) { + View convertView; + for (MarkerView markerView : markerViewMap.keySet()) { + if (markerView.isFlat()) { + convertView = markerViewMap.get(markerView); if (convertView != null) { - convertView.setVisibility(visible ? View.VISIBLE : View.GONE); + markerView.setTilt(tilt); + convertView.setRotationX(tilt); } + } } - - /** - * Updates the position of MarkerViews currently found in the viewport. - *

- * The collection of {@link MarkerView} will be iterated and each item position will be updated. - * If an item is View state is not visible and its related flag is set to visible, the - * {@link MarkerView} will be animated to visible using alpha animation. - *

- */ - public void update() { - for (final MarkerView marker : markerViewMap.keySet()) { - final View convertView = markerViewMap.get(marker); - if (convertView != null) { - PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); - if (marker.getOffsetX() == MapboxConstants.UNMEASURED) { - // ensure view is measured first - if (marker.getWidth() == 0) { - convertView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); - if (convertView.getMeasuredWidth() != 0) { - marker.setWidth(convertView.getMeasuredWidth()); - marker.setHeight(convertView.getMeasuredHeight()); - } - } - } - if (marker.getWidth() != 0) { - int x = (int) (marker.getAnchorU() * marker.getWidth()); - int y = (int) (marker.getAnchorV() * marker.getHeight()); - marker.setOffset(x, y); - } - - convertView.setX(point.x - marker.getOffsetX()); - convertView.setY(point.y - marker.getOffsetY()); - - // animate visibility - if (marker.isVisible() && convertView.getVisibility() == View.GONE) { - animateVisible(marker, true); - } - } - } + } + + /** + * Update and invalidate the MarkerView icon. + * + * @param markerView the marker view to updates. + */ + public void updateIcon(@NonNull MarkerView markerView) { + View convertView = markerViewMap.get(markerView); + if (convertView != null && convertView instanceof ImageView) { + ((ImageView) convertView).setImageBitmap(markerView.getIcon().getBitmap()); } - - /** - * Set tilt on every non flat MarkerView currently shown in the Viewport. - * - * @param tilt the tilt value. - */ - public void setTilt(float tilt) { - View convertView; - for (MarkerView markerView : markerViewMap.keySet()) { - if (markerView.isFlat()) { - convertView = markerViewMap.get(markerView); - if (convertView != null) { - markerView.setTilt(tilt); - convertView.setRotationX(tilt); - } - } + } + + /** + * Animate a MarkerView to a deselected state. + *

+ * The {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter#onDeselect(MarkerView, View)} + * will be called to execute an animation. + *

+ * + * @param marker the MarkerView to deselect. + */ + public void deselect(@NonNull MarkerView marker) { + deselect(marker, true); + } + + /** + * Animate a MarkerView to a deselected state. + *

+ * The {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter#onDeselect(MarkerView, View)} + * will be called to execute an animation. + *

+ * + * @param marker the MarkerView to deselect. + * @param callbackToMap indicates if deselect marker must be called on MapboxMap. + */ + public void deselect(@NonNull MarkerView marker, boolean callbackToMap) { + final View convertView = markerViewMap.get(marker); + if (convertView != null) { + for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { + if (adapter.getMarkerClass().equals(marker.getClass())) { + adapter.onDeselect(marker, convertView); } + } } - - /** - * Update and invalidate the MarkerView icon. - * - * @param markerView the marker view to updates. - */ - public void updateIcon(@NonNull MarkerView markerView) { - View convertView = markerViewMap.get(markerView); - if (convertView != null && convertView instanceof ImageView) { - ((ImageView) convertView).setImageBitmap(markerView.getIcon().getBitmap()); - } + if (callbackToMap) { + mapboxMap.deselectMarker(marker); } - - /** - * Animate a MarkerView to a deselected state. - *

- * The {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter#onDeselect(MarkerView, View)} - * will be called to execute an animation. - *

- * - * @param marker the MarkerView to deselect. - */ - public void deselect(@NonNull MarkerView marker) { - deselect(marker, true); + marker.setSelected(false); + } + + /** + * Animate a MarkerView to a selected state. + * + * @param marker the MarkerView object to select. + */ + public void select(@NonNull MarkerView marker) { + select(marker, true); + } + + /** + * Animate a MarkerView to a selected state. + * + * @param marker the MarkerView object to select. + * @param callbackToMap indicates if select marker must be called on {@link MapboxMap}. + */ + public void select(@NonNull MarkerView marker, boolean callbackToMap) { + final View convertView = markerViewMap.get(marker); + for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { + if (adapter.getMarkerClass().equals(marker.getClass())) { + select(marker, convertView, adapter, callbackToMap); + } } - - /** - * Animate a MarkerView to a deselected state. - *

- * The {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter#onDeselect(MarkerView, View)} - * will be called to execute an animation. - *

- * - * @param marker the MarkerView to deselect. - * @param callbackToMap indicates if deselect marker must be called on MapboxMap. - */ - public void deselect(@NonNull MarkerView marker, boolean callbackToMap) { - final View convertView = markerViewMap.get(marker); - if (convertView != null) { - for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { - if (adapter.getMarkerClass().equals(marker.getClass())) { - adapter.onDeselect(marker, convertView); - } - } - } + } + + /** + * Animate a MarkerView to a selected state. + *

+ * The {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter#onSelect(MarkerView, View, boolean)} + * will be called to execute an animation. + *

+ * + * @param marker the MarkerView object to select. + * @param convertView the View presentation of the MarkerView. + * @param adapter the adapter used to adapt the marker to the convertView. + */ + public void select(@NonNull MarkerView marker, View convertView, MapboxMap.MarkerViewAdapter adapter) { + select(marker, convertView, adapter, true); + } + + + /** + * Animate a MarkerView to a selected state. + *

+ * The {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter#onSelect(MarkerView, View, boolean)} + * will be called to execute an animation. + *

+ * + * @param marker the MarkerView object to select. + * @param convertView the View presentation of the MarkerView. + * @param adapter the adapter used to adapt the marker to the convertView. + * @param callbackToMap indicates if select marker must be called on MapboxMap. + */ + public void select(@NonNull MarkerView marker, View convertView, MapboxMap.MarkerViewAdapter adapter, + boolean callbackToMap) { + if (convertView != null) { + if (adapter.onSelect(marker, convertView, false)) { if (callbackToMap) { - mapboxMap.deselectMarker(marker); + mapboxMap.selectMarker(marker); } - marker.setSelected(false); + } + marker.setSelected(true); + convertView.bringToFront(); } - - /** - * Animate a MarkerView to a selected state. - * - * @param marker the MarkerView object to select. - */ - public void select(@NonNull MarkerView marker) { - select(marker, true); + } + + /** + * Get view representation from a MarkerView. If marker is not found in current viewport, + * {@code null} is returned. + * + * @param marker the marker to get the view. + * @return the Android SDK View object. + */ + @Nullable + public View getView(MarkerView marker) { + return markerViewMap.get(marker); + } + + /** + * Get the view adapter for a marker. + * + * @param markerView the marker to get the view adapter. + * @return the MarkerView adapter. + */ + @Nullable + public MapboxMap.MarkerViewAdapter getViewAdapter(MarkerView markerView) { + MapboxMap.MarkerViewAdapter adapter = null; + for (MapboxMap.MarkerViewAdapter a : markerViewAdapters) { + if (a.getMarkerClass().equals(markerView.getClass())) { + adapter = a; + } } - - /** - * Animate a MarkerView to a selected state. - * - * @param marker the MarkerView object to select. - * @param callbackToMap indicates if select marker must be called on {@link MapboxMap}. - */ - public void select(@NonNull MarkerView marker, boolean callbackToMap) { - final View convertView = markerViewMap.get(marker); - for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { - if (adapter.getMarkerClass().equals(marker.getClass())) { - select(marker, convertView, adapter, callbackToMap); - } + return adapter; + } + + /** + * Remove a MarkerView from a map. + *

+ * The {@link MarkerView} will be removed using an alpha animation and related {@link View} + * will be released to the android.support.v4.util.Pools.SimplePool from the related + * {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter}. It's possible to remove + * the {@link MarkerView} from the underlying collection if needed. + *

+ * + * @param marker the MarkerView to remove. + */ + public void removeMarkerView(MarkerView marker) { + final View viewHolder = markerViewMap.get(marker); + if (viewHolder != null && marker != null) { + for (final MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { + if (adapter.getMarkerClass().equals(marker.getClass())) { + if (adapter.prepareViewForReuse(marker, viewHolder)) { + // reset offset for reuse + marker.setOffset(MapboxConstants.UNMEASURED, MapboxConstants.UNMEASURED); + adapter.releaseView(viewHolder); + } } + } } - - /** - * Animate a MarkerView to a selected state. - *

- * The {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter#onSelect(MarkerView, View, boolean)} - * will be called to execute an animation. - *

- * - * @param marker the MarkerView object to select. - * @param convertView the View presentation of the MarkerView. - * @param adapter the adapter used to adapt the marker to the convertView. - */ - public void select(@NonNull MarkerView marker, View convertView, MapboxMap.MarkerViewAdapter adapter) { - select(marker, convertView, adapter, true); + marker.setMapboxMap(null); + markerViewMap.remove(marker); + } + + /** + * Add a MarkerViewAdapter to the MarkerViewManager. + *

+ * The provided MarkerViewAdapter must supply a generic subclass of MarkerView. + *

+ * + * @param markerViewAdapter the MarkerViewAdapter to add. + */ + public void addMarkerViewAdapter(MapboxMap.MarkerViewAdapter markerViewAdapter) { + if (markerViewAdapter.getMarkerClass().equals(MarkerView.class)) { + throw new RuntimeException("Providing a custom MarkerViewAdapter requires subclassing MarkerView"); } - - /** - * Animate a MarkerView to a selected state. - *

- * The {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter#onSelect(MarkerView, View, boolean)} - * will be called to execute an animation. - *

- * - * @param marker the MarkerView object to select. - * @param convertView the View presentation of the MarkerView. - * @param adapter the adapter used to adapt the marker to the convertView. - * @param callbackToMap indicates if select marker must be called on MapboxMap. - */ - public void select(@NonNull MarkerView marker, View convertView, MapboxMap.MarkerViewAdapter adapter, boolean callbackToMap) { - if (convertView != null) { - if (adapter.onSelect(marker, convertView, false)) { - if (callbackToMap) { - mapboxMap.selectMarker(marker); - } - } - marker.setSelected(true); - convertView.bringToFront(); - } + if (!markerViewAdapters.contains(markerViewAdapter)) { + markerViewAdapters.add(markerViewAdapter); + invalidateViewMarkersInVisibleRegion(); } - - /** - * Get view representation from a MarkerView. If marker is not found in current viewport, - * {@code null} is returned. - * - * @param marker the marker to get the view. - * @return the Android SDK View object. - */ - @Nullable - public View getView(MarkerView marker) { - return markerViewMap.get(marker); + } + + /** + * Get all MarkerViewAdapters associated with this MarkerViewManager. + * + * @return a List of MarkerViewAdapters. + */ + public List getMarkerViewAdapters() { + return markerViewAdapters; + } + + /** + * Register a callback to be invoked when this view is clicked. + * + * @param listener the callback to be invoked. + */ + public void setOnMarkerViewClickListener(@Nullable MapboxMap.OnMarkerViewClickListener listener) { + onMarkerViewClickListener = listener; + } + + /** + * Schedule that ViewMarkers found in the viewport are invalidated. + *

+ * This method is rate limited, and {@link #invalidateViewMarkersInVisibleRegion} will only be called + * once each 250 ms. + *

+ */ + public void scheduleViewMarkerInvalidation() { + if (!markerViewAdapters.isEmpty()) { + long currentTime = SystemClock.elapsedRealtime(); + if (currentTime < viewMarkerBoundsUpdateTime) { + return; + } + invalidateViewMarkersInVisibleRegion(); + viewMarkerBoundsUpdateTime = currentTime + 250; } - - /** - * Get the view adapter for a marker. - * - * @param markerView the marker to get the view adapter. - * @return the MarkerView adapter. - */ - @Nullable - public MapboxMap.MarkerViewAdapter getViewAdapter(MarkerView markerView) { - MapboxMap.MarkerViewAdapter adapter = null; - for (MapboxMap.MarkerViewAdapter a : markerViewAdapters) { - if (a.getMarkerClass().equals(markerView.getClass())) { - adapter = a; - } + } + + /** + * Invalidate the ViewMarkers found in the viewport. + *

+ * This method will remove any markers that aren't in the viewport anymore and will add new + * ones for each found Marker in the changed viewport. + *

+ */ + public void invalidateViewMarkersInVisibleRegion() { + RectF mapViewRect = new RectF(0, 0, markerViewContainer.getWidth(), markerViewContainer.getHeight()); + List markers = mapboxMap.getMarkerViewsInRect(mapViewRect); + View convertView; + + // remove old markers + Iterator iterator = markerViewMap.keySet().iterator(); + while (iterator.hasNext()) { + MarkerView marker = iterator.next(); + if (!markers.contains(marker)) { + // remove marker + convertView = markerViewMap.get(marker); + for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { + if (adapter.getMarkerClass().equals(marker.getClass())) { + adapter.prepareViewForReuse(marker, convertView); + adapter.releaseView(convertView); + marker.setMapboxMap(null); + iterator.remove(); + } } - return adapter; + } } - /** - * Remove a MarkerView from a map. - *

- * The {@link MarkerView} will be removed using an alpha animation and related {@link View} - * will be released to the android.support.v4.util.Pools.SimplePool from the related - * {@link com.mapbox.mapboxsdk.maps.MapboxMap.MarkerViewAdapter}. It's possible to remove - * the {@link MarkerView} from the underlying collection if needed. - *

- * - * @param marker the MarkerView to remove. - */ - public void removeMarkerView(MarkerView marker) { - final View viewHolder = markerViewMap.get(marker); - if (viewHolder != null && marker != null) { - for (final MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { - if (adapter.getMarkerClass().equals(marker.getClass())) { - if (adapter.prepareViewForReuse(marker, viewHolder)) { - // reset offset for reuse - marker.setOffset(MapboxConstants.UNMEASURED, MapboxConstants.UNMEASURED); - adapter.releaseView(viewHolder); - } + // introduce new markers + for (final MarkerView marker : markers) { + if (!markerViewMap.containsKey(marker)) { + for (final MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { + if (adapter.getMarkerClass().equals(marker.getClass())) { + + // Inflate View + convertView = (View) adapter.getViewReusePool().acquire(); + final View adaptedView = adapter.getView(marker, convertView, markerViewContainer); + if (adaptedView != null) { + adaptedView.setRotationX(marker.getTilt()); + adaptedView.setRotation(marker.getRotation()); + adaptedView.setAlpha(marker.getAlpha()); + adaptedView.setVisibility(View.GONE); + + if (mapboxMap.getSelectedMarkers().contains(marker)) { + // if a marker to be shown was selected + // replay that animation with duration 0 + if (adapter.onSelect(marker, adaptedView, true)) { + mapboxMap.selectMarker(marker); } + } + + marker.setMapboxMap(mapboxMap); + markerViewMap.put(marker, adaptedView); + if (convertView == null) { + adaptedView.setVisibility(View.GONE); + markerViewContainer.addView(adaptedView); + } } - } - marker.setMapboxMap(null); - markerViewMap.remove(marker); - } - /** - * Add a MarkerViewAdapter to the MarkerViewManager. - *

- * The provided MarkerViewAdapter must supply a generic subclass of MarkerView. - *

- * - * @param markerViewAdapter the MarkerViewAdapter to add. - */ - public void addMarkerViewAdapter(MapboxMap.MarkerViewAdapter markerViewAdapter) { - if (markerViewAdapter.getMarkerClass().equals(MarkerView.class)) { - throw new RuntimeException("Providing a custom MarkerViewAdapter requires subclassing MarkerView"); - } - - if (!markerViewAdapters.contains(markerViewAdapter)) { - markerViewAdapters.add(markerViewAdapter); - invalidateViewMarkersInVisibleRegion(); + // notify listener is marker view is rendered + OnMarkerViewAddedListener onViewAddedListener = markerViewAddedListenerMap.get(marker.getId()); + if (onViewAddedListener != null) { + onViewAddedListener.onViewAdded(marker); + markerViewAddedListenerMap.remove(marker.getId()); + } + } } + } } - /** - * Get all MarkerViewAdapters associated with this MarkerViewManager. - * - * @return a List of MarkerViewAdapters. - */ - public List getMarkerViewAdapters() { - return markerViewAdapters; + // clear map, don't keep references to MarkerView listeners that are not found in the bounds of the map. + markerViewAddedListenerMap.clear(); + + // trigger update to make newly added ViewMarker visible, + // these would only be updated when the map is moved. + update(); + } + + /** + * When the provided {@link MarkerView} is clicked on by a user, we check if a custom click + * event has been created and if not, display a {@link InfoWindow}. + * + * @param markerView that the click event occurred. + */ + public boolean onClickMarkerView(MarkerView markerView) { + boolean clickHandled = false; + + MapboxMap.MarkerViewAdapter adapter = getViewAdapter(markerView); + View view = getView(markerView); + if (adapter == null || view == null) { + // not a valid state + return true; } - /** - * Register a callback to be invoked when this view is clicked. - * - * @param listener the callback to be invoked. - */ - public void setOnMarkerViewClickListener(@Nullable MapboxMap.OnMarkerViewClickListener listener) { - onMarkerViewClickListener = listener; + if (onMarkerViewClickListener != null) { + clickHandled = onMarkerViewClickListener.onMarkerClick(markerView, view, adapter); } - /** - * Schedule that ViewMarkers found in the viewport are invalidated. - *

- * This method is rate limited, and {@link #invalidateViewMarkersInVisibleRegion} will only be called - * once each 250 ms. - *

- */ - public void scheduleViewMarkerInvalidation() { - if (!markerViewAdapters.isEmpty()) { - long currentTime = SystemClock.elapsedRealtime(); - if (currentTime < viewMarkerBoundsUpdateTime) { - return; - } - invalidateViewMarkersInVisibleRegion(); - viewMarkerBoundsUpdateTime = currentTime + 250; - } + if (!clickHandled) { + ensureInfoWindowOffset(markerView); + select(markerView, view, adapter); } - /** - * Invalidate the ViewMarkers found in the viewport. - *

- * This method will remove any markers that aren't in the viewport anymore and will add new - * ones for each found Marker in the changed viewport. - *

- */ - public void invalidateViewMarkersInVisibleRegion() { - RectF mapViewRect = new RectF(0, 0, markerViewContainer.getWidth(), markerViewContainer.getHeight()); - List markers = mapboxMap.getMarkerViewsInRect(mapViewRect); - View convertView; - - // remove old markers - Iterator iterator = markerViewMap.keySet().iterator(); - while (iterator.hasNext()) { - MarkerView marker = iterator.next(); - if (!markers.contains(marker)) { - // remove marker - convertView = markerViewMap.get(marker); - for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { - if (adapter.getMarkerClass().equals(marker.getClass())) { - adapter.prepareViewForReuse(marker, convertView); - adapter.releaseView(convertView); - marker.setMapboxMap(null); - iterator.remove(); - } - } - } - } - - // introduce new markers - for (final MarkerView marker : markers) { - if (!markerViewMap.containsKey(marker)) { - for (final MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { - if (adapter.getMarkerClass().equals(marker.getClass())) { - - // Inflate View - convertView = (View) adapter.getViewReusePool().acquire(); - final View adaptedView = adapter.getView(marker, convertView, markerViewContainer); - if (adaptedView != null) { - adaptedView.setRotationX(marker.getTilt()); - adaptedView.setRotation(marker.getRotation()); - adaptedView.setAlpha(marker.getAlpha()); - adaptedView.setVisibility(View.GONE); - - if (mapboxMap.getSelectedMarkers().contains(marker)) { - // if a marker to be shown was selected - // replay that animation with duration 0 - if (adapter.onSelect(marker, adaptedView, true)) { - mapboxMap.selectMarker(marker); - } - } - - marker.setMapboxMap(mapboxMap); - markerViewMap.put(marker, adaptedView); - if (convertView == null) { - adaptedView.setVisibility(View.GONE); - markerViewContainer.addView(adaptedView); - } - } - - // notify listener is marker view is rendered - OnMarkerViewAddedListener onViewAddedListener = markerViewAddedListenerMap.get(marker.getId()); - if (onViewAddedListener != null) { - onViewAddedListener.onViewAdded(marker); - markerViewAddedListenerMap.remove(marker.getId()); - } - } - } - } + return clickHandled; + } + + /** + * Handles the {@link MarkerView}'s info window offset. + * + * @param marker that we are ensuring info window offset. + */ + public void ensureInfoWindowOffset(MarkerView marker) { + View view = null; + if (markerViewMap.containsKey(marker)) { + view = markerViewMap.get(marker); + } else { + for (final MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { + if (adapter.getMarkerClass().equals(marker.getClass())) { + View convertView = (View) adapter.getViewReusePool().acquire(); + view = adapter.getView(marker, convertView, markerViewContainer); + break; } - - // clear map, don't keep references to MarkerView listeners that are not found in the bounds of the map. - markerViewAddedListenerMap.clear(); - - // trigger update to make newly added ViewMarker visible, - // these would only be updated when the map is moved. - update(); + } } - /** - * When the provided {@link MarkerView} is clicked on by a user, we check if a custom click - * event has been created and if not, display a {@link InfoWindow}. - * - * @param markerView that the click event occurred. - */ - public boolean onClickMarkerView(MarkerView markerView) { - boolean clickHandled = false; - - MapboxMap.MarkerViewAdapter adapter = getViewAdapter(markerView); - View view = getView(markerView); - if (adapter == null || view == null) { - // not a valid state - return true; + if (view != null) { + if (marker.getWidth() == 0) { + if (view.getMeasuredWidth() == 0) { + //Ensure the marker's view is measured first + view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); } - - if (onMarkerViewClickListener != null) { - clickHandled = onMarkerViewClickListener.onMarkerClick(markerView, view, adapter); - } - - if (!clickHandled) { - ensureInfoWindowOffset(markerView); - select(markerView, view, adapter); - } - - return clickHandled; + marker.setWidth(view.getMeasuredWidth()); + marker.setHeight(view.getMeasuredHeight()); + } + + // update position on map + if (marker.getOffsetX() == MapboxConstants.UNMEASURED) { + int x = (int) (marker.getAnchorU() * marker.getWidth()); + int y = (int) (marker.getAnchorV() * marker.getHeight()); + marker.setOffset(x, y); + } + + // InfoWindow offset + int infoWindowOffsetX = (int) ((view.getMeasuredWidth() * marker.getInfoWindowAnchorU()) - marker.getOffsetX()); + int infoWindowOffsetY = (int) ((view.getMeasuredHeight() * marker.getInfoWindowAnchorV()) - marker.getOffsetY()); + marker.setTopOffsetPixels(infoWindowOffsetY); + marker.setRightOffsetPixels(infoWindowOffsetX); } + } - /** - * Handles the {@link MarkerView}'s info window offset. - * - * @param marker that we are ensuring info window offset. - */ - public void ensureInfoWindowOffset(MarkerView marker) { - View view = null; - if (markerViewMap.containsKey(marker)) { - view = markerViewMap.get(marker); - } else { - for (final MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { - if (adapter.getMarkerClass().equals(marker.getClass())) { - View convertView = (View) adapter.getViewReusePool().acquire(); - view = adapter.getView(marker, convertView, markerViewContainer); - break; - } - } - } + public ViewGroup getMarkerViewContainer() { + return markerViewContainer; + } - if (view != null) { - if (marker.getWidth() == 0) { - if (view.getMeasuredWidth() == 0) { - //Ensure the marker's view is measured first - view.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED); - } - marker.setWidth(view.getMeasuredWidth()); - marker.setHeight(view.getMeasuredHeight()); - } + public void addOnMarkerViewAddedListener(MarkerView markerView, OnMarkerViewAddedListener onMarkerViewAddedListener) { + markerViewAddedListenerMap.put(markerView.getId(), onMarkerViewAddedListener); + } - // update position on map - if (marker.getOffsetX() == MapboxConstants.UNMEASURED) { - int x = (int) (marker.getAnchorU() * marker.getWidth()); - int y = (int) (marker.getAnchorV() * marker.getHeight()); - marker.setOffset(x, y); - } + /** + * Default MarkerViewAdapter used for base class of {@link MarkerView} to adapt a MarkerView to + * an ImageView. + */ + public static class ImageMarkerViewAdapter extends MapboxMap.MarkerViewAdapter { - // InfoWindow offset - int infoWindowOffsetX = (int) ((view.getMeasuredWidth() * marker.getInfoWindowAnchorU()) - marker.getOffsetX()); - int infoWindowOffsetY = (int) ((view.getMeasuredHeight() * marker.getInfoWindowAnchorV()) - marker.getOffsetY()); - marker.setTopOffsetPixels(infoWindowOffsetY); - marker.setRightOffsetPixels(infoWindowOffsetX); - } - } + private LayoutInflater inflater; - public ViewGroup getMarkerViewContainer() { - return markerViewContainer; + public ImageMarkerViewAdapter(Context context) { + super(context); + inflater = LayoutInflater.from(context); } - public void addOnMarkerViewAddedListener(MarkerView markerView, OnMarkerViewAddedListener onMarkerViewAddedListener) { - markerViewAddedListenerMap.put(markerView.getId(), onMarkerViewAddedListener); + @Nullable + @Override + public View getView(@NonNull MarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) { + ViewHolder viewHolder; + if (convertView == null) { + viewHolder = new ViewHolder(); + convertView = inflater.inflate(R.layout.mapbox_view_image_marker, parent, false); + viewHolder.imageView = (ImageView) convertView.findViewById(R.id.image); + convertView.setTag(viewHolder); + } else { + viewHolder = (ViewHolder) convertView.getTag(); + } + viewHolder.imageView.setImageBitmap(marker.getIcon().getBitmap()); + return convertView; } - /** - * Default MarkerViewAdapter used for base class of {@link MarkerView} to adapt a MarkerView to - * an ImageView. - */ - public static class ImageMarkerViewAdapter extends MapboxMap.MarkerViewAdapter { - - private LayoutInflater inflater; - - public ImageMarkerViewAdapter(Context context) { - super(context); - inflater = LayoutInflater.from(context); - } - - @Nullable - @Override - public View getView(@NonNull MarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) { - ViewHolder viewHolder; - if (convertView == null) { - viewHolder = new ViewHolder(); - convertView = inflater.inflate(R.layout.mapbox_view_image_marker, parent, false); - viewHolder.imageView = (ImageView) convertView.findViewById(R.id.image); - convertView.setTag(viewHolder); - } else { - viewHolder = (ViewHolder) convertView.getTag(); - } - viewHolder.imageView.setImageBitmap(marker.getIcon().getBitmap()); - return convertView; - } - - private static class ViewHolder { - ImageView imageView; - } + private static class ViewHolder { + ImageView imageView; } + } + + /** + * Interface definition invoked when the View of a MarkerView has been added to the map. + *

+ * {@link MapboxMap#addMarker(BaseMarkerOptions)} + * and only when the related MarkerView is found in the viewport of the map. + *

+ */ + public interface OnMarkerViewAddedListener { /** - * Interface definition invoked when the View of a MarkerView has been added to the map. - *

- * {@link MapboxMap#addMarker(BaseMarkerOptions)} - * and only when the related MarkerView is found in the viewport of the map. - *

+ * Invoked when the View of a MarkerView has been added to the Map. + * + * @param markerView The MarkerView the View was added for */ - public interface OnMarkerViewAddedListener { - - /** - * Invoked when the View of a MarkerView has been added to the Map. - * - * @param markerView The MarkerView the View was added for - */ - void onViewAdded(@NonNull MarkerView markerView); - } + void onViewAdded(@NonNull MarkerView markerView); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java index 1a763a72a1..2d829537fc 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MarkerViewOptions.java @@ -15,146 +15,150 @@ import com.mapbox.mapboxsdk.geometry.LatLng; */ public class MarkerViewOptions extends BaseMarkerViewOptions { - private MarkerView marker; + private MarkerView marker; - /** - * Defines default options for a MarkerView. Extend {@link BaseMarkerViewOptions} if you need - * more customization. - */ - public MarkerViewOptions() { - marker = new MarkerView(); - } + /** + * Defines default options for a MarkerView. Extend {@link BaseMarkerViewOptions} if you need + * more customization. + */ + public MarkerViewOptions() { + marker = new MarkerView(); + } - protected MarkerViewOptions(Parcel in) { - marker = new MarkerView(); - position((LatLng) in.readParcelable(LatLng.class.getClassLoader())); - snippet(in.readString()); - title(in.readString()); - flat(in.readByte() != 0); - anchor(in.readFloat(), in.readFloat()); - infoWindowAnchor(in.readFloat(), in.readFloat()); - rotation(in.readFloat()); - visible(in.readByte() != 0); - alpha(in.readFloat()); - if (in.readByte() != 0) { - // this means we have an icon - String iconId = in.readString(); - Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader()); - Icon icon = new Icon(iconId, iconBitmap); - icon(icon); - } + protected MarkerViewOptions(Parcel in) { + marker = new MarkerView(); + position((LatLng) in.readParcelable(LatLng.class.getClassLoader())); + snippet(in.readString()); + title(in.readString()); + flat(in.readByte() != 0); + anchor(in.readFloat(), in.readFloat()); + infoWindowAnchor(in.readFloat(), in.readFloat()); + rotation(in.readFloat()); + visible(in.readByte() != 0); + alpha(in.readFloat()); + if (in.readByte() != 0) { + // this means we have an icon + String iconId = in.readString(); + Bitmap iconBitmap = in.readParcelable(Bitmap.class.getClassLoader()); + Icon icon = new Icon(iconId, iconBitmap); + icon(icon); } + } - /** - * Get the instance of the object for which this method was called. - * - * @return the object for which this method was called. - */ - @Override - public MarkerViewOptions getThis() { - return this; - } + /** + * Get the instance of the object for which this method was called. + * + * @return the object for which this method was called. + */ + @Override + public MarkerViewOptions getThis() { + return this; + } - /** - * Describe the kinds of special objects contained in this Parcelable's - * marshalled representation. - * - * @return integer 0. - */ - @Override - public int describeContents() { - return 0; - } + /** + * Describe the kinds of special objects contained in this Parcelable's + * marshalled representation. + * + * @return integer 0. + */ + @Override + public int describeContents() { + return 0; + } - /** - * Flatten this object in to a Parcel. - * - * @param out The Parcel in which the object should be written. - * @param flags Additional flags about how the object should be written. May be 0 or - * {@link #PARCELABLE_WRITE_RETURN_VALUE}. - */ - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeParcelable(getPosition(), flags); - out.writeString(getSnippet()); - out.writeString(getTitle()); - out.writeByte((byte) (isFlat() ? 1 : 0)); - out.writeFloat(getAnchorU()); - out.writeFloat(getAnchorV()); - out.writeFloat(getInfoWindowAnchorU()); - out.writeFloat(getInfoWindowAnchorV()); - out.writeFloat(getRotation()); - out.writeByte((byte) (isVisible() ? 1 : 0)); - out.writeFloat(alpha); - Icon icon = getIcon(); - out.writeByte((byte) (icon != null ? 1 : 0)); - if (icon != null) { - out.writeString(getIcon().getId()); - out.writeParcelable(getIcon().getBitmap(), flags); - } + /** + * Flatten this object in to a Parcel. + * + * @param out The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written. May be 0 or + * {@link #PARCELABLE_WRITE_RETURN_VALUE}. + */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeParcelable(getPosition(), flags); + out.writeString(getSnippet()); + out.writeString(getTitle()); + out.writeByte((byte) (isFlat() ? 1 : 0)); + out.writeFloat(getAnchorU()); + out.writeFloat(getAnchorV()); + out.writeFloat(getInfoWindowAnchorU()); + out.writeFloat(getInfoWindowAnchorV()); + out.writeFloat(getRotation()); + out.writeByte((byte) (isVisible() ? 1 : 0)); + out.writeFloat(alpha); + Icon icon = getIcon(); + out.writeByte((byte) (icon != null ? 1 : 0)); + if (icon != null) { + out.writeString(getIcon().getId()); + out.writeParcelable(getIcon().getBitmap(), flags); } + } - /** - * Get the {@link MarkerView}. - * - * @return {@link MarkerView}. - */ - @Override - public MarkerView getMarker() { - if (position == null) { - throw new InvalidMarkerPositionException(); - } - - marker.setPosition(position); - marker.setSnippet(snippet); - marker.setTitle(title); - marker.setIcon(icon); - marker.setFlat(flat); - marker.setAnchor(anchorU, anchorV); - marker.setInfoWindowAnchor(infoWindowAnchorU, infoWindowAnchorV); - marker.setRotation(rotation); - marker.setVisible(visible); - marker.setAlpha(alpha); - return marker; + /** + * Get the {@link MarkerView}. + * + * @return {@link MarkerView}. + */ + @Override + public MarkerView getMarker() { + if (position == null) { + throw new InvalidMarkerPositionException(); } - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public MarkerViewOptions createFromParcel(Parcel in) { - return new MarkerViewOptions(in); - } + marker.setPosition(position); + marker.setSnippet(snippet); + marker.setTitle(title); + marker.setIcon(icon); + marker.setFlat(flat); + marker.setAnchor(anchorU, anchorV); + marker.setInfoWindowAnchor(infoWindowAnchorU, infoWindowAnchorV); + marker.setRotation(rotation); + marker.setVisible(visible); + marker.setAlpha(alpha); + return marker; + } - public MarkerViewOptions[] newArray(int size) { - return new MarkerViewOptions[size]; - } + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public MarkerViewOptions createFromParcel(Parcel in) { + return new MarkerViewOptions(in); + } + + public MarkerViewOptions[] newArray(int size) { + return new MarkerViewOptions[size]; + } }; - /** - * Compares this {@link MarkerViewOptions} object with another {@link MarkerViewOptions} and - * determines if they match. - * - * @param o Another {@link MarkerViewOptions} to compare with this object. - * @return True if the {@link MarkerViewOptions} being passed in matches this - * {@link PolylineOptions} object. Else, false. - */ - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - MarkerViewOptions that = (MarkerViewOptions) o; - return marker != null ? marker.equals(that.marker) : that.marker == null; + /** + * Compares this {@link MarkerViewOptions} object with another {@link MarkerViewOptions} and + * determines if they match. + * + * @param object Another {@link MarkerViewOptions} to compare with this object. + * @return True if the {@link MarkerViewOptions} being passed in matches this + * {@link PolylineOptions} object. Else, false. + */ + @Override + public boolean equals(Object object) { + if (this == object) { + return true; } - - /** - * Gives an integer which can be used as the bucket number for storing elements of the set/map. - * This bucket number is the address of the element inside the set/map. There's no guarantee - * that this hash value will be consistent between different Java implementations, or even - * between different execution runs of the same program. - * - * @return integer value you can use for storing element. - */ - @Override - public int hashCode() { - return marker != null ? marker.hashCode() : 0; + if (object == null || getClass() != object.getClass()) { + return false; } + MarkerViewOptions that = (MarkerViewOptions) object; + return marker != null ? marker.equals(that.marker) : that.marker == null; + } + + /** + * Gives an integer which can be used as the bucket number for storing elements of the set/map. + * This bucket number is the address of the element inside the set/map. There's no guarantee + * that this hash value will be consistent between different Java implementations, or even + * between different execution runs of the same program. + * + * @return integer value you can use for storing element. + */ + @Override + public int hashCode() { + return marker != null ? marker.hashCode() : 0; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MultiPoint.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MultiPoint.java index 78d21db2e9..2bd3c82786 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MultiPoint.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/MultiPoint.java @@ -10,62 +10,62 @@ import java.util.List; */ public abstract class MultiPoint extends Annotation { - private List points; - private float alpha = 1.0f; + private List points; + private float alpha = 1.0f; - protected MultiPoint() { - super(); - points = new ArrayList<>(); - } + protected MultiPoint() { + super(); + points = new ArrayList<>(); + } - /** - * Returns a copy of the points. - * - * @return A {@link List} of points. - */ - public List getPoints() { - return new ArrayList<>(points); - } + /** + * Returns a copy of the points. + * + * @return A {@link List} of points. + */ + public List getPoints() { + return new ArrayList<>(points); + } - /** - * Sets the points of this polyline. This method will take a copy of the points, so further - * mutations to points will have no effect on this polyline. - * - * @param points A {@link List} of {@link LatLng} points making up the polyline. - */ - public void setPoints(List points) { - this.points = new ArrayList<>(points); - update(); - } + /** + * Sets the points of this polyline. This method will take a copy of the points, so further + * mutations to points will have no effect on this polyline. + * + * @param points A {@link List} of {@link LatLng} points making up the polyline. + */ + public void setPoints(List points) { + this.points = new ArrayList<>(points); + update(); + } - /** - * Add a point to the polyline. - * - * @param point A {@link LatLng} point to be added. - */ - public void addPoint(LatLng point) { - points.add(point); - update(); - } + /** + * Add a point to the polyline. + * + * @param point A {@link LatLng} point to be added. + */ + public void addPoint(LatLng point) { + points.add(point); + update(); + } - /** - * Value between 0 and 1 defining the polyline alpha. - * - * @return float value between 0 and 1. - */ - public float getAlpha() { - return alpha; - } + /** + * Value between 0 and 1 defining the polyline alpha. + * + * @return float value between 0 and 1. + */ + public float getAlpha() { + return alpha; + } - /** - * Set this {@link MultiPoint}s alpha. - * - * @param alpha float value between 0 and 1. - */ - public void setAlpha(float alpha) { - this.alpha = alpha; - update(); - } + /** + * Set this {@link MultiPoint}s alpha. + * + * @param alpha float value between 0 and 1. + */ + public void setAlpha(float alpha) { + this.alpha = alpha; + update(); + } - abstract void update(); + abstract void update(); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java index a06938e3cb..7b9de86bc4 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polygon.java @@ -9,56 +9,56 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; */ public final class Polygon extends MultiPoint { - private int fillColor = Color.BLACK; // default fillColor is black - private int strokeColor = Color.BLACK; // default strokeColor is black + private int fillColor = Color.BLACK; // default fillColor is black + private int strokeColor = Color.BLACK; // default strokeColor is black - Polygon() { - super(); - } + Polygon() { + super(); + } - /** - * Get the color of the fill region of the polygon. - * - * @return The color of the fill. - */ - public int getFillColor() { - return fillColor; - } + /** + * Get the color of the fill region of the polygon. + * + * @return The color of the fill. + */ + public int getFillColor() { + return fillColor; + } - /** - * Get the color fo the stroke of the polygon. - * - * @return The color of the stroke. - */ - public int getStrokeColor() { - return strokeColor; - } + /** + * Get the color fo the stroke of the polygon. + * + * @return The color of the stroke. + */ + public int getStrokeColor() { + return strokeColor; + } - /** - * Sets the color of the fill region of the polygon. - * - * @param color The color in ARGB format. - */ - public void setFillColor(int color) { - fillColor = color; - update(); - } + /** + * Sets the color of the fill region of the polygon. + * + * @param color The color in ARGB format. + */ + public void setFillColor(int color) { + fillColor = color; + update(); + } - /** - * Sets the color of the stroke of the polygon. - * - * @param color The color in ARGB format. - */ - public void setStrokeColor(int color) { - strokeColor = color; - update(); - } + /** + * Sets the color of the stroke of the polygon. + * + * @param color The color in ARGB format. + */ + public void setStrokeColor(int color) { + strokeColor = color; + update(); + } - @Override - void update() { - MapboxMap mapboxMap = getMapboxMap(); - if (mapboxMap != null) { - mapboxMap.updatePolygon(this); - } + @Override + void update() { + MapboxMap mapboxMap = getMapboxMap(); + if (mapboxMap != null) { + mapboxMap.updatePolygon(this); } + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java index 53a4e0995b..22f1258fc7 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolygonOptions.java @@ -14,210 +14,220 @@ import java.util.List; */ public final class PolygonOptions implements Parcelable { - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public PolygonOptions createFromParcel(Parcel in) { - return new PolygonOptions(in); - } - - public PolygonOptions[] newArray(int size) { - return new PolygonOptions[size]; - } + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public PolygonOptions createFromParcel(Parcel in) { + return new PolygonOptions(in); + } + + public PolygonOptions[] newArray(int size) { + return new PolygonOptions[size]; + } }; - private PolygonOptions(Parcel in) { - polygon = new Polygon(); - ArrayList pointsList = new ArrayList<>(); - in.readList(pointsList, LatLng.class.getClassLoader()); - addAll(pointsList); - alpha(in.readFloat()); - fillColor(in.readInt()); - strokeColor(in.readInt()); - } - - /** - * Describe the kinds of special objects contained in this Parcelable's - * marshalled representation. - * - * @return integer 0. - */ - @Override - public int describeContents() { - return 0; - } - - /** - * Flatten this object in to a Parcel. - * - * @param out The Parcel in which the object should be written. - * @param flags Additional flags about how the object should be written. May be 0 or - * {@link #PARCELABLE_WRITE_RETURN_VALUE}. - */ - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeList(getPoints()); - out.writeFloat(getAlpha()); - out.writeInt(getFillColor()); - out.writeInt(getStrokeColor()); - } - - private Polygon polygon; - - /** - * Defines options for a polygon. - */ - public PolygonOptions() { - polygon = new Polygon(); - } - - /** - * Adds a vertex to the outline of the polygon being built. - * - * @param point {@link LatLng} point to be added to polygon geometry. - * @return This {@link PolygonOptions} object with the given point added to the outline. - */ - public PolygonOptions add(LatLng point) { - polygon.addPoint(point); - return this; - } - - /** - * Adds vertices to the outline of the polygon being built. - * - * @param points {@link LatLng} points to be added to polygon geometry. - * @return This {@link PolygonOptions} object with the given points added to the outline. - */ - public PolygonOptions add(LatLng... points) { - for (LatLng point : points) { - add(point); - } - return this; - } - - /** - * Adds vertices to the outline of the polygon being built. - * - * @param points {@link Iterable} list made up of {@link LatLng} points defining the polygon - * geometry - * @return This {@link PolygonOptions} object with the given points added to the outline. - */ - public PolygonOptions addAll(Iterable points) { - for (LatLng point : points) { - add(point); - } - return this; - } - - /** - * Set the alpha value of the polyline. - * - * @param alpha float value between 0 (not visible) and 1. - * @return This {@link PolygonOptions} object with the given polygon alpha value. - */ - public PolygonOptions alpha(float alpha) { - polygon.setAlpha(alpha); - return this; - } - - /** - * Gets the alpha set for this {@link PolygonOptions} object. - * - * @return float value between 0 and 1 defining the alpha. - */ - public float getAlpha() { - return polygon.getAlpha(); - } - - /** - * Specifies the polygon's fill color, as 32-bit ARGB. The default color is black. - * - * @param color 32-bit ARGB color. - * @return This {@link PolylineOptions} object with a new color set. - */ - public PolygonOptions fillColor(int color) { - polygon.setFillColor(color); - return this; - } - - /** - * Gets the fill color set for this {@link PolygonOptions} object. - * - * @return The fill color of the polygon in ARGB format. - */ - public int getFillColor() { - return polygon.getFillColor(); - } - - /** - * Do not use this method. Used internally by the SDK. - * - * @return Polygon the Polygon to return - */ - public Polygon getPolygon() { - return polygon; - } - - /** - * Specifies the polygon's stroke color, as 32-bit ARGB. The default color is black. - * - * @param color 32-bit ARGB color. - * @return This {@link PolygonOptions} object with a new stroke color set. - */ - public PolygonOptions strokeColor(int color) { - polygon.setStrokeColor(color); - return this; - } - - /** - * Gets the stroke color set for this {@link PolygonOptions} object. - * - * @return The stroke color of the polygon in ARGB format. - */ - public int getStrokeColor() { - return polygon.getStrokeColor(); - } - - public List getPoints() { - // the getter gives us a copy, which is the safe thing to do... - return polygon.getPoints(); - } - - /** - * Compares this {@link PolygonOptions} object with another {@link PolygonOptions} and - * determines if their color, alpha, stroke color, and vertices match. - * - * @param o Another {@link PolygonOptions} to compare with this object. - * @return True if color, alpha, stroke color, and vertices match this {@link PolygonOptions} - * object. Else, false. - */ - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - PolygonOptions polygon = (PolygonOptions) o; - - if (Float.compare(polygon.getAlpha(), getAlpha()) != 0) return false; - if (getFillColor() != polygon.getFillColor()) return false; - if (getStrokeColor() != polygon.getStrokeColor()) return false; - return !(getPoints() != null ? !getPoints().equals(polygon.getPoints()) : polygon.getPoints() != null); - } - - /** - * Gives an integer which can be used as the bucket number for storing elements of the set/map. - * This bucket number is the address of the element inside the set/map. There's no guarantee - * that this hash value will be consistent between different Java implementations, or even - * between different execution runs of the same program. - * - * @return integer value you can use for storing element. - */ - @Override - public int hashCode() { - int result = 1; - result = 31 * result + (getAlpha() != +0.0f ? Float.floatToIntBits(getAlpha()) : 0); - result = 31 * result + getFillColor(); - result = 31 * result + getStrokeColor(); - result = 31 * result + (getPoints() != null ? getPoints().hashCode() : 0); - return result; - } + private PolygonOptions(Parcel in) { + polygon = new Polygon(); + ArrayList pointsList = new ArrayList<>(); + in.readList(pointsList, LatLng.class.getClassLoader()); + addAll(pointsList); + alpha(in.readFloat()); + fillColor(in.readInt()); + strokeColor(in.readInt()); + } + + /** + * Describe the kinds of special objects contained in this Parcelable's + * marshalled representation. + * + * @return integer 0. + */ + @Override + public int describeContents() { + return 0; + } + + /** + * Flatten this object in to a Parcel. + * + * @param out The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written. May be 0 or + * {@link #PARCELABLE_WRITE_RETURN_VALUE}. + */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeList(getPoints()); + out.writeFloat(getAlpha()); + out.writeInt(getFillColor()); + out.writeInt(getStrokeColor()); + } + + private Polygon polygon; + + /** + * Defines options for a polygon. + */ + public PolygonOptions() { + polygon = new Polygon(); + } + + /** + * Adds a vertex to the outline of the polygon being built. + * + * @param point {@link LatLng} point to be added to polygon geometry. + * @return This {@link PolygonOptions} object with the given point added to the outline. + */ + public PolygonOptions add(LatLng point) { + polygon.addPoint(point); + return this; + } + + /** + * Adds vertices to the outline of the polygon being built. + * + * @param points {@link LatLng} points to be added to polygon geometry. + * @return This {@link PolygonOptions} object with the given points added to the outline. + */ + public PolygonOptions add(LatLng... points) { + for (LatLng point : points) { + add(point); + } + return this; + } + + /** + * Adds vertices to the outline of the polygon being built. + * + * @param points {@link Iterable} list made up of {@link LatLng} points defining the polygon + * geometry + * @return This {@link PolygonOptions} object with the given points added to the outline. + */ + public PolygonOptions addAll(Iterable points) { + for (LatLng point : points) { + add(point); + } + return this; + } + + /** + * Set the alpha value of the polyline. + * + * @param alpha float value between 0 (not visible) and 1. + * @return This {@link PolygonOptions} object with the given polygon alpha value. + */ + public PolygonOptions alpha(float alpha) { + polygon.setAlpha(alpha); + return this; + } + + /** + * Gets the alpha set for this {@link PolygonOptions} object. + * + * @return float value between 0 and 1 defining the alpha. + */ + public float getAlpha() { + return polygon.getAlpha(); + } + + /** + * Specifies the polygon's fill color, as 32-bit ARGB. The default color is black. + * + * @param color 32-bit ARGB color. + * @return This {@link PolylineOptions} object with a new color set. + */ + public PolygonOptions fillColor(int color) { + polygon.setFillColor(color); + return this; + } + + /** + * Gets the fill color set for this {@link PolygonOptions} object. + * + * @return The fill color of the polygon in ARGB format. + */ + public int getFillColor() { + return polygon.getFillColor(); + } + + /** + * Do not use this method. Used internally by the SDK. + * + * @return Polygon the Polygon to return + */ + public Polygon getPolygon() { + return polygon; + } + + /** + * Specifies the polygon's stroke color, as 32-bit ARGB. The default color is black. + * + * @param color 32-bit ARGB color. + * @return This {@link PolygonOptions} object with a new stroke color set. + */ + public PolygonOptions strokeColor(int color) { + polygon.setStrokeColor(color); + return this; + } + + /** + * Gets the stroke color set for this {@link PolygonOptions} object. + * + * @return The stroke color of the polygon in ARGB format. + */ + public int getStrokeColor() { + return polygon.getStrokeColor(); + } + + public List getPoints() { + // the getter gives us a copy, which is the safe thing to do... + return polygon.getPoints(); + } + + /** + * Compares this {@link PolygonOptions} object with another {@link PolygonOptions} and + * determines if their color, alpha, stroke color, and vertices match. + * + * @param o Another {@link PolygonOptions} to compare with this object. + * @return True if color, alpha, stroke color, and vertices match this {@link PolygonOptions} + * object. Else, false. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + PolygonOptions polygon = (PolygonOptions) o; + + if (Float.compare(polygon.getAlpha(), getAlpha()) != 0) { + return false; + } + if (getFillColor() != polygon.getFillColor()) { + return false; + } + if (getStrokeColor() != polygon.getStrokeColor()) { + return false; + } + return !(getPoints() != null ? !getPoints().equals(polygon.getPoints()) : polygon.getPoints() != null); + } + + /** + * Gives an integer which can be used as the bucket number for storing elements of the set/map. + * This bucket number is the address of the element inside the set/map. There's no guarantee + * that this hash value will be consistent between different Java implementations, or even + * between different execution runs of the same program. + * + * @return integer value you can use for storing element. + */ + @Override + public int hashCode() { + int result = 1; + result = 31 * result + (getAlpha() != +0.0f ? Float.floatToIntBits(getAlpha()) : 0); + result = 31 * result + getFillColor(); + result = 31 * result + getStrokeColor(); + result = 31 * result + (getPoints() != null ? getPoints().hashCode() : 0); + return result; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java index 49d8d5d6e8..a430d11009 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/Polyline.java @@ -9,56 +9,56 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; */ public final class Polyline extends MultiPoint { - private int color = Color.BLACK; // default color is black - private float width = 10; // As specified by Google API Docs (in pixels) + private int color = Color.BLACK; // default color is black + private float width = 10; // As specified by Google API Docs (in pixels) - Polyline() { - super(); - } + Polyline() { + super(); + } - /** - * Gets the color of this polyline. - * - * @return The color in ARGB format. - */ - public int getColor() { - return color; - } + /** + * Gets the color of this polyline. + * + * @return The color in ARGB format. + */ + public int getColor() { + return color; + } - /** - * Gets the width of this polyline. - * - * @return The width in screen pixels. - */ - public float getWidth() { - return width; - } + /** + * Gets the width of this polyline. + * + * @return The width in screen pixels. + */ + public float getWidth() { + return width; + } - /** - * Sets the color of the polyline. - * - * @param color - the color in ARGB format - */ - public void setColor(int color) { - this.color = color; - update(); - } + /** + * Sets the color of the polyline. + * + * @param color - the color in ARGB format + */ + public void setColor(int color) { + this.color = color; + update(); + } - /** - * Sets the width of the polyline. - * - * @param width in pixels - */ - public void setWidth(float width) { - this.width = width; - update(); - } + /** + * Sets the width of the polyline. + * + * @param width in pixels + */ + public void setWidth(float width) { + this.width = width; + update(); + } - @Override - void update() { - MapboxMap mapboxMap = getMapboxMap(); - if (mapboxMap != null) { - mapboxMap.updatePolyline(this); - } + @Override + void update() { + MapboxMap mapboxMap = getMapboxMap(); + if (mapboxMap != null) { + mapboxMap.updatePolyline(this); } + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java index c74f6d196f..ab22109a4e 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/annotations/PolylineOptions.java @@ -14,215 +14,225 @@ import java.util.List; public final class PolylineOptions implements Parcelable { - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public PolylineOptions createFromParcel(Parcel in) { - return new PolylineOptions(in); - } - - public PolylineOptions[] newArray(int size) { - return new PolylineOptions[size]; - } + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public PolylineOptions createFromParcel(Parcel in) { + return new PolylineOptions(in); + } + + public PolylineOptions[] newArray(int size) { + return new PolylineOptions[size]; + } }; - private PolylineOptions(Parcel in) { - polyline = new Polyline(); - ArrayList pointsList = new ArrayList<>(); - in.readList(pointsList, LatLng.class.getClassLoader()); - addAll(pointsList); - alpha(in.readFloat()); - color(in.readInt()); - width(in.readFloat()); - } - - /** - * Describe the kinds of special objects contained in this Parcelable's - * marshalled representation. - * - * @return integer 0. - */ - @Override - public int describeContents() { - return 0; - } - - /** - * Flatten this object in to a Parcel. - * - * @param out The Parcel in which the object should be written. - * @param flags Additional flags about how the object should be written. May be 0 or - * {@link #PARCELABLE_WRITE_RETURN_VALUE}. - */ - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeList(getPoints()); - out.writeFloat(getAlpha()); - out.writeInt(getColor()); - out.writeFloat(getWidth()); - } - - private Polyline polyline; - - /** - * Defines options for a polyline. - */ - public PolylineOptions() { - polyline = new Polyline(); - } - - /** - * Adds a vertex to the end of the polyline being built. - * - * @param point {@link LatLng} point to be added to polyline geometry. - * @return This {@link PolylineOptions} object with the given point on the end. - */ - public PolylineOptions add(LatLng point) { - polyline.addPoint(point); - return this; - } - - /** - * Adds vertices to the end of the polyline being built. - * - * @param points {@link LatLng} points defining the polyline geometry. - * @return This {@link PolylineOptions} object with the given point on the end. - */ - public PolylineOptions add(LatLng... points) { - for (LatLng point : points) { - add(point); - } - return this; - } - - /** - * Adds vertices to the end of the polyline being built. - * - * @param points {@link Iterable} list made up of {@link LatLng} points defining the polyline - * geometry - * @return This {@link PolylineOptions} object with the given points on the end. - */ - public PolylineOptions addAll(Iterable points) { - for (LatLng point : points) { - add(point); - } - return this; - } - - /** - * Set the alpha value of the polyline. - * - * @param alpha float value between 0 (not visible) and 1. - * @return This {@link PolylineOptions} object with the given polyline alpha value. - */ - public PolylineOptions alpha(float alpha) { - polyline.setAlpha(alpha); - return this; - } - - /** - * Gets the alpha set for this {@link PolylineOptions} object. - * - * @return float value between 0 and 1 defining the alpha. - */ - public float getAlpha() { - return polyline.getAlpha(); - } - - /** - * Sets the color of the polyline as a 32-bit ARGB color. The default color is black. - * - * @param color 32-bit ARGB color. - * @return This {@link PolylineOptions} object with a new color set. - */ - public PolylineOptions color(int color) { - polyline.setColor(color); - return this; - } - - /** - * Gets the color set for this {@link PolylineOptions} object. - * - * @return The color of the polyline in ARGB format. - */ - public int getColor() { - return polyline.getColor(); - } - - /** - * Do not use this method. Used internally by the SDK. - * - * @return PolyLine The polyline build by this class. - */ - public Polyline getPolyline() { - return polyline; - } - - /** - * Gets the width set for this {@link PolylineOptions} object. - * - * @return The width of the polyline in screen pixels. - */ - public float getWidth() { - return polyline.getWidth(); - } - - /** - * Sets the width of the polyline in screen pixels. The default is 10. - * - * @param width float value defining width of polyline using unit pixels. - * @return This {@link PolylineOptions} object with a new width set. - */ - public PolylineOptions width(float width) { - polyline.setWidth(width); - return this; - } - - /** - * Gets the points set for this {@link PolylineOptions} object. - * - * @return a {@link List} of {@link LatLng}s specifying the vertices of the polyline. - */ - public List getPoints() { - // the getter gives us a copy, which is the safe thing to do... - return polyline.getPoints(); - } - - /** - * Compares this {@link PolylineOptions} object with another {@link PolylineOptions} and - * determines if their color, alpha, width, and vertices match. - * - * @param o Another {@link PolylineOptions} to compare with this object. - * @return True if color, alpha, width, and vertices match this {@link PolylineOptions} object. - * Else, false. - */ - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - PolylineOptions polyline = (PolylineOptions) o; - - if (Float.compare(polyline.getAlpha(), getAlpha()) != 0) return false; - if (getColor() != polyline.getColor()) return false; - if (Float.compare(polyline.getWidth(), getWidth()) != 0) return false; - return !(getPoints() != null ? !getPoints().equals(polyline.getPoints()) : polyline.getPoints() != null); - } - - /** - * Gives an integer which can be used as the bucket number for storing elements of the set/map. - * This bucket number is the address of the element inside the set/map. There's no guarantee - * that this hash value will be consistent between different Java implementations, or even - * between different execution runs of the same program. - * - * @return integer value you can use for storing element. - */ - @Override - public int hashCode() { - int result = 1; - result = 31 * result + (getAlpha() != +0.0f ? Float.floatToIntBits(getAlpha()) : 0); - result = 31 * result + getColor(); - result = 31 * result + (getWidth() != +0.0f ? Float.floatToIntBits(getWidth()) : 0); - result = 31 * result + (getPoints() != null ? getPoints().hashCode() : 0); - return result; - } + private PolylineOptions(Parcel in) { + polyline = new Polyline(); + ArrayList pointsList = new ArrayList<>(); + in.readList(pointsList, LatLng.class.getClassLoader()); + addAll(pointsList); + alpha(in.readFloat()); + color(in.readInt()); + width(in.readFloat()); + } + + /** + * Describe the kinds of special objects contained in this Parcelable's + * marshalled representation. + * + * @return integer 0. + */ + @Override + public int describeContents() { + return 0; + } + + /** + * Flatten this object in to a Parcel. + * + * @param out The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written. May be 0 or + * {@link #PARCELABLE_WRITE_RETURN_VALUE}. + */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeList(getPoints()); + out.writeFloat(getAlpha()); + out.writeInt(getColor()); + out.writeFloat(getWidth()); + } + + private Polyline polyline; + + /** + * Defines options for a polyline. + */ + public PolylineOptions() { + polyline = new Polyline(); + } + + /** + * Adds a vertex to the end of the polyline being built. + * + * @param point {@link LatLng} point to be added to polyline geometry. + * @return This {@link PolylineOptions} object with the given point on the end. + */ + public PolylineOptions add(LatLng point) { + polyline.addPoint(point); + return this; + } + + /** + * Adds vertices to the end of the polyline being built. + * + * @param points {@link LatLng} points defining the polyline geometry. + * @return This {@link PolylineOptions} object with the given point on the end. + */ + public PolylineOptions add(LatLng... points) { + for (LatLng point : points) { + add(point); + } + return this; + } + + /** + * Adds vertices to the end of the polyline being built. + * + * @param points {@link Iterable} list made up of {@link LatLng} points defining the polyline + * geometry + * @return This {@link PolylineOptions} object with the given points on the end. + */ + public PolylineOptions addAll(Iterable points) { + for (LatLng point : points) { + add(point); + } + return this; + } + + /** + * Set the alpha value of the polyline. + * + * @param alpha float value between 0 (not visible) and 1. + * @return This {@link PolylineOptions} object with the given polyline alpha value. + */ + public PolylineOptions alpha(float alpha) { + polyline.setAlpha(alpha); + return this; + } + + /** + * Gets the alpha set for this {@link PolylineOptions} object. + * + * @return float value between 0 and 1 defining the alpha. + */ + public float getAlpha() { + return polyline.getAlpha(); + } + + /** + * Sets the color of the polyline as a 32-bit ARGB color. The default color is black. + * + * @param color 32-bit ARGB color. + * @return This {@link PolylineOptions} object with a new color set. + */ + public PolylineOptions color(int color) { + polyline.setColor(color); + return this; + } + + /** + * Gets the color set for this {@link PolylineOptions} object. + * + * @return The color of the polyline in ARGB format. + */ + public int getColor() { + return polyline.getColor(); + } + + /** + * Do not use this method. Used internally by the SDK. + * + * @return PolyLine The polyline build by this class. + */ + public Polyline getPolyline() { + return polyline; + } + + /** + * Gets the width set for this {@link PolylineOptions} object. + * + * @return The width of the polyline in screen pixels. + */ + public float getWidth() { + return polyline.getWidth(); + } + + /** + * Sets the width of the polyline in screen pixels. The default is 10. + * + * @param width float value defining width of polyline using unit pixels. + * @return This {@link PolylineOptions} object with a new width set. + */ + public PolylineOptions width(float width) { + polyline.setWidth(width); + return this; + } + + /** + * Gets the points set for this {@link PolylineOptions} object. + * + * @return a {@link List} of {@link LatLng}s specifying the vertices of the polyline. + */ + public List getPoints() { + // the getter gives us a copy, which is the safe thing to do... + return polyline.getPoints(); + } + + /** + * Compares this {@link PolylineOptions} object with another {@link PolylineOptions} and + * determines if their color, alpha, width, and vertices match. + * + * @param o Another {@link PolylineOptions} to compare with this object. + * @return True if color, alpha, width, and vertices match this {@link PolylineOptions} object. + * Else, false. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + + PolylineOptions polyline = (PolylineOptions) o; + + if (Float.compare(polyline.getAlpha(), getAlpha()) != 0) { + return false; + } + if (getColor() != polyline.getColor()) { + return false; + } + if (Float.compare(polyline.getWidth(), getWidth()) != 0) { + return false; + } + return !(getPoints() != null ? !getPoints().equals(polyline.getPoints()) : polyline.getPoints() != null); + } + + /** + * Gives an integer which can be used as the bucket number for storing elements of the set/map. + * This bucket number is the address of the element inside the set/map. There's no guarantee + * that this hash value will be consistent between different Java implementations, or even + * between different execution runs of the same program. + * + * @return integer value you can use for storing element. + */ + @Override + public int hashCode() { + int result = 1; + result = 31 * result + (getAlpha() != +0.0f ? Float.floatToIntBits(getAlpha()) : 0); + result = 31 * result + getColor(); + result = 31 * result + (getWidth() != +0.0f ? Float.floatToIntBits(getWidth()) : 0); + result = 31 * result + (getPoints() != null ? getPoints().hashCode() : 0); + return result; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java index 40e447debe..79045b68bb 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraPosition.java @@ -16,304 +16,304 @@ import static com.mapbox.mapboxsdk.utils.MathUtils.convertNativeBearing; */ public final class CameraPosition implements Parcelable { - public static final CameraPosition DEFAULT = new CameraPosition(new LatLng(), 0, 0, 0); - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public CameraPosition createFromParcel(Parcel in) { - double bearing = in.readDouble(); - LatLng target = in.readParcelable(LatLng.class.getClassLoader()); - double tilt = in.readDouble(); - double zoom = in.readDouble(); - return new CameraPosition(target, zoom, tilt, bearing); - } - - public CameraPosition[] newArray(int size) { - return new CameraPosition[size]; - } + public static final CameraPosition DEFAULT = new CameraPosition(new LatLng(), 0, 0, 0); + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public CameraPosition createFromParcel(Parcel in) { + double bearing = in.readDouble(); + LatLng target = in.readParcelable(LatLng.class.getClassLoader()); + double tilt = in.readDouble(); + double zoom = in.readDouble(); + return new CameraPosition(target, zoom, tilt, bearing); + } + + public CameraPosition[] newArray(int size) { + return new CameraPosition[size]; + } }; + /** + * Direction that the camera is pointing in, in degrees clockwise from north. + */ + public final double bearing; + + /** + * The location that the camera is pointing at. + */ + public final LatLng target; + + /** + * The angle, in degrees, of the camera angle from the nadir (directly facing the Earth). + * See tilt(float) for details of restrictions on the range of values. + */ + public final double tilt; + + /** + * Zoom level near the center of the screen. See zoom(float) for the definition of the camera's + * zoom level. + */ + public final double zoom; + + /** + * Constructs a CameraPosition. + * + * @param target The target location to align with the center of the screen. + * @param zoom Zoom level at target. See zoom(float) for details of restrictions. + * @param tilt The camera angle, in degrees, from the nadir (directly down). See tilt(float) + * for details of restrictions. + * @param bearing Direction that the camera is pointing in, in degrees clockwise from north. + * This value will be normalized to be within 0 degrees inclusive and 360 degrees + * exclusive. + * @throws NullPointerException if target is null + * @throws IllegalArgumentException if tilt is outside the range of 0 to 90 degrees inclusive. + */ + CameraPosition(LatLng target, double zoom, double tilt, double bearing) { + this.target = target; + this.bearing = bearing; + this.tilt = tilt; + this.zoom = zoom; + } + + /** + * Describe the kinds of special objects contained in this Parcelable's + * marshalled representation. + * + * @return integer 0. + */ + @Override + public int describeContents() { + return 0; + } + + /** + * Flatten this object in to a Parcel. + * + * @param out The Parcel in which the object should be written. + * @param flags Additional flags about how the object should be written. May be 0 or + * {@link #PARCELABLE_WRITE_RETURN_VALUE}. + */ + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeDouble(bearing); + out.writeParcelable(target, flags); + out.writeDouble(tilt); + out.writeDouble(zoom); + } + + /** + * Returns a String with the camera target, zoom, bearing and tilt. + * + * @return A String with CameraPosition information. + */ + @Override + public String toString() { + return "Target: " + target + ", Zoom:" + zoom + ", Bearing:" + bearing + ", Tilt:" + tilt; + } + + /** + * Compares this {@link CameraPosition} object with another {@link CameraPosition} and + * determines if their target, zoom, tilt, and bearing match. + * + * @param o Another {@link CameraPosition} to compare with this object. + * @return True if target, zoom, tilt, and bearing match this {@link CameraPosition} object. + * Else, false. + */ + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + + if (o == null || getClass() != o.getClass()) { + return false; + } + + CameraPosition cameraPosition = (CameraPosition) o; + if (target != null && !target.equals(cameraPosition.target)) { + return false; + } else if (zoom != cameraPosition.zoom) { + return false; + } else if (tilt != cameraPosition.tilt) { + return false; + } else if (bearing != cameraPosition.bearing) { + return false; + } + return true; + } + + /** + * Gives an integer which can be used as the bucket number for storing elements of the set/map. + * This bucket number is the address of the element inside the set/map. There's no guarantee + * that this hash value will be consistent between different Java implementations, or even + * between different execution runs of the same program. + * + * @return integer value you can use for storing element. + */ + @Override + public int hashCode() { + int result = 1; + result = 31 * result + (target != null ? target.hashCode() : 0); + return result; + } + + /** + * Builder for composing {@link CameraPosition} objects. + */ + public static final class Builder { + + private double bearing = -1; + private LatLng target = null; + private double tilt = -1; + private double zoom = -1; + /** - * Direction that the camera is pointing in, in degrees clockwise from north. + * Creates an empty builder. */ - public final double bearing; + public Builder() { + super(); + } /** - * The location that the camera is pointing at. + * Create Builder with an existing CameraPosition data. + * + * @param previous Existing CameraPosition values to use */ - public final LatLng target; + public Builder(CameraPosition previous) { + super(); + if (previous != null) { + this.bearing = previous.bearing; + this.target = previous.target; + this.tilt = previous.tilt; + this.zoom = previous.zoom; + } + } /** - * The angle, in degrees, of the camera angle from the nadir (directly facing the Earth). - * See tilt(float) for details of restrictions on the range of values. + * Create Builder with an existing CameraPosition data. + * + * @param typedArray TypedArray containgin attribute values */ - public final double tilt; + public Builder(TypedArray typedArray) { + super(); + if (typedArray != null) { + this.bearing = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraBearing, 0.0f); + double lat = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraTargetLat, 0.0f); + double lng = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraTargetLng, 0.0f); + this.target = new LatLng(lat, lng); + this.tilt = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraTilt, 0.0f); + this.zoom = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraZoom, 0.0f); + } + } /** - * Zoom level near the center of the screen. See zoom(float) for the definition of the camera's - * zoom level. + * Create Builder from an existing CameraPositionUpdate update. + * + * @param update Update containing camera options */ - public final double zoom; + public Builder(CameraUpdateFactory.CameraPositionUpdate update) { + super(); + if (update != null) { + bearing = update.getBearing(); + target = update.getTarget(); + tilt = update.getTilt(); + zoom = update.getZoom(); + } + } /** - * Constructs a CameraPosition. + * Create Builder from an existing CameraPositionUpdate update. * - * @param target The target location to align with the center of the screen. - * @param zoom Zoom level at target. See zoom(float) for details of restrictions. - * @param tilt The camera angle, in degrees, from the nadir (directly down). See tilt(float) - * for details of restrictions. - * @param bearing Direction that the camera is pointing in, in degrees clockwise from north. - * This value will be normalized to be within 0 degrees inclusive and 360 degrees - * exclusive. - * @throws NullPointerException if target is null - * @throws IllegalArgumentException if tilt is outside the range of 0 to 90 degrees inclusive. + * @param update Update containing camera options */ - CameraPosition(LatLng target, double zoom, double tilt, double bearing) { - this.target = target; - this.bearing = bearing; - this.tilt = tilt; - this.zoom = zoom; + public Builder(CameraUpdateFactory.ZoomUpdate update) { + super(); + if (update != null) { + this.zoom = update.getZoom(); + } } /** - * Describe the kinds of special objects contained in this Parcelable's - * marshalled representation. + * Create Builder from an existing array of doubles. + *

+ * These values conform to map.ccp representation of a camera position. + *

* - * @return integer 0. + * @param nativeCameraValues Values containing target, bearing, tilt and zoom */ - @Override - public int describeContents() { - return 0; + public Builder(double[] nativeCameraValues) { + super(); + if (nativeCameraValues != null && nativeCameraValues.length == 5) { + target(new LatLng(nativeCameraValues[0], nativeCameraValues[1])); + bearing(convertNativeBearing(nativeCameraValues[2])); + tilt(nativeCameraValues[3]); + zoom(nativeCameraValues[4]); + } } /** - * Flatten this object in to a Parcel. + * Sets the direction that the camera is pointing in, in degrees clockwise from north. * - * @param out The Parcel in which the object should be written. - * @param flags Additional flags about how the object should be written. May be 0 or - * {@link #PARCELABLE_WRITE_RETURN_VALUE}. + * @param bearing Bearing + * @return Builder */ - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeDouble(bearing); - out.writeParcelable(target, flags); - out.writeDouble(tilt); - out.writeDouble(zoom); + public Builder bearing(double bearing) { + double direction = bearing; + + while (direction >= 360) { + direction -= 360; + } + while (direction < 0) { + direction += 360; + } + + this.bearing = direction; + return this; } /** - * Returns a String with the camera target, zoom, bearing and tilt. + * Builds a CameraPosition. * - * @return A String with CameraPosition information. + * @return CameraPosition */ - @Override - public String toString() { - return "Target: " + target + ", Zoom:" + zoom + ", Bearing:" + bearing + ", Tilt:" + tilt; + public CameraPosition build() { + return new CameraPosition(target, zoom, tilt, bearing); } /** - * Compares this {@link CameraPosition} object with another {@link CameraPosition} and - * determines if their target, zoom, tilt, and bearing match. + * Sets the location that the camera is pointing at. * - * @param o Another {@link CameraPosition} to compare with this object. - * @return True if target, zoom, tilt, and bearing match this {@link CameraPosition} object. - * Else, false. + * @param location Location + * @return Builder */ - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - - if (o == null || getClass() != o.getClass()) { - return false; - } - - CameraPosition cameraPosition = (CameraPosition) o; - if (target != null && !target.equals(cameraPosition.target)) { - return false; - } else if (zoom != cameraPosition.zoom) { - return false; - } else if (tilt != cameraPosition.tilt) { - return false; - } else if (bearing != cameraPosition.bearing) { - return false; - } - return true; + public Builder target(LatLng location) { + this.target = location; + return this; } /** - * Gives an integer which can be used as the bucket number for storing elements of the set/map. - * This bucket number is the address of the element inside the set/map. There's no guarantee - * that this hash value will be consistent between different Java implementations, or even - * between different execution runs of the same program. + * Set the tilt in degrees + *

+ * value is clamped to 0 and 60. + *

* - * @return integer value you can use for storing element. + * @param tilt Tilt value + * @return Builder */ - @Override - public int hashCode() { - int result = 1; - result = 31 * result + (target != null ? target.hashCode() : 0); - return result; + public Builder tilt(double tilt) { + this.tilt = MathUtils.clamp(tilt, MapboxConstants.MINIMUM_TILT, MapboxConstants.MAXIMUM_TILT); + return this; } /** - * Builder for composing {@link CameraPosition} objects. + * Set the zoom + * + * @param zoom Zoom value + * @return Builder */ - public static final class Builder { - - private double bearing = -1; - private LatLng target = null; - private double tilt = -1; - private double zoom = -1; - - /** - * Creates an empty builder. - */ - public Builder() { - super(); - } - - /** - * Create Builder with an existing CameraPosition data. - * - * @param previous Existing CameraPosition values to use - */ - public Builder(CameraPosition previous) { - super(); - if (previous != null) { - this.bearing = previous.bearing; - this.target = previous.target; - this.tilt = previous.tilt; - this.zoom = previous.zoom; - } - } - - /** - * Create Builder with an existing CameraPosition data. - * - * @param typedArray TypedArray containgin attribute values - */ - public Builder(TypedArray typedArray) { - super(); - if (typedArray != null) { - this.bearing = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraBearing, 0.0f); - double lat = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraTargetLat, 0.0f); - double lng = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraTargetLng, 0.0f); - this.target = new LatLng(lat, lng); - this.tilt = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraTilt, 0.0f); - this.zoom = typedArray.getFloat(R.styleable.mapbox_MapView_mapbox_cameraZoom, 0.0f); - } - } - - /** - * Create Builder from an existing CameraPositionUpdate update. - * - * @param update Update containing camera options - */ - public Builder(CameraUpdateFactory.CameraPositionUpdate update) { - super(); - if (update != null) { - bearing = update.getBearing(); - target = update.getTarget(); - tilt = update.getTilt(); - zoom = update.getZoom(); - } - } - - /** - * Create Builder from an existing CameraPositionUpdate update. - * - * @param update Update containing camera options - */ - public Builder(CameraUpdateFactory.ZoomUpdate update) { - super(); - if (update != null) { - this.zoom = update.getZoom(); - } - } - - /** - * Create Builder from an existing array of doubles. - *

- * These values conform to map.ccp representation of a camera position. - *

- * - * @param nativeCameraValues Values containing target, bearing, tilt and zoom - */ - public Builder(double[] nativeCameraValues) { - super(); - if (nativeCameraValues != null && nativeCameraValues.length == 5) { - target(new LatLng(nativeCameraValues[0], nativeCameraValues[1])); - bearing(convertNativeBearing(nativeCameraValues[2])); - tilt(nativeCameraValues[3]); - zoom(nativeCameraValues[4]); - } - } - - /** - * Sets the direction that the camera is pointing in, in degrees clockwise from north. - * - * @param bearing Bearing - * @return Builder - */ - public Builder bearing(double bearing) { - double direction = bearing; - - while (direction >= 360) { - direction -= 360; - } - while (direction < 0) { - direction += 360; - } - - this.bearing = direction; - return this; - } - - /** - * Builds a CameraPosition. - * - * @return CameraPosition - */ - public CameraPosition build() { - return new CameraPosition(target, zoom, tilt, bearing); - } - - /** - * Sets the location that the camera is pointing at. - * - * @param location Location - * @return Builder - */ - public Builder target(LatLng location) { - this.target = location; - return this; - } - - /** - * Set the tilt in degrees - *

- * value is clamped to 0 and 60. - *

- * - * @param tilt Tilt value - * @return Builder - */ - public Builder tilt(double tilt) { - this.tilt = MathUtils.clamp(tilt, MapboxConstants.MINIMUM_TILT, MapboxConstants.MAXIMUM_TILT); - return this; - } - - /** - * Set the zoom - * - * @param zoom Zoom value - * @return Builder - */ - public Builder zoom(double zoom) { - this.zoom = zoom; - return this; - } + public Builder zoom(double zoom) { + this.zoom = zoom; + return this; } + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java index 94ee4912ce..7e0dbf08fb 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdate.java @@ -9,6 +9,6 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; */ public interface CameraUpdate { - CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap); + CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java index d568b9637d..aecc51530b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/camera/CameraUpdateFactory.java @@ -21,395 +21,397 @@ import java.lang.annotation.RetentionPolicy; */ public final class CameraUpdateFactory { - /** - * Returns a CameraUpdate that moves the camera to a specified CameraPosition. - * - * @param cameraPosition Camera Position to change to - * @return CameraUpdate Final Camera Position - */ - public static CameraUpdate newCameraPosition(@NonNull CameraPosition cameraPosition) { - return new CameraPositionUpdate(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom); + /** + * Returns a CameraUpdate that moves the camera to a specified CameraPosition. + * + * @param cameraPosition Camera Position to change to + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate newCameraPosition(@NonNull CameraPosition cameraPosition) { + return new CameraPositionUpdate(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, + cameraPosition.zoom); + } + + /** + * Returns a CameraUpdate that moves the center of the screen to a latitude and longitude + * specified by a LatLng object. This centers the camera on the LatLng object. + * + * @param latLng Target location to change to + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate newLatLng(@NonNull LatLng latLng) { + return new CameraPositionUpdate(-1, latLng, -1, -1); + } + + /** + * Returns a {@link CameraUpdate} that transforms the camera such that the specified + * latitude/longitude bounds are centered on screen at the greatest possible zoom level. + * You can specify padding, in order to inset the bounding box from the map view's edges. + * The returned CameraUpdate has a bearing of 0 and a tilt of 0. + * + * @param bounds Bounds to match Camera position with + * @param padding Padding added to the bounds + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate newLatLngBounds(@NonNull LatLngBounds bounds, int padding) { + return newLatLngBounds(bounds, padding, padding, padding, padding); + } + + /** + * Returns a {@link CameraUpdate} that transforms the camera such that the specified + * latitude/longitude bounds are centered on screen at the greatest possible zoom level. + * You can specify padding, in order to inset the bounding box from the map view's edges. + * The returned CameraUpdate has a bearing of 0 and a tilt of 0. + * + * @param bounds Bounds to base the Camera position out of + * @param paddingLeft Padding left of the bounds + * @param paddingTop Padding top of the bounds + * @param paddingRight Padding right of the bounds + * @param paddingBottom Padding bottom of the bounds + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate newLatLngBounds(@NonNull LatLngBounds bounds, int paddingLeft, int paddingTop, + int paddingRight, int paddingBottom) { + return new CameraBoundsUpdate(bounds, paddingLeft, paddingTop, paddingRight, paddingBottom); + } + + /** + * Returns a CameraUpdate that moves the center of the screen to a latitude and longitude + * specified by a LatLng object, and moves to the given zoom level. + * + * @param latLng Target location to change to + * @param zoom Zoom level to change to + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate newLatLngZoom(@NonNull LatLng latLng, double zoom) { + return new CameraPositionUpdate(-1, latLng, -1, zoom); + } + + /** + * Returns a CameraUpdate that scrolls the camera over the map, + * shifting the center of view by the specified number of pixels in the x and y directions. + * + * @param xPixel Amount of pixels to scroll to in x direction + * @param yPixel Amount of pixels to scroll to in y direction + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate scrollBy(float xPixel, float yPixel) { + return new CameraMoveUpdate(xPixel, yPixel); + } + + /** + * Returns a CameraUpdate that shifts the zoom level of the current camera viewpoint. + * + * @param amount Amount of zoom level to change with + * @param focus Focus point of zoom + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate zoomBy(double amount, Point focus) { + return new ZoomUpdate(amount, focus.x, focus.y); + } + + /** + * Returns a CameraUpdate that shifts the zoom level of the current camera viewpoint. + * + * @param amount Amount of zoom level to change with + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate zoomBy(double amount) { + return new ZoomUpdate(ZoomUpdate.ZOOM_BY, amount); + } + + /** + * Returns a CameraUpdate that zooms in on the map by moving the viewpoint's height closer to + * the Earth's surface. The zoom increment is 1.0. + * + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate zoomIn() { + return new ZoomUpdate(ZoomUpdate.ZOOM_IN); + } + + /** + * Returns a CameraUpdate that zooms out on the map by moving the viewpoint's height farther + * away from the Earth's surface. The zoom increment is -1.0. + * + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate zoomOut() { + return new ZoomUpdate(ZoomUpdate.ZOOM_OUT); + } + + /** + * Returns a CameraUpdate that moves the camera viewpoint to a particular zoom level. + * + * @param zoom Zoom level to change to + * @return CameraUpdate Final Camera Position + */ + public static CameraUpdate zoomTo(double zoom) { + return new ZoomUpdate(ZoomUpdate.ZOOM_TO, zoom); + } + + // + // CameraUpdate types + // + + static final class CameraPositionUpdate implements CameraUpdate { + + private final double bearing; + private final LatLng target; + private final double tilt; + private final double zoom; + + CameraPositionUpdate(double bearing, LatLng target, double tilt, double zoom) { + this.bearing = bearing; + this.target = target; + this.tilt = tilt; + this.zoom = zoom; } - /** - * Returns a CameraUpdate that moves the center of the screen to a latitude and longitude - * specified by a LatLng object. This centers the camera on the LatLng object. - * - * @param latLng Target location to change to - * @return CameraUpdate Final Camera Position - */ - public static CameraUpdate newLatLng(@NonNull LatLng latLng) { - return new CameraPositionUpdate(-1, latLng, -1, -1); + public LatLng getTarget() { + return target; } - /** - * Returns a {@link CameraUpdate} that transforms the camera such that the specified - * latitude/longitude bounds are centered on screen at the greatest possible zoom level. - * You can specify padding, in order to inset the bounding box from the map view's edges. - * The returned CameraUpdate has a bearing of 0 and a tilt of 0. - * - * @param bounds Bounds to match Camera position with - * @param padding Padding added to the bounds - * @return CameraUpdate Final Camera Position - */ - public static CameraUpdate newLatLngBounds(@NonNull LatLngBounds bounds, int padding) { - return newLatLngBounds(bounds, padding, padding, padding, padding); + public double getBearing() { + return bearing; } - /** - * Returns a {@link CameraUpdate} that transforms the camera such that the specified - * latitude/longitude bounds are centered on screen at the greatest possible zoom level. - * You can specify padding, in order to inset the bounding box from the map view's edges. - * The returned CameraUpdate has a bearing of 0 and a tilt of 0. - * - * @param bounds Bounds to base the Camera position out of - * @param paddingLeft Padding left of the bounds - * @param paddingTop Padding top of the bounds - * @param paddingRight Padding right of the bounds - * @param paddingBottom Padding bottom of the bounds - * @return CameraUpdate Final Camera Position - */ - public static CameraUpdate newLatLngBounds(@NonNull LatLngBounds bounds, int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) { - return new CameraBoundsUpdate(bounds, paddingLeft, paddingTop, paddingRight, paddingBottom); + public double getTilt() { + return tilt; } - /** - * Returns a CameraUpdate that moves the center of the screen to a latitude and longitude - * specified by a LatLng object, and moves to the given zoom level. - * - * @param latLng Target location to change to - * @param zoom Zoom level to change to - * @return CameraUpdate Final Camera Position - */ - public static CameraUpdate newLatLngZoom(@NonNull LatLng latLng, double zoom) { - return new CameraPositionUpdate(-1, latLng, -1, zoom); + public double getZoom() { + return zoom; } - /** - * Returns a CameraUpdate that scrolls the camera over the map, - * shifting the center of view by the specified number of pixels in the x and y directions. - * - * @param xPixel Amount of pixels to scroll to in x direction - * @param yPixel Amount of pixels to scroll to in y direction - * @return CameraUpdate Final Camera Position - */ - public static CameraUpdate scrollBy(float xPixel, float yPixel) { - return new CameraMoveUpdate(xPixel, yPixel); + @Override + public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { + CameraPosition previousPosition = mapboxMap.getCameraPosition(); + if (target == null) { + return new CameraPosition.Builder(this) + .target(previousPosition.target) + .build(); + } + return new CameraPosition.Builder(this).build(); } + } - /** - * Returns a CameraUpdate that shifts the zoom level of the current camera viewpoint. - * - * @param amount Amount of zoom level to change with - * @param focus Focus point of zoom - * @return CameraUpdate Final Camera Position - */ - public static CameraUpdate zoomBy(double amount, Point focus) { - return new ZoomUpdate(amount, focus.x, focus.y); + static final class CameraBoundsUpdate implements CameraUpdate { + + private LatLngBounds bounds; + private RectF padding; + + CameraBoundsUpdate(LatLngBounds bounds, RectF padding) { + this.bounds = bounds; + this.padding = padding; } - /** - * Returns a CameraUpdate that shifts the zoom level of the current camera viewpoint. - * - * @param amount Amount of zoom level to change with - * @return CameraUpdate Final Camera Position - */ - public static CameraUpdate zoomBy(double amount) { - return new ZoomUpdate(ZoomUpdate.ZOOM_BY, amount); + CameraBoundsUpdate(LatLngBounds bounds, int[] padding) { + this(bounds, new RectF(padding[0], padding[1], padding[2], padding[3])); } - /** - * Returns a CameraUpdate that zooms in on the map by moving the viewpoint's height closer to - * the Earth's surface. The zoom increment is 1.0. - * - * @return CameraUpdate Final Camera Position - */ - public static CameraUpdate zoomIn() { - return new ZoomUpdate(ZoomUpdate.ZOOM_IN); + CameraBoundsUpdate(LatLngBounds bounds, int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) { + this(bounds, new int[] {paddingLeft, paddingTop, paddingRight, paddingBottom}); } - /** - * Returns a CameraUpdate that zooms out on the map by moving the viewpoint's height farther - * away from the Earth's surface. The zoom increment is -1.0. - * - * @return CameraUpdate Final Camera Position - */ - public static CameraUpdate zoomOut() { - return new ZoomUpdate(ZoomUpdate.ZOOM_OUT); + public LatLngBounds getBounds() { + return bounds; + } + + public RectF getPadding() { + return padding; + } + + @Override + public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { + // Get required objects + Projection projection = mapboxMap.getProjection(); + UiSettings uiSettings = mapboxMap.getUiSettings(); + + // calculate correct padding + int[] mapPadding = mapboxMap.getPadding(); + RectF latLngPadding = getPadding(); + RectF padding = new RectF(latLngPadding.left + mapPadding[0], + latLngPadding.top + mapPadding[1], + latLngPadding.right + mapPadding[2], + latLngPadding.bottom + mapPadding[3]); + + // Calculate the bounds of the possibly rotated shape with respect to the viewport + PointF nePixel = new PointF(-Float.MAX_VALUE, -Float.MAX_VALUE); + PointF swPixel = new PointF(Float.MAX_VALUE, Float.MAX_VALUE); + float viewportHeight = uiSettings.getHeight(); + for (LatLng latLng : getBounds().toLatLngs()) { + PointF pixel = projection.toScreenLocation(latLng); + swPixel.x = Math.min(swPixel.x, pixel.x); + nePixel.x = Math.max(nePixel.x, pixel.x); + swPixel.y = Math.min(swPixel.y, viewportHeight - pixel.y); + nePixel.y = Math.max(nePixel.y, viewportHeight - pixel.y); + } + + // Calculate width/height + float width = nePixel.x - swPixel.x; + float height = nePixel.y - swPixel.y; + + double zoom = 0; + float minScale = 1; + // Calculate the zoom level + if (padding != null) { + float scaleX = (uiSettings.getWidth() - padding.left - padding.right) / width; + float scaleY = (uiSettings.getHeight() - padding.top - padding.bottom) / height; + minScale = scaleX < scaleY ? scaleX : scaleY; + zoom = calculateZoom(mapboxMap, minScale); + zoom = MathUtils.clamp(zoom, mapboxMap.getMinZoomLevel(), mapboxMap.getMaxZoomLevel()); + } + + // Calculate the center point + PointF paddedNEPixel = new PointF(nePixel.x + padding.right / minScale, nePixel.y + padding.top / minScale); + PointF paddedSWPixel = new PointF(swPixel.x - padding.left / minScale, swPixel.y - padding.bottom / minScale); + PointF centerPixel = new PointF((paddedNEPixel.x + paddedSWPixel.x) / 2, (paddedNEPixel.y + paddedSWPixel.y) / 2); + centerPixel.y = viewportHeight - centerPixel.y; + LatLng center = projection.fromScreenLocation(centerPixel); + + return new CameraPosition.Builder() + .target(center) + .zoom(zoom) + .tilt(0) + .bearing(0) + .build(); } /** - * Returns a CameraUpdate that moves the camera viewpoint to a particular zoom level. + * Calculates a zoom level based on minimum scale and current scale from MapView * - * @param zoom Zoom level to change to - * @return CameraUpdate Final Camera Position + * @param minScale The minimum scale to calculate the zoom level. + * @return zoom level that fits the MapView. */ - public static CameraUpdate zoomTo(double zoom) { - return new ZoomUpdate(ZoomUpdate.ZOOM_TO, zoom); + public double calculateZoom(MapboxMap mapboxMap, float minScale) { + return Math.log(mapboxMap.getCameraPosition().zoom * minScale) / Math.log(2); + } + } + + static final class CameraMoveUpdate implements CameraUpdate { + + private float x; + private float y; + + CameraMoveUpdate(float x, float y) { + this.x = x; + this.y = y; + } + + @Override + public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { + UiSettings uiSettings = mapboxMap.getUiSettings(); + Projection projection = mapboxMap.getProjection(); + + // Calculate the new center point + float viewPortWidth = uiSettings.getWidth(); + float viewPortHeight = uiSettings.getHeight(); + PointF targetPoint = new PointF(viewPortWidth / 2 + x, viewPortHeight / 2 + y); + + // Convert point to LatLng + LatLng latLng = projection.fromScreenLocation(targetPoint); + + CameraPosition previousPosition = mapboxMap.getCameraPosition(); + return new CameraPosition.Builder() + .target(latLng != null ? latLng : previousPosition.target) + .zoom(previousPosition.zoom) + .tilt(previousPosition.tilt) + .bearing(previousPosition.bearing) + .build(); + } + } + + static final class ZoomUpdate implements CameraUpdate { + + @IntDef( {ZOOM_IN, ZOOM_OUT, ZOOM_BY, ZOOM_TO, ZOOM_TO_POINT}) + @Retention(RetentionPolicy.SOURCE) + @interface Type { + } + + static final int ZOOM_IN = 0; + static final int ZOOM_OUT = 1; + static final int ZOOM_BY = 2; + static final int ZOOM_TO = 3; + static final int ZOOM_TO_POINT = 4; + + @Type + private final int type; + private final double zoom; + private float x; + private float y; + + ZoomUpdate(@Type int type) { + this.type = type; + this.zoom = 0; + } + + ZoomUpdate(@Type int type, double zoom) { + this.type = type; + this.zoom = zoom; + } + + ZoomUpdate(double zoom, float x, float y) { + this.type = ZOOM_TO_POINT; + this.zoom = zoom; + this.x = x; + this.y = y; + } + + public double getZoom() { + return zoom; + } + + @Type + public int getType() { + return type; } - // - // CameraUpdate types - // - - static final class CameraPositionUpdate implements CameraUpdate { - - private final double bearing; - private final LatLng target; - private final double tilt; - private final double zoom; - - CameraPositionUpdate(double bearing, LatLng target, double tilt, double zoom) { - this.bearing = bearing; - this.target = target; - this.tilt = tilt; - this.zoom = zoom; - } - - public LatLng getTarget() { - return target; - } - - public double getBearing() { - return bearing; - } - - public double getTilt() { - return tilt; - } - - public double getZoom() { - return zoom; - } - - @Override - public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { - CameraPosition previousPosition = mapboxMap.getCameraPosition(); - if (target == null) { - return new CameraPosition.Builder(this) - .target(previousPosition.target) - .build(); - } - return new CameraPosition.Builder(this).build(); - } + public float getX() { + return x; } - static final class CameraBoundsUpdate implements CameraUpdate { - - private LatLngBounds bounds; - private RectF padding; - - CameraBoundsUpdate(LatLngBounds bounds, RectF padding) { - this.bounds = bounds; - this.padding = padding; - } - - CameraBoundsUpdate(LatLngBounds bounds, int[] padding) { - this(bounds, new RectF(padding[0], padding[1], padding[2], padding[3])); - } - - CameraBoundsUpdate(LatLngBounds bounds, int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) { - this(bounds, new int[]{paddingLeft, paddingTop, paddingRight, paddingBottom}); - } - - public LatLngBounds getBounds() { - return bounds; - } - - public RectF getPadding() { - return padding; - } - - @Override - public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { - // Get required objects - Projection projection = mapboxMap.getProjection(); - UiSettings uiSettings = mapboxMap.getUiSettings(); - - // calculate correct padding - int[] mapPadding = mapboxMap.getPadding(); - RectF latLngPadding = getPadding(); - RectF padding = new RectF(latLngPadding.left + mapPadding[0], - latLngPadding.top + mapPadding[1], - latLngPadding.right + mapPadding[2], - latLngPadding.bottom + mapPadding[3]); - - // Calculate the bounds of the possibly rotated shape with respect to the viewport - PointF nePixel = new PointF(-Float.MAX_VALUE, -Float.MAX_VALUE); - PointF swPixel = new PointF(Float.MAX_VALUE, Float.MAX_VALUE); - float viewportHeight = uiSettings.getHeight(); - for (LatLng latLng : getBounds().toLatLngs()) { - PointF pixel = projection.toScreenLocation(latLng); - swPixel.x = Math.min(swPixel.x, pixel.x); - nePixel.x = Math.max(nePixel.x, pixel.x); - swPixel.y = Math.min(swPixel.y, viewportHeight - pixel.y); - nePixel.y = Math.max(nePixel.y, viewportHeight - pixel.y); - } - - // Calculate width/height - float width = nePixel.x - swPixel.x; - float height = nePixel.y - swPixel.y; - - double zoom = 0; - float minScale = 1; - // Calculate the zoom level - if (padding != null) { - float scaleX = (uiSettings.getWidth() - padding.left - padding.right) / width; - float scaleY = (uiSettings.getHeight() - padding.top - padding.bottom) / height; - minScale = scaleX < scaleY ? scaleX : scaleY; - zoom = calculateZoom(mapboxMap, minScale); - zoom = MathUtils.clamp(zoom, mapboxMap.getMinZoomLevel(), mapboxMap.getMaxZoomLevel()); - } - - // Calculate the center point - PointF paddedNEPixel = new PointF(nePixel.x + padding.right / minScale, nePixel.y + padding.top / minScale); - PointF paddedSWPixel = new PointF(swPixel.x - padding.left / minScale, swPixel.y - padding.bottom / minScale); - PointF centerPixel = new PointF((paddedNEPixel.x + paddedSWPixel.x) / 2, (paddedNEPixel.y + paddedSWPixel.y) / 2); - centerPixel.y = viewportHeight - centerPixel.y; - LatLng center = projection.fromScreenLocation(centerPixel); - - return new CameraPosition.Builder() - .target(center) - .zoom(zoom) - .tilt(0) - .bearing(0) - .build(); - } - - /** - * Calculates a zoom level based on minimum scale and current scale from MapView - * - * @param minScale The minimum scale to calculate the zoom level. - * @return zoom level that fits the MapView. - */ - public double calculateZoom(MapboxMap mapboxMap, float minScale) { - return Math.log(mapboxMap.getCameraPosition().zoom * minScale) / Math.log(2); - } + public float getY() { + return y; } - static final class CameraMoveUpdate implements CameraUpdate { - - private float x; - private float y; - - CameraMoveUpdate(float x, float y) { - this.x = x; - this.y = y; - } - - @Override - public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { - UiSettings uiSettings = mapboxMap.getUiSettings(); - Projection projection = mapboxMap.getProjection(); - - // Calculate the new center point - float viewPortWidth = uiSettings.getWidth(); - float viewPortHeight = uiSettings.getHeight(); - PointF targetPoint = new PointF(viewPortWidth / 2 + x, viewPortHeight / 2 + y); - - // Convert point to LatLng - LatLng latLng = projection.fromScreenLocation(targetPoint); - - CameraPosition previousPosition = mapboxMap.getCameraPosition(); - return new CameraPosition.Builder() - .target(latLng != null ? latLng : previousPosition.target) - .zoom(previousPosition.zoom) - .tilt(previousPosition.tilt) - .bearing(previousPosition.bearing) - .build(); - } + double transformZoom(double currentZoom) { + switch (getType()) { + case CameraUpdateFactory.ZoomUpdate.ZOOM_IN: + currentZoom++; + break; + case CameraUpdateFactory.ZoomUpdate.ZOOM_OUT: + currentZoom--; + if (currentZoom < 0) { + currentZoom = 0; + } + break; + case CameraUpdateFactory.ZoomUpdate.ZOOM_TO: + currentZoom = getZoom(); + break; + case CameraUpdateFactory.ZoomUpdate.ZOOM_BY: + currentZoom = currentZoom + getZoom(); + break; + case CameraUpdateFactory.ZoomUpdate.ZOOM_TO_POINT: + currentZoom = currentZoom + getZoom(); + break; + } + return currentZoom; } - static final class ZoomUpdate implements CameraUpdate { - - @IntDef({ZOOM_IN, ZOOM_OUT, ZOOM_BY, ZOOM_TO, ZOOM_TO_POINT}) - @Retention(RetentionPolicy.SOURCE) - @interface Type { - } - - static final int ZOOM_IN = 0; - static final int ZOOM_OUT = 1; - static final int ZOOM_BY = 2; - static final int ZOOM_TO = 3; - static final int ZOOM_TO_POINT = 4; - - @Type - private final int type; - private final double zoom; - private float x; - private float y; - - ZoomUpdate(@Type int type) { - this.type = type; - this.zoom = 0; - } - - ZoomUpdate(@Type int type, double zoom) { - this.type = type; - this.zoom = zoom; - } - - ZoomUpdate(double zoom, float x, float y) { - this.type = ZOOM_TO_POINT; - this.zoom = zoom; - this.x = x; - this.y = y; - } - - public double getZoom() { - return zoom; - } - - @Type - public int getType() { - return type; - } - - public float getX() { - return x; - } - - public float getY() { - return y; - } - - double transformZoom(double currentZoom) { - switch (getType()) { - case CameraUpdateFactory.ZoomUpdate.ZOOM_IN: - currentZoom++; - break; - case CameraUpdateFactory.ZoomUpdate.ZOOM_OUT: - currentZoom--; - if (currentZoom < 0) { - currentZoom = 0; - } - break; - case CameraUpdateFactory.ZoomUpdate.ZOOM_TO: - currentZoom = getZoom(); - break; - case CameraUpdateFactory.ZoomUpdate.ZOOM_BY: - currentZoom = currentZoom + getZoom(); - break; - case CameraUpdateFactory.ZoomUpdate.ZOOM_TO_POINT: - currentZoom = currentZoom + getZoom(); - break; - } - return currentZoom; - } - - @Override - public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { - CameraPosition cameraPosition = mapboxMap.getCameraPosition(); - if (getType() != CameraUpdateFactory.ZoomUpdate.ZOOM_TO_POINT) { - return new CameraPosition.Builder(cameraPosition) - .zoom(transformZoom(cameraPosition.zoom)) - .build(); - } else { - return new CameraPosition.Builder(cameraPosition) - .zoom(transformZoom(cameraPosition.zoom)) - .target(mapboxMap.getProjection().fromScreenLocation(new PointF(getX(), getY()))) - .build(); - } - } + @Override + public CameraPosition getCameraPosition(@NonNull MapboxMap mapboxMap) { + CameraPosition cameraPosition = mapboxMap.getCameraPosition(); + if (getType() != CameraUpdateFactory.ZoomUpdate.ZOOM_TO_POINT) { + return new CameraPosition.Builder(cameraPosition) + .zoom(transformZoom(cameraPosition.zoom)) + .build(); + } else { + return new CameraPosition.Builder(cameraPosition) + .zoom(transformZoom(cameraPosition.zoom)) + .target(mapboxMap.getProjection().fromScreenLocation(new PointF(getX(), getY()))) + .build(); + } } + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeoConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeoConstants.java index ed6f77f419..009ae936d5 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeoConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/GeoConstants.java @@ -5,34 +5,34 @@ package com.mapbox.mapboxsdk.constants; */ public class GeoConstants { - /** - * The equatorial radius - * value in meters - */ - public static final int RADIUS_EARTH_METERS = 6378137; + /** + * The equatorial radius + * value in meters + */ + public static final int RADIUS_EARTH_METERS = 6378137; - /** - * The minimum latitude on Earth. This is the minimum latitude representable - * by Mapbox GL's Mercator projection, because the projection distorts latitude - * near the poles towards infinity. - */ - public static final double MIN_LATITUDE = -85.05112878; + /** + * The minimum latitude on Earth. This is the minimum latitude representable + * by Mapbox GL's Mercator projection, because the projection distorts latitude + * near the poles towards infinity. + */ + public static final double MIN_LATITUDE = -85.05112878; - /** - * The maximum latitude on Earth. This is the maximum latitude representable - * by Mapbox GL's Mercator projection, because the projection distorts latitude - * near the poles towards infinity. - */ - public static final double MAX_LATITUDE = 85.05112878; + /** + * The maximum latitude on Earth. This is the maximum latitude representable + * by Mapbox GL's Mercator projection, because the projection distorts latitude + * near the poles towards infinity. + */ + public static final double MAX_LATITUDE = 85.05112878; - /** - * The minimum longitude on Earth - */ - public static final double MIN_LONGITUDE = -180; + /** + * The minimum longitude on Earth + */ + public static final double MIN_LONGITUDE = -180; - /** - * The maximum longitude on Earth - */ - public static final double MAX_LONGITUDE = 180; + /** + * The maximum longitude on Earth + */ + public static final double MAX_LONGITUDE = 180; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java index 9c5e8194dd..fb3240fd7b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MapboxConstants.java @@ -1,6 +1,7 @@ package com.mapbox.mapboxsdk.constants; import android.content.Context; + import java.util.Locale; /** @@ -8,137 +9,140 @@ import java.util.Locale; */ public class MapboxConstants { - /** - * Default Locale for data processing (ex: String.toLowerCase(MAPBOX_LOCALE, "foo")) - */ - public static final Locale MAPBOX_LOCALE = Locale.US; - - /** - * Key used to store access token in AndroidManifest.xml - * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.MapboxAccountManager#start(Context, String)} - */ - @Deprecated - public static final String KEY_META_DATA_MANIFEST = "com.mapbox.AccessToken"; - - /** - * Key used to store staging data server url in AndroidManifest.xml - */ - public static final String KEY_META_DATA_STAGING_SERVER = "com.mapbox.TestEventsServer"; - - /** - * Key used to store staging data server access token in AndroidManifest.xml - */ - public static final String KEY_META_DATA_STAGING_ACCESS_TOKEN = "com.mapbox.TestEventsAccessToken"; - - /** - * Key used to switch storage to external in AndroidManifest.xml - */ - public final static String KEY_META_DATA_SET_STORAGE_EXTERNAL = "com.mapbox.SetStorageExternal"; - - /** - * Default value for KEY_META_DATA_SET_STORAGE_EXTERNAL (default is internal storage) - */ - public final static boolean DEFAULT_SET_STORAGE_EXTERNAL = false; - - /** - * Unmeasured state - */ - public final static float UNMEASURED = -1f; - - /** - * Default animation time - */ - public static final int ANIMATION_DURATION = 300; - - /** - * Default short animation time - */ - public static final int ANIMATION_DURATION_SHORT = 150; - - /** - * Animation time of a fling gesture - */ - public static final long ANIMATION_DURATION_FLING = 350; - - /** - * The currently supported minimum zoom level. - */ - public static final float MINIMUM_ZOOM = 0.0f; - - /** - * The currently supported maximum zoom level. - */ - public static final float MAXIMUM_ZOOM = 20.0f; - - /** - * The currently supported maximum tilt value. - */ - public static final double MAXIMUM_TILT = 60; - - /** - * The currently supported minimum tilt value. - */ - public static final double MINIMUM_TILT = 0; - - /** - * The currently supported maximum direction - */ - public static final double MAXIMUM_DIRECTION = 360; - - /** - * The currently supported minimum direction - */ - public static final double MINIMUM_DIRECTION = 0; - - /** - * Fragment Argument Key for MapboxMapOptions - */ - public static final String FRAG_ARG_MAPBOXMAPOPTIONS = "MapboxMapOptions"; - - // Save instance state keys - public static final String STATE_HAS_SAVED_STATE = "savedState"; - public static final String STATE_CAMERA_POSITION = "cameraPosition"; - public static final String STATE_ZOOM_ENABLED = "zoomEnabled"; - public static final String STATE_ZOOM_ENABLED_CHANGE = "zoomEnabledChange"; - public static final String STATE_SCROLL_ENABLED = "scrollEnabled"; - public static final String STATE_SCROLL_ENABLED_CHANGE = "scrollEnabledChange"; - public static final String STATE_ROTATE_ENABLED = "rotateEnabled"; - public static final String STATE_ROTATE_ENABLED_CHANGE = "rotateEnabledChange"; - public static final String STATE_TILT_ENABLED = "tiltEnabled"; - public static final String STATE_TILT_ENABLED_CHANGE = "tiltEnabledChange"; - public static final String STATE_ZOOM_CONTROLS_ENABLED = "zoomControlsEnabled"; - public static final String STATE_DEBUG_ACTIVE = "debugActive"; - public static final String STATE_STYLE_URL = "styleUrl"; - public static final String STATE_MY_LOCATION_ENABLED = "myLocationEnabled"; - public static final String STATE_MY_LOCATION_TRACKING_MODE = "myLocationTracking"; - public static final String STATE_MY_BEARING_TRACKING_MODE = "myBearingTracking"; - public static final String STATE_MY_LOCATION_TRACKING_DISMISS = "myLocationTrackingDismiss"; - public static final String STATE_MY_BEARING_TRACKING_DISMISS = "myBearingTrackingDismiss"; - public static final String STATE_COMPASS_ENABLED = "compassEnabled"; - public static final String STATE_COMPASS_GRAVITY = "compassGravity"; - public static final String STATE_COMPASS_MARGIN_LEFT = "compassMarginLeft"; - public static final String STATE_COMPASS_MARGIN_TOP = "compassMarginTop"; - public static final String STATE_COMPASS_MARGIN_RIGHT = "compassMarginRight"; - public static final String STATE_COMPASS_MARGIN_BOTTOM = "compassMarginBottom"; - public static final String STATE_COMPASS_FADE_WHEN_FACING_NORTH = "compassFade"; - public static final String STATE_LOGO_GRAVITY = "logoGravity"; - public static final String STATE_LOGO_MARGIN_LEFT = "logoMarginLeft"; - public static final String STATE_LOGO_MARGIN_TOP = "logoMarginTop"; - public static final String STATE_LOGO_MARGIN_RIGHT = "logoMarginRight"; - public static final String STATE_LOGO_MARGIN_BOTTOM = "logoMarginBottom"; - public static final String STATE_LOGO_ENABLED = "logoEnabled"; - public static final String STATE_ATTRIBUTION_GRAVITY = "attrGravity"; - public static final String STATE_ATTRIBUTION_MARGIN_LEFT = "attrMarginLeft"; - public static final String STATE_ATTRIBUTION_MARGIN_TOP = "attrMarginTop"; - public static final String STATE_ATTRIBUTION_MARGIN_RIGHT = "attrMarginRight"; - public static final String STATE_ATTRIBUTION_MARGIN_BOTTOM = "atrrMarginBottom"; - public static final String STATE_ATTRIBUTION_ENABLED = "atrrEnabled"; - - public static final String TAG = "MapboxMap"; - - public static final String MAPBOX_SHARED_PREFERENCES_FILE = "MapboxSharedPreferences"; - public static final String MAPBOX_SHARED_PREFERENCE_KEY_VENDORID = "mapboxVendorId"; - public static final String MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_ENABLED = "mapboxTelemetryEnabled"; - public static final String MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_STAGING_URL = "mapboxTelemetryStagingUrl"; - public static final String MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_STAGING_ACCESS_TOKEN = "mapboxTelemetryStagingAccessToken"; + /** + * Default Locale for data processing (ex: String.toLowerCase(MAPBOX_LOCALE, "foo")) + */ + public static final Locale MAPBOX_LOCALE = Locale.US; + + /** + * Key used to store access token in AndroidManifest.xml + * + * @deprecated As of release 4.1.0, replaced by + * {@link com.mapbox.mapboxsdk.MapboxAccountManager#start(Context, String)} + */ + @Deprecated + public static final String KEY_META_DATA_MANIFEST = "com.mapbox.AccessToken"; + + /** + * Key used to store staging data server url in AndroidManifest.xml + */ + public static final String KEY_META_DATA_STAGING_SERVER = "com.mapbox.TestEventsServer"; + + /** + * Key used to store staging data server access token in AndroidManifest.xml + */ + public static final String KEY_META_DATA_STAGING_ACCESS_TOKEN = "com.mapbox.TestEventsAccessToken"; + + /** + * Key used to switch storage to external in AndroidManifest.xml + */ + public static final String KEY_META_DATA_SET_STORAGE_EXTERNAL = "com.mapbox.SetStorageExternal"; + + /** + * Default value for KEY_META_DATA_SET_STORAGE_EXTERNAL (default is internal storage) + */ + public static final boolean DEFAULT_SET_STORAGE_EXTERNAL = false; + + /** + * Unmeasured state + */ + public static final float UNMEASURED = -1f; + + /** + * Default animation time + */ + public static final int ANIMATION_DURATION = 300; + + /** + * Default short animation time + */ + public static final int ANIMATION_DURATION_SHORT = 150; + + /** + * Animation time of a fling gesture + */ + public static final long ANIMATION_DURATION_FLING = 350; + + /** + * The currently supported minimum zoom level. + */ + public static final float MINIMUM_ZOOM = 0.0f; + + /** + * The currently supported maximum zoom level. + */ + public static final float MAXIMUM_ZOOM = 20.0f; + + /** + * The currently supported maximum tilt value. + */ + public static final double MAXIMUM_TILT = 60; + + /** + * The currently supported minimum tilt value. + */ + public static final double MINIMUM_TILT = 0; + + /** + * The currently supported maximum direction + */ + public static final double MAXIMUM_DIRECTION = 360; + + /** + * The currently supported minimum direction + */ + public static final double MINIMUM_DIRECTION = 0; + + /** + * Fragment Argument Key for MapboxMapOptions + */ + public static final String FRAG_ARG_MAPBOXMAPOPTIONS = "MapboxMapOptions"; + + // Save instance state keys + public static final String STATE_HAS_SAVED_STATE = "savedState"; + public static final String STATE_CAMERA_POSITION = "cameraPosition"; + public static final String STATE_ZOOM_ENABLED = "zoomEnabled"; + public static final String STATE_ZOOM_ENABLED_CHANGE = "zoomEnabledChange"; + public static final String STATE_SCROLL_ENABLED = "scrollEnabled"; + public static final String STATE_SCROLL_ENABLED_CHANGE = "scrollEnabledChange"; + public static final String STATE_ROTATE_ENABLED = "rotateEnabled"; + public static final String STATE_ROTATE_ENABLED_CHANGE = "rotateEnabledChange"; + public static final String STATE_TILT_ENABLED = "tiltEnabled"; + public static final String STATE_TILT_ENABLED_CHANGE = "tiltEnabledChange"; + public static final String STATE_ZOOM_CONTROLS_ENABLED = "zoomControlsEnabled"; + public static final String STATE_DEBUG_ACTIVE = "debugActive"; + public static final String STATE_STYLE_URL = "styleUrl"; + public static final String STATE_MY_LOCATION_ENABLED = "myLocationEnabled"; + public static final String STATE_MY_LOCATION_TRACKING_MODE = "myLocationTracking"; + public static final String STATE_MY_BEARING_TRACKING_MODE = "myBearingTracking"; + public static final String STATE_MY_LOCATION_TRACKING_DISMISS = "myLocationTrackingDismiss"; + public static final String STATE_MY_BEARING_TRACKING_DISMISS = "myBearingTrackingDismiss"; + public static final String STATE_COMPASS_ENABLED = "compassEnabled"; + public static final String STATE_COMPASS_GRAVITY = "compassGravity"; + public static final String STATE_COMPASS_MARGIN_LEFT = "compassMarginLeft"; + public static final String STATE_COMPASS_MARGIN_TOP = "compassMarginTop"; + public static final String STATE_COMPASS_MARGIN_RIGHT = "compassMarginRight"; + public static final String STATE_COMPASS_MARGIN_BOTTOM = "compassMarginBottom"; + public static final String STATE_COMPASS_FADE_WHEN_FACING_NORTH = "compassFade"; + public static final String STATE_LOGO_GRAVITY = "logoGravity"; + public static final String STATE_LOGO_MARGIN_LEFT = "logoMarginLeft"; + public static final String STATE_LOGO_MARGIN_TOP = "logoMarginTop"; + public static final String STATE_LOGO_MARGIN_RIGHT = "logoMarginRight"; + public static final String STATE_LOGO_MARGIN_BOTTOM = "logoMarginBottom"; + public static final String STATE_LOGO_ENABLED = "logoEnabled"; + public static final String STATE_ATTRIBUTION_GRAVITY = "attrGravity"; + public static final String STATE_ATTRIBUTION_MARGIN_LEFT = "attrMarginLeft"; + public static final String STATE_ATTRIBUTION_MARGIN_TOP = "attrMarginTop"; + public static final String STATE_ATTRIBUTION_MARGIN_RIGHT = "attrMarginRight"; + public static final String STATE_ATTRIBUTION_MARGIN_BOTTOM = "atrrMarginBottom"; + public static final String STATE_ATTRIBUTION_ENABLED = "atrrEnabled"; + + public static final String TAG = "MapboxMap"; + + public static final String MAPBOX_SHARED_PREFERENCES_FILE = "MapboxSharedPreferences"; + public static final String MAPBOX_SHARED_PREFERENCE_KEY_VENDORID = "mapboxVendorId"; + public static final String MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_ENABLED = "mapboxTelemetryEnabled"; + public static final String MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_STAGING_URL = "mapboxTelemetryStagingUrl"; + public static final String MAPBOX_SHARED_PREFERENCE_KEY_TELEMETRY_STAGING_ACCESS_TOKEN = + "mapboxTelemetryStagingAccessToken"; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java index 929df2da77..cba2fb282c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyBearingTracking.java @@ -2,7 +2,6 @@ package com.mapbox.mapboxsdk.constants; import android.support.annotation.IntDef; -import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.widgets.MyLocationView; import java.lang.annotation.Retention; @@ -11,34 +10,34 @@ import java.lang.annotation.RetentionPolicy; /** * MyBearingTracking exposes different types bearing tracking modes. * - * @see MapView#setMyBearingTrackingMode(int) + * @see com.mapbox.mapboxsdk.maps.TrackingSettings#setMyBearingTrackingMode(int) * @see MyLocationView#setMyBearingTrackingMode(int) */ public class MyBearingTracking { - /** - * Indicates the parameter accepts one of the values from {@link MyBearingTracking}. - */ - @IntDef({NONE, COMPASS, GPS, /**COMBINED**/}) - @Retention(RetentionPolicy.SOURCE) - public @interface Mode { - } - - /** - * Bearing tracking is disabled - */ - public static final int NONE = 0x00000000; - - /** - * Tracking the bearing of the user based on sensor data - */ - public static final int COMPASS = 0x00000004; - - /** - * Tracking the bearing of the user based on GPS data - */ - public static final int GPS = 0x00000008; - - //public static final int COMBINED = 0x00000012; + /** + * Indicates the parameter accepts one of the values from {@link MyBearingTracking}. + */ + @IntDef( {NONE, COMPASS, GPS, /**COMBINED**/}) + @Retention(RetentionPolicy.SOURCE) + public @interface Mode { + } + + /** + * Bearing tracking is disabled + */ + public static final int NONE = 0x00000000; + + /** + * Tracking the bearing of the user based on sensor data + */ + public static final int COMPASS = 0x00000004; + + /** + * Tracking the bearing of the user based on GPS data + */ + public static final int GPS = 0x00000008; + + //public static final int COMBINED = 0x00000012; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java index b2a49c6454..d1eaac04de 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/MyLocationTracking.java @@ -11,27 +11,27 @@ import java.lang.annotation.RetentionPolicy; /** * MyLocationTracking exposes different types of locational tracking modes. * - * @see MapView#setMyLocationTrackingMode(int) + * @see com.mapbox.mapboxsdk.maps.TrackingSettings#setMyLocationTrackingMode(int) * @see MyLocationView#setMyLocationTrackingMode(int) */ public class MyLocationTracking { - /** - * Indicates the parameter accepts one of the values from {@link MyLocationTracking}. - */ - @IntDef({TRACKING_NONE, TRACKING_FOLLOW}) - @Retention(RetentionPolicy.SOURCE) - public @interface Mode { - } - - /** - * Location tracking is disabled. - */ - public static final int TRACKING_NONE = 0x00000000; - - /** - * Tracking the location of the user, {@link MapView} will reposition to center of {@link MyLocationView} - */ - public static final int TRACKING_FOLLOW = 0x00000004; + /** + * Indicates the parameter accepts one of the values from {@link MyLocationTracking}. + */ + @IntDef( {TRACKING_NONE, TRACKING_FOLLOW}) + @Retention(RetentionPolicy.SOURCE) + public @interface Mode { + } + + /** + * Location tracking is disabled. + */ + public static final int TRACKING_NONE = 0x00000000; + + /** + * Tracking the location of the user, {@link MapView} will reposition to center of {@link MyLocationView} + */ + public static final int TRACKING_FOLLOW = 0x00000004; } \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java index 51eb038052..574ef4afa6 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/constants/Style.java @@ -18,61 +18,61 @@ import java.lang.annotation.RetentionPolicy; public class Style { - /** - * Indicates the parameter accepts one of the values from {@link Style}. Using one of these - * constants means your map style will always use the latest version and may change as we - * improve the style - */ - @StringDef({MAPBOX_STREETS, OUTDOORS, EMERALD, LIGHT, DARK, SATELLITE, SATELLITE_STREETS}) - @Retention(RetentionPolicy.SOURCE) - public @interface StyleUrl { - } + /** + * Indicates the parameter accepts one of the values from {@link Style}. Using one of these + * constants means your map style will always use the latest version and may change as we + * improve the style + */ + @StringDef( {MAPBOX_STREETS, OUTDOORS, EMERALD, LIGHT, DARK, SATELLITE, SATELLITE_STREETS}) + @Retention(RetentionPolicy.SOURCE) + public @interface StyleUrl { + } - // IMPORTANT: If you change any of these you also need to edit them in strings.xml + // IMPORTANT: If you change any of these you also need to edit them in strings.xml - /** - * Mapbox Streets: A complete basemap, perfect for incorporating your own data. Using this - * constant means your map style will always use the latest version and may change as we - * improve the style. - */ - public static final String MAPBOX_STREETS = "mapbox://styles/mapbox/streets-v9"; + /** + * Mapbox Streets: A complete basemap, perfect for incorporating your own data. Using this + * constant means your map style will always use the latest version and may change as we + * improve the style. + */ + public static final String MAPBOX_STREETS = "mapbox://styles/mapbox/streets-v9"; - /** - * Outdoors: A general-purpose style tailored to outdoor activities. Using this constant means - * your map style will always use the latest version and may change as we improve the style. - */ - public static final String OUTDOORS = "mapbox://styles/mapbox/outdoors-v9"; + /** + * Outdoors: A general-purpose style tailored to outdoor activities. Using this constant means + * your map style will always use the latest version and may change as we improve the style. + */ + public static final String OUTDOORS = "mapbox://styles/mapbox/outdoors-v9"; - /** - * Emerald: A versatile style, with emphasis on road networks and public transit. - * - * @deprecated this style has been deprecated and will be removed in future versions. - */ - @Deprecated - public static final String EMERALD = "mapbox://styles/mapbox/emerald-v8"; + /** + * Emerald: A versatile style, with emphasis on road networks and public transit. + * + * @deprecated this style has been deprecated and will be removed in future versions. + */ + @Deprecated + public static final String EMERALD = "mapbox://styles/mapbox/emerald-v8"; - /** - * Light: Subtle light backdrop for data visualizations. Using this constant means your map - * style will always use the latest version and may change as we improve the style. - */ - public static final String LIGHT = "mapbox://styles/mapbox/light-v9"; + /** + * Light: Subtle light backdrop for data visualizations. Using this constant means your map + * style will always use the latest version and may change as we improve the style. + */ + public static final String LIGHT = "mapbox://styles/mapbox/light-v9"; - /** - * Dark: Subtle dark backdrop for data visualizations. Using this constant means your map style - * will always use the latest version and may change as we improve the style. - */ - public static final String DARK = "mapbox://styles/mapbox/dark-v9"; + /** + * Dark: Subtle dark backdrop for data visualizations. Using this constant means your map style + * will always use the latest version and may change as we improve the style. + */ + public static final String DARK = "mapbox://styles/mapbox/dark-v9"; - /** - * Satellite: A beautiful global satellite and aerial imagery layer. Using this constant means - * your map style will always use the latest version and may change as we improve the style. - */ - public static final String SATELLITE = "mapbox://styles/mapbox/satellite-v9"; + /** + * Satellite: A beautiful global satellite and aerial imagery layer. Using this constant means + * your map style will always use the latest version and may change as we improve the style. + */ + public static final String SATELLITE = "mapbox://styles/mapbox/satellite-v9"; - /** - * Satellite Streets: Global satellite and aerial imagery with unobtrusive labels. Using this - * constant means your map style will always use the latest version and may change as we - * improve the style. - */ - public static final String SATELLITE_STREETS = "mapbox://styles/mapbox/satellite-streets-v9"; + /** + * Satellite Streets: Global satellite and aerial imagery with unobtrusive labels. Using this + * constant means your map style will always use the latest version and may change as we + * improve the style. + */ + public static final String SATELLITE_STREETS = "mapbox://styles/mapbox/satellite-streets-v9"; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/ConversionException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/ConversionException.java index 87656db2a9..be2b586683 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/ConversionException.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/ConversionException.java @@ -5,18 +5,18 @@ package com.mapbox.mapboxsdk.exceptions; */ public class ConversionException extends RuntimeException { - public ConversionException() { - } + public ConversionException() { + } - public ConversionException(String detailMessage) { - super(detailMessage); - } + public ConversionException(String detailMessage) { + super(detailMessage); + } - public ConversionException(String detailMessage, Throwable throwable) { - super(detailMessage, throwable); - } + public ConversionException(String detailMessage, Throwable throwable) { + super(detailMessage, throwable); + } - public ConversionException(Throwable throwable) { - super(throwable); - } + public ConversionException(Throwable throwable) { + super(throwable); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/IconBitmapChangedException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/IconBitmapChangedException.java index 1be82d6178..7154049bd7 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/IconBitmapChangedException.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/IconBitmapChangedException.java @@ -19,9 +19,9 @@ import com.mapbox.mapboxsdk.maps.MapView; */ public class IconBitmapChangedException extends RuntimeException { - public IconBitmapChangedException() { - super("The added Marker has an Icon with a bitmap that has been modified. An Icon cannot be modified" + - "after it has been added to the map in a Marker."); - } + public IconBitmapChangedException() { + super("The added Marker has an Icon with a bitmap that has been modified. An Icon cannot be modified" + + "after it has been added to the map in a Marker."); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidAccessTokenException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidAccessTokenException.java index 77797ecb4f..9f95826ba3 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidAccessTokenException.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidAccessTokenException.java @@ -5,18 +5,19 @@ import android.os.Bundle; import com.mapbox.mapboxsdk.maps.MapView; /** - * A {@code InvalidAccessTokenException} is thrown by {@link com.mapbox.mapboxsdk.maps.MapboxMap} when there is either no access - * token set before {@link MapView#onCreate(Bundle)} or an invalid access token is set in {@link MapView#setAccessToken(String)} + * A {@code InvalidAccessTokenException} is thrown by {@link com.mapbox.mapboxsdk.maps.MapboxMap} when there is either + * no access token set before {@link MapView#onCreate(Bundle)} or an invalid access token is set in + * {@link MapView#setAccessToken(String)} * * @see MapView#onCreate(Bundle) * @see MapView#setAccessToken(String) */ public class InvalidAccessTokenException extends RuntimeException { - public InvalidAccessTokenException() { - super("\nUsing MapView requires setting a valid access token. Use setAccessToken on Mapview to provide one. " + - "\nPlease see https://www.mapbox.com/help/create-api-access-token/ to learn how to create one." + - "\nMore information in this guide https://www.mapbox.com/help/first-steps-android-sdk/#access-tokens."); - } + public InvalidAccessTokenException() { + super("\nUsing MapView requires setting a valid access token. Use setAccessToken on Mapview to provide one. " + + "\nPlease see https://www.mapbox.com/help/create-api-access-token/ to learn how to create one." + + "\nMore information in this guide https://www.mapbox.com/help/first-steps-android-sdk/#access-tokens."); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidLatLngBoundsException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidLatLngBoundsException.java index 92feaac64b..08a23a7373 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidLatLngBoundsException.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidLatLngBoundsException.java @@ -6,7 +6,7 @@ package com.mapbox.mapboxsdk.exceptions; */ public class InvalidLatLngBoundsException extends RuntimeException { - public InvalidLatLngBoundsException(int latLngsListSize) { - super("Cannot create a LatLngBounds from " + latLngsListSize + " items"); - } + public InvalidLatLngBoundsException(int latLngsListSize) { + super("Cannot create a LatLngBounds from " + latLngsListSize + " items"); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java index 8dc98118b1..e5a647841f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/InvalidMarkerPositionException.java @@ -2,9 +2,9 @@ package com.mapbox.mapboxsdk.exceptions; public class InvalidMarkerPositionException extends RuntimeException { - public InvalidMarkerPositionException() { - super("Adding an invalid Marker to a Map. " + - "Missing the required position field. " + - "Provide a non null LatLng as position to the Marker."); - } + public InvalidMarkerPositionException() { + super("Adding an invalid Marker to a Map. " + + "Missing the required position field. " + + "Provide a non null LatLng as position to the Marker."); + } } \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxAccountManagerNotStartedException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxAccountManagerNotStartedException.java index 4954098f15..e1179b4aa9 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxAccountManagerNotStartedException.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/MapboxAccountManagerNotStartedException.java @@ -1,7 +1,5 @@ package com.mapbox.mapboxsdk.exceptions; - -import android.content.Context; import android.os.Bundle; import com.mapbox.mapboxsdk.MapboxAccountManager; @@ -12,12 +10,13 @@ import com.mapbox.mapboxsdk.maps.MapView; * when {@link MapboxAccountManager} is not started before {@link MapView#onCreate(Bundle)}. * * @see MapView#onCreate(Bundle) - * @see MapboxAccountManager#start(Context, String) + * @see MapboxAccountManager#start(android.content.Context, String) */ public class MapboxAccountManagerNotStartedException extends RuntimeException { - public MapboxAccountManagerNotStartedException() { - super("\nMapboxAccountManager was not started correctly. Use MapboxAccountManager#start(Context, String) to initialise. " + - "\nMore information in this guide https://www.mapbox.com/help/first-steps-android-sdk/#access-tokens."); - } + public MapboxAccountManagerNotStartedException() { + super("\nMapboxAccountManager was not started correctly. Use MapboxAccountManager#start(Context, String) to" + + "initialise. " + + "\nMore information in this guide https://www.mapbox.com/help/first-steps-android-sdk/#access-tokens."); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TelemetryServiceNotConfiguredException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TelemetryServiceNotConfiguredException.java index ec2b0d792d..e2e114fa77 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TelemetryServiceNotConfiguredException.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TelemetryServiceNotConfiguredException.java @@ -12,10 +12,11 @@ import com.mapbox.mapboxsdk.maps.MapView; */ public class TelemetryServiceNotConfiguredException extends RuntimeException { - public TelemetryServiceNotConfiguredException() { - super("\nTelemetryService is not configured in your applications AndroidManifest.xml. " + - "\nPlease add \"com.mapbox.mapboxsdk.telemetry.TelemetryService\" service in your applications AndroidManifest.xml" + - "\nFor an example visit http://goo.gl/cET0Jn. For more information visit https://www.mapbox.com/android-sdk/."); - } + public TelemetryServiceNotConfiguredException() { + super("\nTelemetryService is not configured in your applications AndroidManifest.xml. " + + "\nPlease add \"com.mapbox.mapboxsdk.telemetry.TelemetryService\" service in your applications " + + "AndroidManifest.xml" + + "\nFor an example visit http://goo.gl/cET0Jn. For more information visit https://www.mapbox.com/android-sdk/."); + } } \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManyIconsException.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManyIconsException.java index 4dcdea112c..8923d822f2 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManyIconsException.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/exceptions/TooManyIconsException.java @@ -14,8 +14,8 @@ import com.mapbox.mapboxsdk.annotations.IconFactory; */ public class TooManyIconsException extends RuntimeException { - public TooManyIconsException() { - super("Cannot create an Icon because there are already too many. Try reusing Icon objects whenever possible."); - } + public TooManyIconsException() { + super("Cannot create an Icon because there are already too many. Try reusing Icon objects whenever possible."); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ILatLng.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ILatLng.java index afd22e5ddb..1af8e7cfc7 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ILatLng.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ILatLng.java @@ -4,9 +4,9 @@ package com.mapbox.mapboxsdk.geometry; * Describes a latitude, longitude point. */ public interface ILatLng { - double getLatitude(); + double getLatitude(); - double getLongitude(); + double getLongitude(); - double getAltitude(); + double getAltitude(); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/IProjectedMeters.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/IProjectedMeters.java index 43fe25f8e5..694c935143 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/IProjectedMeters.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/IProjectedMeters.java @@ -4,7 +4,7 @@ package com.mapbox.mapboxsdk.geometry; * Describes a projection in Mercator meters. */ public interface IProjectedMeters { - double getNorthing(); + double getNorthing(); - double getEasting(); + double getEasting(); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java index 4449a7fe0d..b18b7e87b0 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLng.java @@ -21,183 +21,191 @@ import com.mapbox.mapboxsdk.utils.MathUtils; */ public class LatLng implements ILatLng, Parcelable { - public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { - public LatLng createFromParcel(Parcel in) { - return new LatLng(in); - } - - public LatLng[] newArray(int size) { - return new LatLng[size]; - } - }; - - private double latitude; - private double longitude; - private double altitude = 0.0; - - /** - * Construct a new latitude, longitude point at (0, 0) - */ - public LatLng() { - this.latitude = 0.0; - this.longitude = 0.0; - } - - /** - * Construct a new latitude, longitude point given float arguments - * @param latitude Latitude in degrees - * @param longitude Longitude in degrees - */ - public LatLng(double latitude, double longitude) { - this.latitude = latitude; - this.longitude = longitude; - } - - /** - * Construct a new latitude, longitude, altitude point given float arguments - * @param latitude Latitude in degrees - * @param longitude Longitude in degress - * @param altitude Altitude in meters - */ - public LatLng(double latitude, double longitude, double altitude) { - this.latitude = latitude; - this.longitude = longitude; - this.altitude = altitude; - } - - /** - * Transform a Location into a LatLng point - * @param location Android Location - */ - public LatLng(Location location) { - this(location.getLatitude(), location.getLongitude(), location.getAltitude()); - } - - /** - * Clone an existing latitude longitude point - * @param aLatLng LatLng - */ - public LatLng(LatLng aLatLng) { - this.latitude = aLatLng.latitude; - this.longitude = aLatLng.longitude; - this.altitude = aLatLng.altitude; - } - - protected LatLng(Parcel in) { - latitude = in.readDouble(); - longitude = in.readDouble(); - altitude = in.readDouble(); - } - - public void setLatitude(double latitude) { - this.latitude = latitude; - } - - @Override - public double getLatitude() { - return latitude; - } - - public void setLongitude(double longitude) { - this.longitude = longitude; - } - - @Override - public double getLongitude() { - return longitude; - } - - public void setAltitude(double altitude) { - this.altitude = altitude; - } - - @Override - public double getAltitude() { - return altitude; - } - - /** - * Return a new LatLng object with a wrapped Longitude. This allows original data object - * to remain unchanged. - * @return New LatLng object with wrapped Longitude - */ - public LatLng wrap(){ - LatLng wrappedVersion = new LatLng(this); - double lon = wrappedVersion.getLongitude(); - if (lon < GeoConstants.MIN_LONGITUDE || lon > GeoConstants.MAX_LONGITUDE) { - wrappedVersion.setLongitude(MathUtils.wrap(wrappedVersion.getLongitude(), GeoConstants.MIN_LONGITUDE, GeoConstants.MAX_LONGITUDE)); - } - return wrappedVersion; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - LatLng latLng = (LatLng) o; - - return Double.compare(latLng.altitude, altitude) == 0 && Double.compare(latLng.latitude, latitude) == 0 && Double.compare(latLng.longitude, longitude) == 0; - } - - @Override - public int hashCode() { - int result; - long temp; - temp = Double.doubleToLongBits(latitude); - result = (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(longitude); - result = 31 * result + (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(altitude); - result = 31 * result + (int) (temp ^ (temp >>> 32)); - return result; - } - - @Override - public String toString() { - return "LatLng [latitude=" + latitude + ", longitude=" + longitude + ", altitude=" + altitude + "]"; - } - - @Override - public int describeContents() { - return 0; - } - - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeDouble(latitude); - out.writeDouble(longitude); - out.writeDouble(altitude); - } - - /** - * Calculate distance between two points - * @param other Other LatLng to compare to - * @return distance in meters - */ - public double distanceTo(LatLng other) { - if(latitude == other.latitude && longitude == other.longitude){ - // return 0.0 to avoid a NaN - return 0.0; - } - - final double a1 = Math.toRadians(this.latitude); - final double a2 = Math.toRadians(this.longitude); - final double b1 = Math.toRadians(other.getLatitude()); - final double b2 = Math.toRadians(other.getLongitude()); - - final double cosa1 = Math.cos(a1); - final double cosb1 = Math.cos(b1); - - final double t1 = cosa1 * Math.cos(a2) * cosb1 * Math.cos(b2); - final double t2 = cosa1 * Math.sin(a2) * cosb1 * Math.sin(b2); - final double t3 = Math.sin(a1) * Math.sin(b1); - final double tt = Math.acos(t1 + t2 + t3); - - return GeoConstants.RADIUS_EARTH_METERS * tt; - } + public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { + public LatLng createFromParcel(Parcel in) { + return new LatLng(in); + } + + public LatLng[] newArray(int size) { + return new LatLng[size]; + } + }; + + private double latitude; + private double longitude; + private double altitude = 0.0; + + /** + * Construct a new latitude, longitude point at (0, 0) + */ + public LatLng() { + this.latitude = 0.0; + this.longitude = 0.0; + } + + /** + * Construct a new latitude, longitude point given float arguments + * + * @param latitude Latitude in degrees + * @param longitude Longitude in degrees + */ + public LatLng(double latitude, double longitude) { + this.latitude = latitude; + this.longitude = longitude; + } + + /** + * Construct a new latitude, longitude, altitude point given float arguments + * + * @param latitude Latitude in degrees + * @param longitude Longitude in degress + * @param altitude Altitude in meters + */ + public LatLng(double latitude, double longitude, double altitude) { + this.latitude = latitude; + this.longitude = longitude; + this.altitude = altitude; + } + + /** + * Transform a Location into a LatLng point + * + * @param location Android Location + */ + public LatLng(Location location) { + this(location.getLatitude(), location.getLongitude(), location.getAltitude()); + } + + /** + * Clone an existing latitude longitude point + * + * @param aLatLng LatLng + */ + public LatLng(LatLng aLatLng) { + this.latitude = aLatLng.latitude; + this.longitude = aLatLng.longitude; + this.altitude = aLatLng.altitude; + } + + protected LatLng(Parcel in) { + latitude = in.readDouble(); + longitude = in.readDouble(); + altitude = in.readDouble(); + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + @Override + public double getLatitude() { + return latitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + @Override + public double getLongitude() { + return longitude; + } + + public void setAltitude(double altitude) { + this.altitude = altitude; + } + + @Override + public double getAltitude() { + return altitude; + } + + /** + * Return a new LatLng object with a wrapped Longitude. This allows original data object + * to remain unchanged. + * + * @return New LatLng object with wrapped Longitude + */ + public LatLng wrap() { + LatLng wrappedVersion = new LatLng(this); + double lon = wrappedVersion.getLongitude(); + if (lon < GeoConstants.MIN_LONGITUDE || lon > GeoConstants.MAX_LONGITUDE) { + wrappedVersion.setLongitude(MathUtils.wrap(wrappedVersion.getLongitude(), GeoConstants.MIN_LONGITUDE, + GeoConstants.MAX_LONGITUDE)); + } + return wrappedVersion; + } + + @Override + public boolean equals(Object object) { + if (this == object) { + return true; + } + if (object == null || getClass() != object.getClass()) { + return false; + } + + LatLng latLng = (LatLng) object; + + return Double.compare(latLng.altitude, altitude) == 0 && Double.compare(latLng.latitude, latitude) == 0 + && Double.compare(latLng.longitude, longitude) == 0; + } + + @Override + public int hashCode() { + int result; + long temp; + temp = Double.doubleToLongBits(latitude); + result = (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(longitude); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(altitude); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public String toString() { + return "LatLng [latitude=" + latitude + ", longitude=" + longitude + ", altitude=" + altitude + "]"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeDouble(latitude); + out.writeDouble(longitude); + out.writeDouble(altitude); + } + + /** + * Calculate distance between two points + * + * @param other Other LatLng to compare to + * @return distance in meters + */ + public double distanceTo(LatLng other) { + if (latitude == other.latitude && longitude == other.longitude) { + // return 0.0 to avoid a NaN + return 0.0; + } + + final double a1 = Math.toRadians(this.latitude); + final double a2 = Math.toRadians(this.longitude); + final double b1 = Math.toRadians(other.getLatitude()); + final double b2 = Math.toRadians(other.getLongitude()); + + final double cosa1 = Math.cos(a1); + final double cosb1 = Math.cos(b1); + + final double t1 = cosa1 * Math.cos(a2) * cosb1 * Math.cos(b2); + final double t2 = cosa1 * Math.sin(a2) * cosb1 * Math.sin(b2); + final double t3 = Math.sin(a1) * Math.sin(b1); + final double tt = Math.acos(t1 + t2 + t3); + + return GeoConstants.RADIUS_EARTH_METERS * tt; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java index 2fd28202af..3b92f0f0f5 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngBounds.java @@ -14,292 +14,296 @@ import java.util.List; */ public class LatLngBounds implements Parcelable { - private final double mLatNorth; - private final double mLatSouth; - private final double mLonEast; - private final double mLonWest; - - /** - * Construct a new LatLngBounds based on its corners, given in NESW - * order. - * - * @param northLatitude Northern Latitude - * @param eastLongitude Eastern Longitude - * @param southLatitude Southern Latitude - * @param westLongitude Western Longitude - */ - LatLngBounds(final double northLatitude, final double eastLongitude, final double southLatitude, final double westLongitude) { - this.mLatNorth = northLatitude; - this.mLonEast = eastLongitude; - this.mLatSouth = southLatitude; - this.mLonWest = westLongitude; + private final double mLatNorth; + private final double mLatSouth; + private final double mLonEast; + private final double mLonWest; + + /** + * Construct a new LatLngBounds based on its corners, given in NESW + * order. + * + * @param northLatitude Northern Latitude + * @param eastLongitude Eastern Longitude + * @param southLatitude Southern Latitude + * @param westLongitude Western Longitude + */ + LatLngBounds(final double northLatitude, final double eastLongitude, final double southLatitude, + final double westLongitude) { + this.mLatNorth = northLatitude; + this.mLonEast = eastLongitude; + this.mLatSouth = southLatitude; + this.mLonWest = westLongitude; + } + + /** + * Calculates the centerpoint of this LatLngBounds by simple interpolation and returns + * it as a point. This is a non-geodesic calculation which is not the geographic center. + * + * @return LatLng center of this LatLngBounds + */ + public LatLng getCenter() { + return new LatLng((this.mLatNorth + this.mLatSouth) / 2, + (this.mLonEast + this.mLonWest) / 2); + } + + public double getLatNorth() { + return this.mLatNorth; + } + + public double getLatSouth() { + return this.mLatSouth; + } + + public double getLonEast() { + return this.mLonEast; + } + + public double getLonWest() { + return this.mLonWest; + } + + /** + * Get the area spanned by this LatLngBounds + * + * @return LatLngSpan area + */ + public LatLngSpan getSpan() { + return new LatLngSpan(getLatitudeSpan(), getLongitudeSpan()); + } + + /** + * Get the absolute distance, in degrees, between the north and + * south boundaries of this LatLngBounds + * + * @return Span distance + */ + public double getLatitudeSpan() { + return Math.abs(this.mLatNorth - this.mLatSouth); + } + + /** + * Get the absolute distance, in degrees, between the west and + * east boundaries of this LatLngBounds + * + * @return Span distance + */ + public double getLongitudeSpan() { + return Math.abs(this.mLonEast - this.mLonWest); + } + + + /** + * Validate if LatLngBounds is empty, determined if absolute distance is + * + * @return boolean indicating if span is empty + */ + public boolean isEmptySpan() { + return getLongitudeSpan() == 0.0 || getLatitudeSpan() == 0.0; + } + + @Override + public String toString() { + return "N:" + this.mLatNorth + "; E:" + this.mLonEast + "; S:" + this.mLatSouth + "; W:" + this.mLonWest; + } + + /** + * Constructs a LatLngBounds that contains all of a list of LatLng + * objects. Empty lists will yield invalid LatLngBounds. + * + * @param latLngs List of LatLng objects + * @return LatLngBounds + */ + static LatLngBounds fromLatLngs(final List latLngs) { + double minLat = 90; + double minLon = 180; + double maxLat = -90; + double maxLon = -180; + + for (final ILatLng gp : latLngs) { + final double latitude = gp.getLatitude(); + final double longitude = gp.getLongitude(); + + minLat = Math.min(minLat, latitude); + minLon = Math.min(minLon, longitude); + maxLat = Math.max(maxLat, latitude); + maxLon = Math.max(maxLon, longitude); } - /** - * Calculates the centerpoint of this LatLngBounds by simple interpolation and returns - * it as a point. This is a non-geodesic calculation which is not the geographic center. - * - * @return LatLng center of this LatLngBounds - */ - public LatLng getCenter() { - return new LatLng((this.mLatNorth + this.mLatSouth) / 2, - (this.mLonEast + this.mLonWest) / 2); + return new LatLngBounds(maxLat, maxLon, minLat, minLon); + } + + public LatLng[] toLatLngs() { + return new LatLng[] {new LatLng(mLatNorth, mLonEast), new LatLng(mLatSouth, mLonWest)}; + } + + /** + * Determines whether this LatLngBounds matches another one via LatLng. + * + * @param o another object + * @return a boolean indicating whether the LatLngBounds are equal + */ + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; } - - public double getLatNorth() { - return this.mLatNorth; - } - - public double getLatSouth() { - return this.mLatSouth; - } - - public double getLonEast() { - return this.mLonEast; - } - - public double getLonWest() { - return this.mLonWest; - } - - /** - * Get the area spanned by this LatLngBounds - * - * @return LatLngSpan area - */ - public LatLngSpan getSpan() { - return new LatLngSpan(getLatitudeSpan(), getLongitudeSpan()); - } - - /** - * Get the absolute distance, in degrees, between the north and - * south boundaries of this LatLngBounds - * - * @return Span distance - */ - public double getLatitudeSpan() { - return Math.abs(this.mLatNorth - this.mLatSouth); - } - - /** - * Get the absolute distance, in degrees, between the west and - * east boundaries of this LatLngBounds - * - * @return Span distance - */ - public double getLongitudeSpan() { - return Math.abs(this.mLonEast - this.mLonWest); - } - - - /** - * Validate if LatLngBounds is empty, determined if absolute distance is - * - * @return boolean indicating if span is empty - */ - public boolean isEmptySpan() { - return getLongitudeSpan() == 0.0 || getLatitudeSpan() == 0.0; - } - - @Override - public String toString() { - return "N:" + this.mLatNorth + "; E:" + this.mLonEast + "; S:" + this.mLatSouth + "; W:" + this.mLonWest; + if (o instanceof LatLngBounds) { + LatLngBounds other = (LatLngBounds) o; + return mLatNorth == other.getLatNorth() + && mLatSouth == other.getLatSouth() + && mLonEast == other.getLonEast() + && mLonWest == other.getLonWest(); } - - /** - * Constructs a LatLngBounds that contains all of a list of LatLng - * objects. Empty lists will yield invalid LatLngBounds. - * - * @param latLngs List of LatLng objects - * @return LatLngBounds - */ - static LatLngBounds fromLatLngs(final List latLngs) { - double minLat = 90, - minLon = 180, - maxLat = -90, - maxLon = -180; - - for (final ILatLng gp : latLngs) { - final double latitude = gp.getLatitude(); - final double longitude = gp.getLongitude(); - - minLat = Math.min(minLat, latitude); - minLon = Math.min(minLon, longitude); - maxLat = Math.max(maxLat, latitude); - maxLon = Math.max(maxLon, longitude); - } - - return new LatLngBounds(maxLat, maxLon, minLat, minLon); - } - - public LatLng[] toLatLngs() { - return new LatLng[]{new LatLng(mLatNorth, mLonEast), new LatLng(mLatSouth, mLonWest)}; - } - - /** - * Determines whether this LatLngBounds matches another one via LatLng. - * - * @param o another object - * @return a boolean indicating whether the LatLngBounds are equal - */ - @Override - public boolean equals(final Object o) { - if (this == o) return true; - if (o instanceof LatLngBounds) { - LatLngBounds other = (LatLngBounds) o; - return mLatNorth == other.getLatNorth() - && mLatSouth == other.getLatSouth() - && mLonEast == other.getLonEast() - && mLonWest == other.getLonWest(); - } - return false; - } - - /** - * Determines whether this LatLngBounds contains a point and the point - * does not touch its boundary. - * - * @param latLng the point which may be contained - * @return true, if the point is contained within the box. - */ - public boolean contains(final ILatLng latLng) { - final double latitude = latLng.getLatitude(); - final double longitude = latLng.getLongitude(); - return ((latitude < this.mLatNorth) - && (latitude > this.mLatSouth)) - && ((longitude < this.mLonEast) - && (longitude > this.mLonWest)); - } - - /** - * Returns a new LatLngBounds that stretches to contain both this and another LatLngBounds. - * - * @param bounds LatLngBounds to add - * @return LatLngBounds - */ - public LatLngBounds union(LatLngBounds bounds) { - return union(bounds.getLatNorth(), bounds.getLonEast(), bounds.getLatSouth(), bounds.getLonWest()); + return false; + } + + /** + * Determines whether this LatLngBounds contains a point and the point + * does not touch its boundary. + * + * @param latLng the point which may be contained + * @return true, if the point is contained within the box. + */ + public boolean contains(final ILatLng latLng) { + final double latitude = latLng.getLatitude(); + final double longitude = latLng.getLongitude(); + return ((latitude < this.mLatNorth) + && (latitude > this.mLatSouth)) + && ((longitude < this.mLonEast) + && (longitude > this.mLonWest)); + } + + /** + * Returns a new LatLngBounds that stretches to contain both this and another LatLngBounds. + * + * @param bounds LatLngBounds to add + * @return LatLngBounds + */ + public LatLngBounds union(LatLngBounds bounds) { + return union(bounds.getLatNorth(), bounds.getLonEast(), bounds.getLatSouth(), bounds.getLonWest()); + } + + /** + * Returns a new LatLngBounds that stretches to include another LatLngBounds, + * given by corner points. + * + * @param lonNorth Northern Longitude + * @param latEast Eastern Latitude + * @param lonSouth Southern Longitude + * @param latWest Western Longitude + * @return BoundingBox + */ + public LatLngBounds union(final double lonNorth, final double latEast, final double lonSouth, final double latWest) { + return new LatLngBounds((this.mLatNorth < lonNorth) ? lonNorth : this.mLatNorth, + (this.mLonEast < latEast) ? latEast : this.mLonEast, + (this.mLatSouth > lonSouth) ? lonSouth : this.mLatSouth, + (this.mLonWest > latWest) ? latWest : this.mLonWest); + } + + /** + * Returns a new LatLngBounds that is the intersection of this with another box + * + * @param box LatLngBounds to intersect with + * @return LatLngBounds + */ + public LatLngBounds intersect(LatLngBounds box) { + double minLatWest = Math.max(getLonWest(), box.getLonWest()); + double maxLatEast = Math.min(getLonEast(), box.getLonEast()); + if (maxLatEast > minLatWest) { + double minLonSouth = Math.max(getLatSouth(), box.getLatSouth()); + double maxLonNorth = Math.min(getLatNorth(), box.getLatNorth()); + if (maxLonNorth > minLonSouth) { + return new LatLngBounds(maxLonNorth, maxLatEast, minLonSouth, minLatWest); + } } - - /** - * Returns a new LatLngBounds that stretches to include another LatLngBounds, - * given by corner points. - * - * @param lonNorth Northern Longitude - * @param latEast Eastern Latitude - * @param lonSouth Southern Longitude - * @param latWest Western Longitude - * @return BoundingBox - */ - public LatLngBounds union(final double lonNorth, final double latEast, final double lonSouth, final double latWest) { - return new LatLngBounds((this.mLatNorth < lonNorth) ? lonNorth : this.mLatNorth, - (this.mLonEast < latEast) ? latEast : this.mLonEast, - (this.mLatSouth > lonSouth) ? lonSouth : this.mLatSouth, - (this.mLonWest > latWest) ? latWest : this.mLonWest); - } - - /** - * Returns a new LatLngBounds that is the intersection of this with another box - * - * @param box LatLngBounds to intersect with - * @return LatLngBounds - */ - public LatLngBounds intersect(LatLngBounds box) { - double minLatWest = Math.max(getLonWest(), box.getLonWest()); - double maxLatEast = Math.min(getLonEast(), box.getLonEast()); - if (maxLatEast > minLatWest) { - double minLonSouth = Math.max(getLatSouth(), box.getLatSouth()); - double maxLonNorth = Math.min(getLatNorth(), box.getLatNorth()); - if (maxLonNorth > minLonSouth) { - return new LatLngBounds(maxLonNorth, maxLatEast, minLonSouth, minLatWest); - } - } - return null; - } - - /** - * Returns a new LatLngBounds that is the intersection of this with another LatLngBounds - * - * @param northLatitude Northern Longitude - * @param eastLongitude Eastern Latitude - * @param southLatitude Southern Longitude - * @param westLongitude Western Latitude - * @return LatLngBounds - */ - public LatLngBounds intersect(double northLatitude, double eastLongitude, double southLatitude, double westLongitude) { - return intersect(new LatLngBounds(northLatitude, eastLongitude, southLatitude, westLongitude)); - } - - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public LatLngBounds createFromParcel(final Parcel in) { - return readFromParcel(in); - } - - @Override - public LatLngBounds[] newArray(final int size) { - return new LatLngBounds[size]; - } - }; - - @Override - public int hashCode() { - return (int) ((mLatNorth + 90) - + ((mLatSouth + 90) * 1000) - + ((mLonEast + 180) * 1000000) - + ((mLonEast + 180) * 1000000000)); - } - - @Override - public int describeContents() { - return 0; + return null; + } + + /** + * Returns a new LatLngBounds that is the intersection of this with another LatLngBounds + * + * @param northLatitude Northern Longitude + * @param eastLongitude Eastern Latitude + * @param southLatitude Southern Longitude + * @param westLongitude Western Latitude + * @return LatLngBounds + */ + public LatLngBounds intersect(double northLatitude, double eastLongitude, double southLatitude, + double westLongitude) { + return intersect(new LatLngBounds(northLatitude, eastLongitude, southLatitude, westLongitude)); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public LatLngBounds createFromParcel(final Parcel in) { + return readFromParcel(in); + } + + @Override + public LatLngBounds[] newArray(final int size) { + return new LatLngBounds[size]; + } + }; + + @Override + public int hashCode() { + return (int) ((mLatNorth + 90) + + ((mLatSouth + 90) * 1000) + + ((mLonEast + 180) * 1000000) + + ((mLonEast + 180) * 1000000000)); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(final Parcel out, final int arg1) { + out.writeDouble(this.mLatNorth); + out.writeDouble(this.mLonEast); + out.writeDouble(this.mLatSouth); + out.writeDouble(this.mLonWest); + } + + private static LatLngBounds readFromParcel(final Parcel in) { + final double lonNorth = in.readDouble(); + final double latEast = in.readDouble(); + final double lonSouth = in.readDouble(); + final double latWest = in.readDouble(); + return new LatLngBounds(lonNorth, latEast, lonSouth, latWest); + } + + /** + * Builder for composing LatLngBounds objects. + */ + public static final class Builder { + + private List mLatLngList; + + public Builder() { + mLatLngList = new ArrayList<>(); } - @Override - public void writeToParcel(final Parcel out, final int arg1) { - out.writeDouble(this.mLatNorth); - out.writeDouble(this.mLonEast); - out.writeDouble(this.mLatSouth); - out.writeDouble(this.mLonWest); + public LatLngBounds build() { + if (mLatLngList.size() < 2) { + throw new InvalidLatLngBoundsException(mLatLngList.size()); + } + return LatLngBounds.fromLatLngs(mLatLngList); } - private static LatLngBounds readFromParcel(final Parcel in) { - final double lonNorth = in.readDouble(); - final double latEast = in.readDouble(); - final double lonSouth = in.readDouble(); - final double latWest = in.readDouble(); - return new LatLngBounds(lonNorth, latEast, lonSouth, latWest); + public Builder includes(List latLngs) { + for (LatLng point : latLngs) { + mLatLngList.add(point); + } + return this; } - /** - * Builder for composing LatLngBounds objects. - */ - public static final class Builder { - - private List mLatLngList; - - public Builder() { - mLatLngList = new ArrayList<>(); - } - - public LatLngBounds build() { - if (mLatLngList.size() < 2) { - throw new InvalidLatLngBoundsException(mLatLngList.size()); - } - return LatLngBounds.fromLatLngs(mLatLngList); - } - - public Builder includes(List latLngs){ - for (LatLng point : latLngs) { - mLatLngList.add(point); - } - return this; - } - - public Builder include(@NonNull LatLng latLng) { - mLatLngList.add(latLng); - return this; - } + public Builder include(@NonNull LatLng latLng) { + mLatLngList.add(latLng); + return this; } + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java index 81e52666f6..dd7fef4d23 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/LatLngSpan.java @@ -9,93 +9,95 @@ import android.support.annotation.NonNull; */ public class LatLngSpan implements Parcelable { - private double mLatitudeSpan; - private double mLongitudeSpan; + private double mLatitudeSpan; + private double mLongitudeSpan; - private LatLngSpan(@NonNull Parcel in) { - mLatitudeSpan = in.readDouble(); - mLongitudeSpan = in.readDouble(); - } + private LatLngSpan(@NonNull Parcel in) { + mLatitudeSpan = in.readDouble(); + mLongitudeSpan = in.readDouble(); + } - /** - * Creates a LatLgnSpan. - * - * @param latitudeSpan The span used for latitude. - * @param longitudeSpan The span used for longitude. - */ - public LatLngSpan(double latitudeSpan, double longitudeSpan) { - mLatitudeSpan = latitudeSpan; - mLongitudeSpan = longitudeSpan; - } + /** + * Creates a LatLgnSpan. + * + * @param latitudeSpan The span used for latitude. + * @param longitudeSpan The span used for longitude. + */ + public LatLngSpan(double latitudeSpan, double longitudeSpan) { + mLatitudeSpan = latitudeSpan; + mLongitudeSpan = longitudeSpan; + } - /** - * Returns the latitude span. - * - * @return The latitude span. - */ - public double getLatitudeSpan() { - return mLatitudeSpan; - } + /** + * Returns the latitude span. + * + * @return The latitude span. + */ + public double getLatitudeSpan() { + return mLatitudeSpan; + } - /** - * Sets the latitude span. - * - * @param latitudeSpan The latitude span to set. - */ - public void setLatitudeSpan(double latitudeSpan) { - mLatitudeSpan = latitudeSpan; - } + /** + * Sets the latitude span. + * + * @param latitudeSpan The latitude span to set. + */ + public void setLatitudeSpan(double latitudeSpan) { + mLatitudeSpan = latitudeSpan; + } - /** - * Returns to longitude span. - * - * @return The longitude span. - */ - public double getLongitudeSpan() { - return mLongitudeSpan; - } + /** + * Returns to longitude span. + * + * @return The longitude span. + */ + public double getLongitudeSpan() { + return mLongitudeSpan; + } - /** - * Sets the longitude span. - * - * @param longitudeSpan The longitude span to set. - */ - public void setLongitudeSpan(double longitudeSpan) { - mLongitudeSpan = longitudeSpan; - } + /** + * Sets the longitude span. + * + * @param longitudeSpan The longitude span to set. + */ + public void setLongitudeSpan(double longitudeSpan) { + mLongitudeSpan = longitudeSpan; + } - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o instanceof LatLngSpan) { - LatLngSpan other = (LatLngSpan) o; - return mLongitudeSpan == other.getLongitudeSpan() - && mLatitudeSpan == other.getLatitudeSpan(); - } - return false; + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o instanceof LatLngSpan) { + LatLngSpan other = (LatLngSpan) o; + return mLongitudeSpan == other.getLongitudeSpan() + && mLatitudeSpan == other.getLatitudeSpan(); } + return false; + } - public static final Parcelable.Creator CREATOR = - new Parcelable.Creator() { - @Override - public LatLngSpan createFromParcel(Parcel in) { - return new LatLngSpan(in); - } + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + @Override + public LatLngSpan createFromParcel(Parcel in) { + return new LatLngSpan(in); + } - @Override - public LatLngSpan[] newArray(int size) { - return new LatLngSpan[size]; - } - }; + @Override + public LatLngSpan[] newArray(int size) { + return new LatLngSpan[size]; + } + }; - @Override - public int describeContents() { - return 0; - } + @Override + public int describeContents() { + return 0; + } - @Override - public void writeToParcel(Parcel out, int arg1) { - out.writeDouble(mLatitudeSpan); - out.writeDouble(mLongitudeSpan); - } + @Override + public void writeToParcel(Parcel out, int arg1) { + out.writeDouble(mLatitudeSpan); + out.writeDouble(mLongitudeSpan); + } } \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java index 1f1417b4b6..761d8f2a8b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/ProjectedMeters.java @@ -13,104 +13,105 @@ import android.os.Parcelable; */ public class ProjectedMeters implements IProjectedMeters, Parcelable { - public static final Creator CREATOR = new Creator() { - public ProjectedMeters createFromParcel(Parcel in) { - return new ProjectedMeters(in); - } - - public ProjectedMeters[] newArray(int size) { - return new ProjectedMeters[size]; - } - }; - - private double northing; - private double easting; - - /** - * Creates a ProjectedMeters based on projected meters in north and east direction. - * - * @param northing the northing in meters - * @param easting the easting in meters - */ - public ProjectedMeters(double northing, double easting) { - this.northing = northing; - this.easting = easting; + public static final Creator CREATOR = new Creator() { + public ProjectedMeters createFromParcel(Parcel in) { + return new ProjectedMeters(in); } - /** - * Creates a ProjecteMeters based on another set of projected meters. - * - * @param projectedMeters The projected meters to be based on. - */ - public ProjectedMeters(ProjectedMeters projectedMeters) { - this.northing = projectedMeters.northing; - this.easting = projectedMeters.easting; + public ProjectedMeters[] newArray(int size) { + return new ProjectedMeters[size]; } - - private ProjectedMeters(Parcel in) { - northing = in.readDouble(); - easting = in.readDouble(); - } - - /** - * Get projected meters in north direction. - * - * @return Projected meters in north. - */ - @Override - public double getNorthing() { - return northing; - } - - /** - * Get projected meters in east direction. - * - * @return Projected meters in east. - */ - @Override - public double getEasting() { - return easting; - } - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - - ProjectedMeters projectedMeters = (ProjectedMeters) o; - - return Double.compare(projectedMeters.easting, easting) == 0 && Double.compare(projectedMeters.northing, northing) == 0; - - } - - @Override - public int hashCode() { - int result; - long temp; - temp = Double.doubleToLongBits(easting); - result = (int) (temp ^ (temp >>> 32)); - temp = Double.doubleToLongBits(northing); - result = 31 * result + (int) (temp ^ (temp >>> 32)); - return result; + }; + + private double northing; + private double easting; + + /** + * Creates a ProjectedMeters based on projected meters in north and east direction. + * + * @param northing the northing in meters + * @param easting the easting in meters + */ + public ProjectedMeters(double northing, double easting) { + this.northing = northing; + this.easting = easting; + } + + /** + * Creates a ProjecteMeters based on another set of projected meters. + * + * @param projectedMeters The projected meters to be based on. + */ + public ProjectedMeters(ProjectedMeters projectedMeters) { + this.northing = projectedMeters.northing; + this.easting = projectedMeters.easting; + } + + private ProjectedMeters(Parcel in) { + northing = in.readDouble(); + easting = in.readDouble(); + } + + /** + * Get projected meters in north direction. + * + * @return Projected meters in north. + */ + @Override + public double getNorthing() { + return northing; + } + + /** + * Get projected meters in east direction. + * + * @return Projected meters in east. + */ + @Override + public double getEasting() { + return easting; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; } - - @Override - public String toString() { - return "ProjectedMeters [northing=" + northing + ", easting=" + easting + "]"; - } - - @Override - public int describeContents() { - return 0; + if (o == null || getClass() != o.getClass()) { + return false; } - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeDouble(northing); - out.writeDouble(easting); - } + ProjectedMeters projectedMeters = (ProjectedMeters) o; + + return Double.compare(projectedMeters.easting, easting) == 0 + && Double.compare(projectedMeters.northing, northing) == 0; + + } + + @Override + public int hashCode() { + int result; + long temp; + temp = Double.doubleToLongBits(easting); + result = (int) (temp ^ (temp >>> 32)); + temp = Double.doubleToLongBits(northing); + result = 31 * result + (int) (temp ^ (temp >>> 32)); + return result; + } + + @Override + public String toString() { + return "ProjectedMeters [northing=" + northing + ", easting=" + easting + "]"; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeDouble(northing); + out.writeDouble(easting); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java index de562c3632..45300f248c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/geometry/VisibleRegion.java @@ -12,118 +12,119 @@ import android.os.Parcelable; */ public class VisibleRegion implements Parcelable { - /** - * LatLng object that defines the far left corner of the camera. - */ - public final LatLng farLeft; - - /** - * LatLng object that defines the far right corner of the camera. - */ - public final LatLng farRight; - - /** - * LatLng object that defines the bottom left corner of the camera. - */ - public final LatLng nearLeft; - - /** - * LatLng object that defines the bottom right corner of the camera. - */ - public final LatLng nearRight; - - /** - * The smallest bounding box that includes the visible region defined in this class. - */ - public final LatLngBounds latLngBounds; - - private VisibleRegion(Parcel in) { - this.farLeft = in.readParcelable(LatLng.class.getClassLoader()); - this.farRight = in.readParcelable(LatLng.class.getClassLoader()); - this.nearLeft = in.readParcelable(LatLng.class.getClassLoader()); - this.nearRight = in.readParcelable(LatLng.class.getClassLoader()); - this.latLngBounds = in.readParcelable(LatLngBounds.class.getClassLoader()); + /** + * LatLng object that defines the far left corner of the camera. + */ + public final LatLng farLeft; + + /** + * LatLng object that defines the far right corner of the camera. + */ + public final LatLng farRight; + + /** + * LatLng object that defines the bottom left corner of the camera. + */ + public final LatLng nearLeft; + + /** + * LatLng object that defines the bottom right corner of the camera. + */ + public final LatLng nearRight; + + /** + * The smallest bounding box that includes the visible region defined in this class. + */ + public final LatLngBounds latLngBounds; + + private VisibleRegion(Parcel in) { + this.farLeft = in.readParcelable(LatLng.class.getClassLoader()); + this.farRight = in.readParcelable(LatLng.class.getClassLoader()); + this.nearLeft = in.readParcelable(LatLng.class.getClassLoader()); + this.nearRight = in.readParcelable(LatLng.class.getClassLoader()); + this.latLngBounds = in.readParcelable(LatLngBounds.class.getClassLoader()); + } + + /** + * Creates a new VisibleRegion given the four corners of the camera. + * + * @param farLeft A LatLng object containing the latitude and longitude of the near left corner of the region. + * @param farRight A LatLng object containing the latitude and longitude of the near left corner of the region. + * @param nearLeft A LatLng object containing the latitude and longitude of the near left corner of the region. + * @param nearRight A LatLng object containing the latitude and longitude of the near left corner of the region. + * @param latLngBounds The smallest bounding box that includes the visible region defined in this class. + */ + public VisibleRegion(LatLng farLeft, LatLng farRight, LatLng nearLeft, LatLng nearRight, LatLngBounds latLngBounds) { + this.farLeft = farLeft; + this.farRight = farRight; + this.nearLeft = nearLeft; + this.nearRight = nearRight; + this.latLngBounds = latLngBounds; + } + + /** + * Compares this VisibleRegion to another object. + * If the other object is actually a pointer to this object, + * or if all four corners and the bounds of the two objects are the same, + * this method returns true. Otherwise, this method returns false. + * + * @param o The Object to compare with. + * @return true if both objects are the same object. + */ + @Override + public boolean equals(Object o) { + if (!(o instanceof VisibleRegion)) { + return false; } - - /** - * Creates a new VisibleRegion given the four corners of the camera. - * - * @param farLeft A LatLng object containing the latitude and longitude of the near left corner of the region. - * @param farRight A LatLng object containing the latitude and longitude of the near left corner of the region. - * @param nearLeft A LatLng object containing the latitude and longitude of the near left corner of the region. - * @param nearRight A LatLng object containing the latitude and longitude of the near left corner of the region. - * @param latLngBounds The smallest bounding box that includes the visible region defined in this class. - */ - public VisibleRegion(LatLng farLeft, LatLng farRight, LatLng nearLeft, LatLng nearRight, LatLngBounds latLngBounds) { - this.farLeft = farLeft; - this.farRight = farRight; - this.nearLeft = nearLeft; - this.nearRight = nearRight; - this.latLngBounds = latLngBounds; - } - - /** - * Compares this VisibleRegion to another object. - * If the other object is actually a pointer to this object, - * or if all four corners and the bounds of the two objects are the same, - * this method returns true. Otherwise, this method returns false. - * - * @param o The Object to compare with. - * @return true if both objects are the same object. - */ - @Override - public boolean equals(Object o) { - if (!(o instanceof VisibleRegion)) { - return false; - } - if (o == this) { - return true; - } - - VisibleRegion visibleRegion = (VisibleRegion) o; - return farLeft.equals(visibleRegion.farLeft) - && farRight.equals(visibleRegion.farRight) - && nearLeft.equals(visibleRegion.nearLeft) - && nearRight.equals(visibleRegion.nearRight) - && latLngBounds.equals(visibleRegion.latLngBounds); - } - - @Override - public String toString() { - return "[farLeft [" + farLeft + "], farRight [" + farRight + "], nearLeft [" + nearLeft + "], nearRight [" + nearRight + "], latLngBounds [" + latLngBounds + "]]"; - } - - @Override - public int hashCode() { - return ((farLeft.hashCode() + 90) - + ((farRight.hashCode() + 90) * 1000) - + ((nearLeft.hashCode() + 180) * 1000000) - + ((nearRight.hashCode() + 180) * 1000000000)); - } - - @Override - public int describeContents() { - return 0; + if (o == this) { + return true; } - @Override - public void writeToParcel(Parcel out, int flags) { - out.writeParcelable(farLeft, flags); - out.writeParcelable(farRight, flags); - out.writeParcelable(nearLeft, flags); - out.writeParcelable(nearRight, flags); - out.writeParcelable(latLngBounds, flags); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public VisibleRegion createFromParcel(Parcel in) { - return new VisibleRegion(in); - } - - public VisibleRegion[] newArray(int size) { - return new VisibleRegion[size]; - } + VisibleRegion visibleRegion = (VisibleRegion) o; + return farLeft.equals(visibleRegion.farLeft) + && farRight.equals(visibleRegion.farRight) + && nearLeft.equals(visibleRegion.nearLeft) + && nearRight.equals(visibleRegion.nearRight) + && latLngBounds.equals(visibleRegion.latLngBounds); + } + + @Override + public String toString() { + return "[farLeft [" + farLeft + "], farRight [" + farRight + "], nearLeft [" + nearLeft + "], nearRight [" + + nearRight + "], latLngBounds [" + latLngBounds + "]]"; + } + + @Override + public int hashCode() { + return ((farLeft.hashCode() + 90) + + ((farRight.hashCode() + 90) * 1000) + + ((nearLeft.hashCode() + 180) * 1000000) + + ((nearRight.hashCode() + 180) * 1000000000)); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + out.writeParcelable(farLeft, flags); + out.writeParcelable(farRight, flags); + out.writeParcelable(nearLeft, flags); + out.writeParcelable(nearRight, flags); + out.writeParcelable(latLngBounds, flags); + } + + public static final Parcelable.Creator CREATOR = + new Parcelable.Creator() { + public VisibleRegion createFromParcel(Parcel in) { + return new VisibleRegion(in); + } + + public VisibleRegion[] newArray(int size) { + return new VisibleRegion[size]; + } }; } \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java index 991bb49ab3..ef6b9670db 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/http/HTTPRequest.java @@ -5,6 +5,7 @@ import android.content.Context; import android.content.pm.PackageInfo; import android.os.Build; import android.text.TextUtils; + import timber.log.Timber; import com.mapbox.mapboxsdk.BuildConfig; @@ -31,172 +32,175 @@ import okhttp3.internal.Util; class HTTPRequest implements Callback { - private static OkHttpClient mClient = new OkHttpClient(); - private String USER_AGENT_STRING = null; - - private static final int CONNECTION_ERROR = 0; - private static final int TEMPORARY_ERROR = 1; - private static final int PERMANENT_ERROR = 2; - - // Reentrancy is not needed, but "Lock" is an - // abstract class. - private ReentrantLock mLock = new ReentrantLock(); - - private long mNativePtr = 0; - - private Call mCall; - private Request mRequest; - - private native void nativeOnFailure(int type, String message); - - private native void nativeOnResponse(int code, String etag, String modified, String cacheControl, String expires, String retryAfter, String xRateLimitReset, byte[] body); - - private HTTPRequest(long nativePtr, String resourceUrl, String etag, String modified) { - mNativePtr = nativePtr; - - try { - // Don't try a request if we aren't connected - if (!MapboxAccountManager.getInstance().isConnected()) { - throw new NoRouteToHostException("No Internet connection available."); - } - - HttpUrl httpUrl = HttpUrl.parse(resourceUrl); - final String host = httpUrl.host().toLowerCase(MapboxConstants.MAPBOX_LOCALE); - if (host.equals("mapbox.com") || host.endsWith(".mapbox.com") || host.equals("mapbox.cn") || host.endsWith(".mapbox.cn")) { - if (httpUrl.querySize() == 0) { - resourceUrl = resourceUrl + "?"; - } else { - resourceUrl = resourceUrl + "&"; - } - resourceUrl = resourceUrl + "events=true"; - } - - Request.Builder builder = new Request.Builder() - .url(resourceUrl) - .tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE)) - .addHeader("User-Agent", getUserAgent()); - if (etag.length() > 0) { - builder = builder.addHeader("If-None-Match", etag); - } else if (modified.length() > 0) { - builder = builder.addHeader("If-Modified-Since", modified); - } - mRequest = builder.build(); - mCall = mClient.newCall(mRequest); - mCall.enqueue(this); - } catch (Exception e) { - onFailure(e); - } - } + private static OkHttpClient mClient = new OkHttpClient(); + private String USER_AGENT_STRING = null; - public void cancel() { - // mCall can be null if the constructor gets aborted (e.g, under a NoRouteToHostException). - if (mCall != null) { - mCall.cancel(); - } + private static final int CONNECTION_ERROR = 0; + private static final int TEMPORARY_ERROR = 1; + private static final int PERMANENT_ERROR = 2; - // TODO: We need a lock here because we can try - // to cancel at the same time the request is getting - // answered on the OkHTTP thread. We could get rid of - // this lock by using Runnable when we move Android - // implementation of mbgl::RunLoop to Looper. - mLock.lock(); - mNativePtr = 0; - mLock.unlock(); - } + // Reentrancy is not needed, but "Lock" is an + // abstract class. + private ReentrantLock mLock = new ReentrantLock(); - @Override - public void onResponse(Call call, Response response) throws IOException { - if (response.isSuccessful()) { - Timber.v(String.format("[HTTP] Request was successful (code = %d).", response.code())); - } else { - // We don't want to call this unsuccessful because a 304 isn't really an error - String message = !TextUtils.isEmpty(response.message()) ? response.message() : "No additional information"; - Timber.d(String.format( - "[HTTP] Request with response code = %d: %s", - response.code(), message)); - } + private long mNativePtr = 0; - byte[] body; - try { - body = response.body().bytes(); - } catch (IOException e) { - onFailure(e); - //throw e; - return; - } finally { - response.body().close(); - } + private Call mCall; + private Request mRequest; - mLock.lock(); - if (mNativePtr != 0) { - nativeOnResponse(response.code(), - response.header("ETag"), - response.header("Last-Modified"), - response.header("Cache-Control"), - response.header("Expires"), - response.header("Retry-After"), - response.header("x-rate-limit-reset"), - body); - } - mLock.unlock(); - } + private native void nativeOnFailure(int type, String message); - @Override - public void onFailure(Call call, IOException e) { - onFailure(e); - } + private native void nativeOnResponse(int code, String etag, String modified, String cacheControl, String expires, + String retryAfter, String xRateLimitReset, byte[] body); - private void onFailure(Exception e) { - int type = PERMANENT_ERROR; - if ((e instanceof NoRouteToHostException) || (e instanceof UnknownHostException) || (e instanceof SocketException) || (e instanceof ProtocolException) || (e instanceof SSLException)) { - type = CONNECTION_ERROR; - } else if ((e instanceof InterruptedIOException)) { - type = TEMPORARY_ERROR; - } + private HTTPRequest(long nativePtr, String resourceUrl, String etag, String modified) { + mNativePtr = nativePtr; - String errorMessage = e.getMessage() != null ? e.getMessage() : "Error processing the request"; + try { + // Don't try a request if we aren't connected + if (!MapboxAccountManager.getInstance().isConnected()) { + throw new NoRouteToHostException("No Internet connection available."); + } - if (type == TEMPORARY_ERROR) { - Timber.d(String.format(MapboxConstants.MAPBOX_LOCALE, - "Request failed due to a temporary error: %s", errorMessage)); - } else if (type == CONNECTION_ERROR) { - Timber.i(String.format(MapboxConstants.MAPBOX_LOCALE, - "Request failed due to a connection error: %s", errorMessage)); + HttpUrl httpUrl = HttpUrl.parse(resourceUrl); + final String host = httpUrl.host().toLowerCase(MapboxConstants.MAPBOX_LOCALE); + if (host.equals("mapbox.com") || host.endsWith(".mapbox.com") || host.equals("mapbox.cn") + || host.endsWith(".mapbox.cn")) { + if (httpUrl.querySize() == 0) { + resourceUrl = resourceUrl + "?"; } else { - // PERMANENT_ERROR - Timber.w(String.format(MapboxConstants.MAPBOX_LOCALE, - "Request failed due to a permanent error: %s", errorMessage)); + resourceUrl = resourceUrl + "&"; } + resourceUrl = resourceUrl + "events=true"; + } + + Request.Builder builder = new Request.Builder() + .url(resourceUrl) + .tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE)) + .addHeader("User-Agent", getUserAgent()); + if (etag.length() > 0) { + builder = builder.addHeader("If-None-Match", etag); + } else if (modified.length() > 0) { + builder = builder.addHeader("If-Modified-Since", modified); + } + mRequest = builder.build(); + mCall = mClient.newCall(mRequest); + mCall.enqueue(this); + } catch (Exception exception) { + onFailure(exception); + } + } - mLock.lock(); - if (mNativePtr != 0) { - nativeOnFailure(type, errorMessage); - } - mLock.unlock(); + public void cancel() { + // mCall can be null if the constructor gets aborted (e.g, under a NoRouteToHostException). + if (mCall != null) { + mCall.cancel(); } - private String getUserAgent() { - if (USER_AGENT_STRING == null) { - return USER_AGENT_STRING = Util.toHumanReadableAscii( - String.format("%s %s (%s) Android/%s (%s)", - getApplicationIdentifier(), - BuildConfig.MAPBOX_VERSION_STRING, - BuildConfig.GIT_REVISION_SHORT, - Build.VERSION.SDK_INT, - Build.CPU_ABI) - ); - } else { - return USER_AGENT_STRING; - } + // TODO: We need a lock here because we can try + // to cancel at the same time the request is getting + // answered on the OkHTTP thread. We could get rid of + // this lock by using Runnable when we move Android + // implementation of mbgl::RunLoop to Looper. + mLock.lock(); + mNativePtr = 0; + mLock.unlock(); + } + + @Override + public void onResponse(Call call, Response response) throws IOException { + if (response.isSuccessful()) { + Timber.v(String.format("[HTTP] Request was successful (code = %d).", response.code())); + } else { + // We don't want to call this unsuccessful because a 304 isn't really an error + String message = !TextUtils.isEmpty(response.message()) ? response.message() : "No additional information"; + Timber.d(String.format( + "[HTTP] Request with response code = %d: %s", + response.code(), message)); } - private String getApplicationIdentifier() { - try { - Context context = MapboxAccountManager.getInstance().getApplicationContext(); - PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); - return String.format("%s/%s (%s)", context.getPackageName(), packageInfo.versionName, packageInfo.versionCode); - } catch (Exception e) { - return ""; - } + byte[] body; + try { + body = response.body().bytes(); + } catch (IOException ioException) { + onFailure(ioException); + //throw ioException; + return; + } finally { + response.body().close(); + } + + mLock.lock(); + if (mNativePtr != 0) { + nativeOnResponse(response.code(), + response.header("ETag"), + response.header("Last-Modified"), + response.header("Cache-Control"), + response.header("Expires"), + response.header("Retry-After"), + response.header("x-rate-limit-reset"), + body); + } + mLock.unlock(); + } + + @Override + public void onFailure(Call call, IOException e) { + onFailure(e); + } + + private void onFailure(Exception e) { + int type = PERMANENT_ERROR; + if ((e instanceof NoRouteToHostException) || (e instanceof UnknownHostException) || (e instanceof SocketException) + || (e instanceof ProtocolException) || (e instanceof SSLException)) { + type = CONNECTION_ERROR; + } else if ((e instanceof InterruptedIOException)) { + type = TEMPORARY_ERROR; + } + + String errorMessage = e.getMessage() != null ? e.getMessage() : "Error processing the request"; + + if (type == TEMPORARY_ERROR) { + Timber.d(String.format(MapboxConstants.MAPBOX_LOCALE, + "Request failed due to a temporary error: %s", errorMessage)); + } else if (type == CONNECTION_ERROR) { + Timber.i(String.format(MapboxConstants.MAPBOX_LOCALE, + "Request failed due to a connection error: %s", errorMessage)); + } else { + // PERMANENT_ERROR + Timber.w(String.format(MapboxConstants.MAPBOX_LOCALE, + "Request failed due to a permanent error: %s", errorMessage)); + } + + mLock.lock(); + if (mNativePtr != 0) { + nativeOnFailure(type, errorMessage); + } + mLock.unlock(); + } + + private String getUserAgent() { + if (USER_AGENT_STRING == null) { + return USER_AGENT_STRING = Util.toHumanReadableAscii( + String.format("%s %s (%s) Android/%s (%s)", + getApplicationIdentifier(), + BuildConfig.MAPBOX_VERSION_STRING, + BuildConfig.GIT_REVISION_SHORT, + Build.VERSION.SDK_INT, + Build.CPU_ABI) + ); + } else { + return USER_AGENT_STRING; + } + } + + private String getApplicationIdentifier() { + try { + Context context = MapboxAccountManager.getInstance().getApplicationContext(); + PackageInfo packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0); + return String.format("%s/%s (%s)", context.getPackageName(), packageInfo.versionName, packageInfo.versionCode); + } catch (Exception exception) { + return ""; } + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationListener.java index eb8c4100dc..7d86d8b096 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationListener.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationListener.java @@ -7,10 +7,11 @@ import android.location.Location; */ public interface LocationListener { - /** - * Callback method for receiving location updates from LocationServices. - * @param location The new Location data - */ - void onLocationChanged(Location location); + /** + * Callback method for receiving location updates from LocationServices. + * + * @param location The new Location data + */ + void onLocationChanged(Location location); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java index 6b8cdd1b76..666dcb565f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/location/LocationServices.java @@ -8,6 +8,7 @@ import android.location.Location; import android.location.LocationManager; import android.support.annotation.NonNull; import android.support.v4.content.ContextCompat; + import timber.log.Timber; import com.mapbox.mapboxsdk.telemetry.TelemetryLocationReceiver; @@ -19,169 +20,174 @@ import java.util.concurrent.CopyOnWriteArrayList; /** * Manages locational updates. Contains methods to register and unregister location listeners. *

    - *
  • You can register a {@link LocationListener} with {@link #addLocationListener(LocationListener)} to receive location updates.
  • + *
  • You can register a {@link LocationListener} with {@link #addLocationListener(LocationListener)} to receive + * location updates.
  • *
  • You can unregister a {@link LocationListener} with {@link #removeLocationListener(LocationListener)}.
  • *
*

- * Note: If registering a listener in your Activity.onStart() implementation, you should unregister it in Activity.onStop(). - * (You won't receive location updates when paused, and this will cut down on unnecessary system overhead). - * Do not unregister in Activity.onSaveInstanceState(), because this won't be called if the user moves back in the history stack. + * Note: If registering a listener in your Activity.onStart() implementation, you should unregister it in + * Activity.onStop(). (You won't receive location updates when paused, and this will cut down on unnecessary system + * overhead). Do not unregister in Activity.onSaveInstanceState(), because this won't be called if the user moves back + * in the history stack. *

*/ public class LocationServices implements com.mapzen.android.lost.api.LocationListener { - private static LocationServices instance; - - private Context context; - private LostApiClient locationClient; - private Location lastLocation; - - private CopyOnWriteArrayList locationListeners; - - private boolean isGPSEnabled; - - /** - * Private constructor for singleton LocationServices - */ - private LocationServices(Context context) { - super(); - this.context = context; - // Setup location services - locationClient = new LostApiClient.Builder(context).build(); - locationListeners = new CopyOnWriteArrayList<>(); + private static LocationServices instance; + + private Context context; + private LostApiClient locationClient; + private Location lastLocation; + + private CopyOnWriteArrayList locationListeners; + + private boolean isGpsEnabled; + + /** + * Private constructor for singleton LocationServices + */ + private LocationServices(Context context) { + super(); + this.context = context; + // Setup location services + locationClient = new LostApiClient.Builder(context).build(); + locationListeners = new CopyOnWriteArrayList<>(); + } + + /** + * Primary (singleton) access method for LocationServices + * + * @param context Context + * @return LocationServices + */ + public static LocationServices getLocationServices(@NonNull final Context context) { + if (instance == null) { + instance = new LocationServices(context.getApplicationContext()); } - - /** - * Primary (singleton) access method for LocationServices - * - * @param context Context - * @return LocationServices - */ - public static LocationServices getLocationServices(@NonNull final Context context) { - if (instance == null) { - instance = new LocationServices(context.getApplicationContext()); - } - return instance; + return instance; + } + + /** + * Enabled / Disable GPS focused location tracking + * + * @param enableGPS true if GPS is to be enabled, false if GPS is to be disabled + */ + public void toggleGPS(boolean enableGPS) { + if (!areLocationPermissionsGranted()) { + Timber.w("Location Permissions Not Granted Yet. Try again after requesting."); + return; } - /** - * Enabled / Disable GPS focused location tracking - * - * @param enableGPS true if GPS is to be enabled, false if GPS is to be disabled - */ - public void toggleGPS(boolean enableGPS) { - if (!areLocationPermissionsGranted()) { - Timber.w("Location Permissions Not Granted Yet. Try again after requesting."); - return; - } - - // Disconnect - if (locationClient.isConnected()) { - // Disconnect first to ensure that the new requests are GPS - com.mapzen.android.lost.api.LocationServices.FusedLocationApi.removeLocationUpdates(this); - locationClient.disconnect(); - } - - // Setup Fresh - locationClient.connect(); - Location lastLocation = com.mapzen.android.lost.api.LocationServices.FusedLocationApi.getLastLocation(); - if (lastLocation != null) { - this.lastLocation = lastLocation; - } - - LocationRequest locationRequest; - - if (enableGPS) { - // LocationRequest Tuned for GPS - locationRequest = LocationRequest.create() - .setFastestInterval(1000) - .setSmallestDisplacement(3.0f) - .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); - - com.mapzen.android.lost.api.LocationServices.FusedLocationApi.requestLocationUpdates(locationRequest, this); - } else { - // LocationRequest Tuned for PASSIVE - locationRequest = LocationRequest.create() - .setFastestInterval(1000) - .setSmallestDisplacement(3.0f) - .setPriority(LocationRequest.PRIORITY_NO_POWER); - - com.mapzen.android.lost.api.LocationServices.FusedLocationApi.requestLocationUpdates(locationRequest, this); - } - - isGPSEnabled = enableGPS; + // Disconnect + if (locationClient.isConnected()) { + // Disconnect first to ensure that the new requests are GPS + com.mapzen.android.lost.api.LocationServices.FusedLocationApi.removeLocationUpdates(this); + locationClient.disconnect(); } - /** - * Returns if the GPS sensor is currently enabled - * - * @return active state of the GPS - */ - public boolean isGPSEnabled() { - return isGPSEnabled; + // Setup Fresh + locationClient.connect(); + Location lastLocation = com.mapzen.android.lost.api.LocationServices.FusedLocationApi.getLastLocation(); + if (lastLocation != null) { + this.lastLocation = lastLocation; } - /** - * Called when the location has changed. - * - * @param location The updated location - */ - @Override - public void onLocationChanged(Location location) { -// Timber.d("onLocationChanged()..." + location); - this.lastLocation = location; - - // Update Listeners - for (LocationListener listener : this.locationListeners) { - listener.onLocationChanged(location); - } - - // Update the Telemetry Receiver - Intent locIntent = new Intent(TelemetryLocationReceiver.INTENT_STRING); - locIntent.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); - context.sendBroadcast(locIntent); - } + LocationRequest locationRequest; - /** - * Last known location - * - * @return Last known location data - */ - public Location getLastLocation() { - return lastLocation; - } + if (enableGPS) { + // LocationRequest Tuned for GPS + locationRequest = LocationRequest.create() + .setFastestInterval(1000) + .setSmallestDisplacement(3.0f) + .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); - /** - * Registers a LocationListener to receive location updates - * - * @param locationListener LocationListener - */ - public void addLocationListener(@NonNull LocationListener locationListener) { - if (!this.locationListeners.contains(locationListener)) { - this.locationListeners.add(locationListener); - } + com.mapzen.android.lost.api.LocationServices.FusedLocationApi.requestLocationUpdates(locationRequest, this); + } else { + // LocationRequest Tuned for PASSIVE + locationRequest = LocationRequest.create() + .setFastestInterval(1000) + .setSmallestDisplacement(3.0f) + .setPriority(LocationRequest.PRIORITY_NO_POWER); + + com.mapzen.android.lost.api.LocationServices.FusedLocationApi.requestLocationUpdates(locationRequest, this); } - /** - * Unregister a LocationListener to stop receiving location updates - * - * @param locationListener LocationListener to remove - * @return True if LocationListener was found and removed, False if it was not - */ - public boolean removeLocationListener(@NonNull LocationListener locationListener) { - return this.locationListeners.remove(locationListener); + isGpsEnabled = enableGPS; + } + + /** + * Returns if the GPS sensor is currently enabled + * + * @return active state of the GPS + */ + public boolean isGpsEnabled() { + return isGpsEnabled; + } + + /** + * Called when the location has changed. + * + * @param location The updated location + */ + @Override + public void onLocationChanged(Location location) { + // Timber.d("onLocationChanged()..." + location); + this.lastLocation = location; + + // Update Listeners + for (LocationListener listener : this.locationListeners) { + listener.onLocationChanged(location); } - /** - * Check status of Location Permissions - * @return True if granted to the app, False if not - */ - public boolean areLocationPermissionsGranted() { - if ((ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) && - (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)) { - Timber.w("Location Permissions Not Granted Yet. Try again after requesting."); - return false; - } - return true; + // Update the Telemetry Receiver + Intent locIntent = new Intent(TelemetryLocationReceiver.INTENT_STRING); + locIntent.putExtra(LocationManager.KEY_LOCATION_CHANGED, location); + context.sendBroadcast(locIntent); + } + + /** + * Last known location + * + * @return Last known location data + */ + public Location getLastLocation() { + return lastLocation; + } + + /** + * Registers a LocationListener to receive location updates + * + * @param locationListener LocationListener + */ + public void addLocationListener(@NonNull LocationListener locationListener) { + if (!this.locationListeners.contains(locationListener)) { + this.locationListeners.add(locationListener); + } + } + + /** + * Unregister a LocationListener to stop receiving location updates + * + * @param locationListener LocationListener to remove + * @return True if LocationListener was found and removed, False if it was not + */ + public boolean removeLocationListener(@NonNull LocationListener locationListener) { + return this.locationListeners.remove(locationListener); + } + + /** + * Check status of Location Permissions + * + * @return True if granted to the app, False if not + */ + public boolean areLocationPermissionsGranted() { + if ((ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) + != PackageManager.PERMISSION_GRANTED) + && (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) + != PackageManager.PERMISSION_GRANTED)) { + Timber.w("Location Permissions Not Granted Yet. Try again after requesting."); + return false; } + return true; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java index eb90ae764b..bffcf2fa2f 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/AnnotationManager.java @@ -30,656 +30,659 @@ import java.util.List; * Responsible for referencing {@link InfoWindowManager} and {@link MarkerViewManager}. *

*

- * Exposes convenience methods to add/remove/update all subtypes of annotations found in com.mapbox.mapboxsdk.annotations. + * Exposes convenience methods to add/remove/update all subtypes of annotations found in + * com.mapbox.mapboxsdk.annotations. *

*/ class AnnotationManager { - private final NativeMapView nativeMapView; - private final MapView mapView; - private final IconManager iconManager; - private final InfoWindowManager infoWindowManager = new InfoWindowManager(); - private final MarkerViewManager markerViewManager; - private final LongSparseArray annotations = new LongSparseArray<>(); - private final List selectedMarkers = new ArrayList<>(); - - private MapboxMap mapboxMap; - - private HashMap markerMap = new HashMap<>(); - private MapboxMap.OnMarkerClickListener onMarkerClickListener; - - AnnotationManager(NativeMapView view, MapView mapView, MarkerViewManager markerViewManager) { - this.nativeMapView = view; - this.mapView = mapView; - this.iconManager = new IconManager(nativeMapView); - this.markerViewManager = markerViewManager; - if (view != null) { - // null checking needed for unit tests - nativeMapView.addOnMapChangedListener(markerViewManager); + private final NativeMapView nativeMapView; + private final MapView mapView; + private final IconManager iconManager; + private final InfoWindowManager infoWindowManager = new InfoWindowManager(); + private final MarkerViewManager markerViewManager; + private final LongSparseArray annotations = new LongSparseArray<>(); + private final List selectedMarkers = new ArrayList<>(); + + private MapboxMap mapboxMap; + + private HashMap markerMap = new HashMap<>(); + private MapboxMap.OnMarkerClickListener onMarkerClickListener; + + AnnotationManager(NativeMapView view, MapView mapView, MarkerViewManager markerViewManager) { + this.nativeMapView = view; + this.mapView = mapView; + this.iconManager = new IconManager(nativeMapView); + this.markerViewManager = markerViewManager; + if (view != null) { + // null checking needed for unit tests + nativeMapView.addOnMapChangedListener(markerViewManager); + } + } + + // TODO refactor MapboxMap out for Projection and Transform + // Requires removing MapboxMap from Annotations by using Peer model from #6912 + AnnotationManager bind(MapboxMap mapboxMap) { + this.mapboxMap = mapboxMap; + this.markerViewManager.bind(mapboxMap); + return this; + } + + // + // Annotations + // + + Annotation getAnnotation(long id) { + return annotations.get(id); + } + + List getAnnotations() { + List annotations = new ArrayList<>(); + for (int i = 0; i < this.annotations.size(); i++) { + annotations.add(this.annotations.get(this.annotations.keyAt(i))); + } + return annotations; + } + + void removeAnnotation(@NonNull Annotation annotation) { + if (annotation instanceof Marker) { + Marker marker = (Marker) annotation; + marker.hideInfoWindow(); + if (marker instanceof MarkerView) { + markerViewManager.removeMarkerView((MarkerView) marker); + } + } + long id = annotation.getId(); + if (nativeMapView != null) { + nativeMapView.removeAnnotation(id); + } + annotations.remove(id); + } + + void removeAnnotation(long id) { + if (nativeMapView != null) { + nativeMapView.removeAnnotation(id); + } + annotations.remove(id); + } + + void removeAnnotations(@NonNull List annotationList) { + int count = annotationList.size(); + long[] ids = new long[count]; + for (int i = 0; i < count; i++) { + Annotation annotation = annotationList.get(i); + if (annotation instanceof Marker) { + Marker marker = (Marker) annotation; + marker.hideInfoWindow(); + if (marker instanceof MarkerView) { + markerViewManager.removeMarkerView((MarkerView) marker); } + } + ids[i] = annotationList.get(i).getId(); } - // TODO refactor MapboxMap out for Projection and Transform - // Requires removing MapboxMap from Annotations by using Peer model from #6912 - AnnotationManager bind(MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; - this.markerViewManager.bind(mapboxMap); - return this; + if (nativeMapView != null) { + nativeMapView.removeAnnotations(ids); } - // - // Annotations - // - - Annotation getAnnotation(long id) { - return annotations.get(id); + for (long id : ids) { + annotations.remove(id); } + } - List getAnnotations() { - List annotations = new ArrayList<>(); - for (int i = 0; i < this.annotations.size(); i++) { - annotations.add(this.annotations.get(this.annotations.keyAt(i))); + void removeAnnotations() { + Annotation annotation; + int count = annotations.size(); + long[] ids = new long[count]; + for (int i = 0; i < count; i++) { + ids[i] = annotations.keyAt(i); + annotation = annotations.get(ids[i]); + if (annotation instanceof Marker) { + Marker marker = (Marker) annotation; + marker.hideInfoWindow(); + if (marker instanceof MarkerView) { + markerViewManager.removeMarkerView((MarkerView) marker); } - return annotations; + } } - void removeAnnotation(@NonNull Annotation annotation) { - if (annotation instanceof Marker) { - Marker marker = (Marker) annotation; - marker.hideInfoWindow(); - if (marker instanceof MarkerView) { - markerViewManager.removeMarkerView((MarkerView) marker); - } - } - long id = annotation.getId(); - if (nativeMapView != null) { - nativeMapView.removeAnnotation(id); - } - annotations.remove(id); + if (nativeMapView != null) { + nativeMapView.removeAnnotations(ids); } - void removeAnnotation(long id) { - if (nativeMapView != null) { - nativeMapView.removeAnnotation(id); - } - annotations.remove(id); - } - - void removeAnnotations(@NonNull List annotationList) { - int count = annotationList.size(); - long[] ids = new long[count]; - for (int i = 0; i < count; i++) { - Annotation annotation = annotationList.get(i); - if (annotation instanceof Marker) { - Marker marker = (Marker) annotation; - marker.hideInfoWindow(); - if (marker instanceof MarkerView) { - markerViewManager.removeMarkerView((MarkerView) marker); - } - } - ids[i] = annotationList.get(i).getId(); - } - - if (nativeMapView != null) { - nativeMapView.removeAnnotations(ids); - } + annotations.clear(); + } - for (long id : ids) { - annotations.remove(id); - } - } + // + // Markers + // - void removeAnnotations() { - Annotation annotation; - int count = annotations.size(); - long[] ids = new long[count]; - for (int i = 0; i < count; i++) { - ids[i] = annotations.keyAt(i); - annotation = annotations.get(ids[i]); - if (annotation instanceof Marker) { - Marker marker = (Marker) annotation; - marker.hideInfoWindow(); - if (marker instanceof MarkerView) { - markerViewManager.removeMarkerView((MarkerView) marker); - } - } - } + List addMarkers(@NonNull List markerOptionsList, @NonNull MapboxMap mapboxMap) { + int count = markerOptionsList.size(); + List markers = new ArrayList<>(count); + if (count > 0) { + BaseMarkerOptions markerOptions; + Marker marker; + for (int i = 0; i < count; i++) { + markerOptions = markerOptionsList.get(i); + marker = prepareMarker(markerOptions); + markers.add(marker); + } + if (markers.size() > 0) { + long[] ids = null; if (nativeMapView != null) { - nativeMapView.removeAnnotations(ids); - } - - annotations.clear(); - } - - // - // Markers - // - - Marker addMarker(@NonNull BaseMarkerOptions markerOptions, @NonNull MapboxMap mapboxMap) { - Marker marker = prepareMarker(markerOptions); - long id = nativeMapView != null ? nativeMapView.addMarker(marker) : 0; - marker.setMapboxMap(mapboxMap); - marker.setId(id); - annotations.put(id, marker); - return marker; + ids = nativeMapView.addMarkers(markers); + } + + long id = 0; + Marker m; + for (int i = 0; i < markers.size(); i++) { + m = markers.get(i); + m.setMapboxMap(mapboxMap); + if (ids != null) { + id = ids[i]; + } else { + //unit test + id++; + } + m.setId(id); + annotations.put(id, m); + } + + } + } + return markers; + } + + private Marker prepareMarker(BaseMarkerOptions markerOptions) { + Marker marker = markerOptions.getMarker(); + Icon icon = iconManager.loadIconForMarker(marker); + marker.setTopOffsetPixels(iconManager.getTopOffsetPixelsForIcon(icon)); + return marker; + } + + Marker addMarker(@NonNull BaseMarkerOptions markerOptions, @NonNull MapboxMap mapboxMap) { + Marker marker = prepareMarker(markerOptions); + long id = nativeMapView != null ? nativeMapView.addMarker(marker) : 0; + marker.setMapboxMap(mapboxMap); + marker.setId(id); + annotations.put(id, marker); + return marker; + } + + MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions, @NonNull MapboxMap mapboxMap) { + MarkerView marker = prepareViewMarker(markerOptions); + marker.setMapboxMap(mapboxMap); + long id = nativeMapView.addMarker(marker); + marker.setId(id); + annotations.put(id, marker); + return marker; + } + + public MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions, @NonNull MapboxMap mapboxMap, + final MarkerViewManager.OnMarkerViewAddedListener onMarkerViewAddedListener) { + final MarkerView marker = prepareViewMarker(markerOptions); + + // add marker to map + marker.setMapboxMap(mapboxMap); + long id = nativeMapView.addMarker(marker); + marker.setId(id); + annotations.put(id, marker); + + markerViewManager.addOnMarkerViewAddedListener(marker, onMarkerViewAddedListener); + markerViewManager.setWaitingForRenderInvoke(true); + return marker; + } + + + List addMarkerViews(@NonNull List markerViewOptions, + @NonNull MapboxMap mapboxMap) { + List markers = new ArrayList<>(); + for (BaseMarkerViewOptions markerViewOption : markerViewOptions) { + // if last marker + if (markerViewOptions.indexOf(markerViewOption) == markerViewOptions.size() - 1) { + // get notified when render occurs to invalidate and draw MarkerViews + markerViewManager.setWaitingForRenderInvoke(true); + } + // add marker to map + MarkerView marker = prepareViewMarker(markerViewOption); + marker.setMapboxMap(mapboxMap); + long id = nativeMapView.addMarker(marker); + marker.setId(id); + annotations.put(id, marker); + markers.add(marker); } + markerViewManager.invalidateViewMarkersInVisibleRegion(); + return markers; + } - List addMarkers(@NonNull List markerOptionsList, @NonNull MapboxMap mapboxMap) { - int count = markerOptionsList.size(); - List markers = new ArrayList<>(count); - if (count > 0) { - BaseMarkerOptions markerOptions; - Marker marker; - for (int i = 0; i < count; i++) { - markerOptions = markerOptionsList.get(i); - marker = prepareMarker(markerOptions); - markers.add(marker); - } - - if (markers.size() > 0) { - long[] ids = null; - if (nativeMapView != null) { - ids = nativeMapView.addMarkers(markers); - } - - long id = 0; - Marker m; - for (int i = 0; i < markers.size(); i++) { - m = markers.get(i); - m.setMapboxMap(mapboxMap); - if (ids != null) { - id = ids[i]; - } else { - //unit test - id++; - } - m.setId(id); - annotations.put(id, m); - } - - } - } - return markers; - } + private MarkerView prepareViewMarker(BaseMarkerViewOptions markerViewOptions) { + MarkerView marker = markerViewOptions.getMarker(); + iconManager.loadIconForMarkerView(marker); + return marker; + } - private Marker prepareMarker(BaseMarkerOptions markerOptions) { - Marker marker = markerOptions.getMarker(); - Icon icon = iconManager.loadIconForMarker(marker); - marker.setTopOffsetPixels(iconManager.getTopOffsetPixelsForIcon(icon)); - return marker; + void updateMarker(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap) { + if (updatedMarker == null) { + return; } - MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions, @NonNull MapboxMap mapboxMap) { - MarkerView marker = prepareViewMarker(markerOptions); - marker.setMapboxMap(mapboxMap); - long id = nativeMapView.addMarker(marker); - marker.setId(id); - annotations.put(id, marker); - return marker; + if (updatedMarker.getId() == -1) { + return; } - public MarkerView addMarker(@NonNull BaseMarkerViewOptions markerOptions, @NonNull MapboxMap mapboxMap, final MarkerViewManager.OnMarkerViewAddedListener onMarkerViewAddedListener) { - final MarkerView marker = prepareViewMarker(markerOptions); - - // add marker to map - marker.setMapboxMap(mapboxMap); - long id = nativeMapView.addMarker(marker); - marker.setId(id); - annotations.put(id, marker); - - markerViewManager.addOnMarkerViewAddedListener(marker, onMarkerViewAddedListener); - markerViewManager.setWaitingForRenderInvoke(true); - return marker; + if (!(updatedMarker instanceof MarkerView)) { + iconManager.ensureIconLoaded(updatedMarker, mapboxMap); } + nativeMapView.updateMarker(updatedMarker); - List addMarkerViews(@NonNull List markerViewOptions, @NonNull MapboxMap mapboxMap) { - List markers = new ArrayList<>(); - for (BaseMarkerViewOptions markerViewOption : markerViewOptions) { - // if last marker - if (markerViewOptions.indexOf(markerViewOption) == markerViewOptions.size() - 1) { - // get notified when render occurs to invalidate and draw MarkerViews - markerViewManager.setWaitingForRenderInvoke(true); - } - // add marker to map - MarkerView marker = prepareViewMarker(markerViewOption); - marker.setMapboxMap(mapboxMap); - long id = nativeMapView.addMarker(marker); - marker.setId(id); - annotations.put(id, marker); - markers.add(marker); - } - markerViewManager.invalidateViewMarkersInVisibleRegion(); - return markers; + int index = annotations.indexOfKey(updatedMarker.getId()); + if (index > -1) { + annotations.setValueAt(index, updatedMarker); } + } - private MarkerView prepareViewMarker(BaseMarkerViewOptions markerViewOptions) { - MarkerView marker = markerViewOptions.getMarker(); - iconManager.loadIconForMarkerView(marker); - return marker; + List getMarkers() { + List markers = new ArrayList<>(); + Annotation annotation; + for (int i = 0; i < annotations.size(); i++) { + annotation = annotations.get(annotations.keyAt(i)); + if (annotation instanceof Marker) { + markers.add((Marker) annotation); + } } + return markers; + } - void updateMarker(@NonNull Marker updatedMarker, @NonNull MapboxMap mapboxMap) { - if (updatedMarker == null) { - return; - } - - if (updatedMarker.getId() == -1) { - return; - } + void setOnMarkerClickListener(@Nullable MapboxMap.OnMarkerClickListener listener) { + onMarkerClickListener = listener; + } - if (!(updatedMarker instanceof MarkerView)) { - iconManager.ensureIconLoaded(updatedMarker, mapboxMap); - } - - nativeMapView.updateMarker(updatedMarker); - - int index = annotations.indexOfKey(updatedMarker.getId()); - if (index > -1) { - annotations.setValueAt(index, updatedMarker); - } + void selectMarker(@NonNull Marker marker) { + if (selectedMarkers.contains(marker)) { + return; } - List getMarkers() { - List markers = new ArrayList<>(); - Annotation annotation; - for (int i = 0; i < annotations.size(); i++) { - annotation = annotations.get(annotations.keyAt(i)); - if (annotation instanceof Marker) { - markers.add((Marker) annotation); - } - } - return markers; + // Need to deselect any currently selected annotation first + if (!infoWindowManager.isAllowConcurrentMultipleOpenInfoWindows()) { + deselectMarkers(); } - void setOnMarkerClickListener(@Nullable MapboxMap.OnMarkerClickListener listener) { - onMarkerClickListener = listener; + if (marker instanceof MarkerView) { + markerViewManager.select((MarkerView) marker, false); + markerViewManager.ensureInfoWindowOffset((MarkerView) marker); } - void selectMarker(@NonNull Marker marker) { - if (selectedMarkers.contains(marker)) { - return; - } - - // Need to deselect any currently selected annotation first - if (!infoWindowManager.isAllowConcurrentMultipleOpenInfoWindows()) { - deselectMarkers(); - } - - if (marker instanceof MarkerView) { - markerViewManager.select((MarkerView) marker, false); - markerViewManager.ensureInfoWindowOffset((MarkerView) marker); - } + if (infoWindowManager.isInfoWindowValidForMarker(marker) || infoWindowManager.getInfoWindowAdapter() != null) { + infoWindowManager.add(marker.showInfoWindow(mapboxMap, mapView)); + } - if (infoWindowManager.isInfoWindowValidForMarker(marker) || infoWindowManager.getInfoWindowAdapter() != null) { - infoWindowManager.add(marker.showInfoWindow(mapboxMap, mapView)); - } + // only add to selected markers if user didn't handle the click event themselves #3176 + selectedMarkers.add(marker); + } - // only add to selected markers if user didn't handle the click event themselves #3176 - selectedMarkers.add(marker); + void deselectMarkers() { + if (selectedMarkers.isEmpty()) { + return; } - void deselectMarkers() { - if (selectedMarkers.isEmpty()) { - return; - } + for (Marker marker : selectedMarkers) { + if (marker.isInfoWindowShown()) { + marker.hideInfoWindow(); + } - for (Marker marker : selectedMarkers) { - if (marker.isInfoWindowShown()) { - marker.hideInfoWindow(); - } - - if (marker instanceof MarkerView) { - markerViewManager.deselect((MarkerView) marker, false); - } - } - - // Removes all selected markers from the list - selectedMarkers.clear(); + if (marker instanceof MarkerView) { + markerViewManager.deselect((MarkerView) marker, false); + } } - void deselectMarker(@NonNull Marker marker) { - if (!selectedMarkers.contains(marker)) { - return; - } - - if (marker.isInfoWindowShown()) { - marker.hideInfoWindow(); - } + // Removes all selected markers from the list + selectedMarkers.clear(); + } - if (marker instanceof MarkerView) { - markerViewManager.deselect((MarkerView) marker, false); - } + void deselectMarker(@NonNull Marker marker) { + if (!selectedMarkers.contains(marker)) { + return; + } - selectedMarkers.remove(marker); + if (marker.isInfoWindowShown()) { + marker.hideInfoWindow(); } - List getSelectedMarkers() { - return selectedMarkers; + if (marker instanceof MarkerView) { + markerViewManager.deselect((MarkerView) marker, false); } - public List getMarkersInRect(@NonNull RectF rectangle) { - // convert Rectangle to be density depedent - float pixelRatio = nativeMapView.getPixelRatio(); - RectF rect = new RectF(rectangle.left / pixelRatio, - rectangle.top / pixelRatio, - rectangle.right / pixelRatio, - rectangle.bottom / pixelRatio); + selectedMarkers.remove(marker); + } - long[] ids = nativeMapView.queryPointAnnotations(rect); + List getSelectedMarkers() { + return selectedMarkers; + } - List idsList = new ArrayList<>(ids.length); - for (long id : ids) { - idsList.add(id); - } + public List getMarkersInRect(@NonNull RectF rectangle) { + // convert Rectangle to be density depedent + float pixelRatio = nativeMapView.getPixelRatio(); + RectF rect = new RectF(rectangle.left / pixelRatio, + rectangle.top / pixelRatio, + rectangle.right / pixelRatio, + rectangle.bottom / pixelRatio); - List annotations = new ArrayList<>(ids.length); - List annotationList = getAnnotations(); - int count = annotationList.size(); - for (int i = 0; i < count; i++) { - Annotation annotation = annotationList.get(i); - if (annotation instanceof com.mapbox.mapboxsdk.annotations.Marker && idsList.contains(annotation.getId())) { - annotations.add((com.mapbox.mapboxsdk.annotations.Marker) annotation); - } - } + long[] ids = nativeMapView.queryPointAnnotations(rect); - return new ArrayList<>(annotations); + List idsList = new ArrayList<>(ids.length); + for (long id : ids) { + idsList.add(id); } - public List getMarkerViewsInRect(@NonNull RectF rectangle) { - float pixelRatio = nativeMapView.getPixelRatio(); - RectF rect = new RectF(rectangle.left / pixelRatio, - rectangle.top / pixelRatio, - rectangle.right / pixelRatio, - rectangle.bottom / pixelRatio); + List annotations = new ArrayList<>(ids.length); + List annotationList = getAnnotations(); + int count = annotationList.size(); + for (int i = 0; i < count; i++) { + Annotation annotation = annotationList.get(i); + if (annotation instanceof com.mapbox.mapboxsdk.annotations.Marker && idsList.contains(annotation.getId())) { + annotations.add((com.mapbox.mapboxsdk.annotations.Marker) annotation); + } + } - long[] ids = nativeMapView.queryPointAnnotations(rect); + return new ArrayList<>(annotations); + } - List idsList = new ArrayList<>(ids.length); - for (long id : ids) { - idsList.add(id); - } + public List getMarkerViewsInRect(@NonNull RectF rectangle) { + float pixelRatio = nativeMapView.getPixelRatio(); + RectF rect = new RectF(rectangle.left / pixelRatio, + rectangle.top / pixelRatio, + rectangle.right / pixelRatio, + rectangle.bottom / pixelRatio); - List annotations = new ArrayList<>(ids.length); - List annotationList = getAnnotations(); - int count = annotationList.size(); - for (int i = 0; i < count; i++) { - Annotation annotation = annotationList.get(i); - if (annotation instanceof MarkerView && idsList.contains(annotation.getId())) { - annotations.add((MarkerView) annotation); - } - } + long[] ids = nativeMapView.queryPointAnnotations(rect); - return new ArrayList<>(annotations); + List idsList = new ArrayList<>(ids.length); + for (long id : ids) { + idsList.add(id); } - // - // Polygons - // - - Polygon addPolygon(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap) { - Polygon polygon = polygonOptions.getPolygon(); - if (!polygon.getPoints().isEmpty()) { - long id = nativeMapView != null ? nativeMapView.addPolygon(polygon) : 0; - polygon.setId(id); - polygon.setMapboxMap(mapboxMap); - annotations.put(id, polygon); - } - return polygon; + List annotations = new ArrayList<>(ids.length); + List annotationList = getAnnotations(); + int count = annotationList.size(); + for (int i = 0; i < count; i++) { + Annotation annotation = annotationList.get(i); + if (annotation instanceof MarkerView && idsList.contains(annotation.getId())) { + annotations.add((MarkerView) annotation); + } } - List addPolygons(@NonNull List polygonOptionsList, @NonNull MapboxMap mapboxMap) { - int count = polygonOptionsList.size(); - - Polygon polygon; - List polygons = new ArrayList<>(count); - if (count > 0) { - for (PolygonOptions polygonOptions : polygonOptionsList) { - polygon = polygonOptions.getPolygon(); - if (!polygon.getPoints().isEmpty()) { - polygons.add(polygon); - } - } + return new ArrayList<>(annotations); + } - long[] ids = null; - if (nativeMapView != null) { - ids = nativeMapView.addPolygons(polygons); - } + // + // Polygons + // - long id = 0; - for (int i = 0; i < polygons.size(); i++) { - polygon = polygons.get(i); - polygon.setMapboxMap(mapboxMap); - if (ids != null) { - id = ids[i]; - } else { - // unit test - id++; - } - polygon.setId(id); - annotations.put(id, polygon); - } - } - return polygons; + Polygon addPolygon(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap) { + Polygon polygon = polygonOptions.getPolygon(); + if (!polygon.getPoints().isEmpty()) { + long id = nativeMapView != null ? nativeMapView.addPolygon(polygon) : 0; + polygon.setId(id); + polygon.setMapboxMap(mapboxMap); + annotations.put(id, polygon); } + return polygon; + } - void updatePolygon(Polygon polygon) { - if (polygon == null) { - return; - } + List addPolygons(@NonNull List polygonOptionsList, @NonNull MapboxMap mapboxMap) { + int count = polygonOptionsList.size(); - if (polygon.getId() == -1) { - return; + Polygon polygon; + List polygons = new ArrayList<>(count); + if (count > 0) { + for (PolygonOptions polygonOptions : polygonOptionsList) { + polygon = polygonOptions.getPolygon(); + if (!polygon.getPoints().isEmpty()) { + polygons.add(polygon); } + } - nativeMapView.updatePolygon(polygon); + long[] ids = null; + if (nativeMapView != null) { + ids = nativeMapView.addPolygons(polygons); + } - int index = annotations.indexOfKey(polygon.getId()); - if (index > -1) { - annotations.setValueAt(index, polygon); + long id = 0; + for (int i = 0; i < polygons.size(); i++) { + polygon = polygons.get(i); + polygon.setMapboxMap(mapboxMap); + if (ids != null) { + id = ids[i]; + } else { + // unit test + id++; } + polygon.setId(id); + annotations.put(id, polygon); + } } + return polygons; + } - List getPolygons() { - List polygons = new ArrayList<>(); - Annotation annotation; - for (int i = 0; i < annotations.size(); i++) { - annotation = annotations.get(annotations.keyAt(i)); - if (annotation instanceof Polygon) { - polygons.add((Polygon) annotation); - } - } - return polygons; + void updatePolygon(Polygon polygon) { + if (polygon == null) { + return; } - // - // Polylines - // - - Polyline addPolyline(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap) { - Polyline polyline = polylineOptions.getPolyline(); - if (!polyline.getPoints().isEmpty()) { - long id = nativeMapView != null ? nativeMapView.addPolyline(polyline) : 0; - polyline.setMapboxMap(mapboxMap); - polyline.setId(id); - annotations.put(id, polyline); - } - return polyline; + if (polygon.getId() == -1) { + return; } - List addPolylines(@NonNull List polylineOptionsList, @NonNull MapboxMap mapboxMap) { - int count = polylineOptionsList.size(); - Polyline polyline; - List polylines = new ArrayList<>(count); + nativeMapView.updatePolygon(polygon); - if (count > 0) { - for (PolylineOptions options : polylineOptionsList) { - polyline = options.getPolyline(); - if (!polyline.getPoints().isEmpty()) { - polylines.add(polyline); - } - } - - long[] ids = null; - if (nativeMapView != null) { - ids = nativeMapView.addPolylines(polylines); - } - - long id = 0; - Polyline p; - - for (int i = 0; i < polylines.size(); i++) { - p = polylines.get(i); - p.setMapboxMap(mapboxMap); - if (ids != null) { - id = ids[i]; - } else { - // unit test - id++; - } - p.setId(id); - annotations.put(id, p); - } - } - return polylines; + int index = annotations.indexOfKey(polygon.getId()); + if (index > -1) { + annotations.setValueAt(index, polygon); } + } - void updatePolyline(Polyline polyline) { - if (polyline == null) { - return; - } - - if (polyline.getId() == -1) { - return; - } - - nativeMapView.updatePolyline(polyline); - - int index = annotations.indexOfKey(polyline.getId()); - if (index > -1) { - annotations.setValueAt(index, polyline); - } + List getPolygons() { + List polygons = new ArrayList<>(); + Annotation annotation; + for (int i = 0; i < annotations.size(); i++) { + annotation = annotations.get(annotations.keyAt(i)); + if (annotation instanceof Polygon) { + polygons.add((Polygon) annotation); + } } + return polygons; + } - List getPolylines() { - List polylines = new ArrayList<>(); - Annotation annotation; - for (int i = 0; i < annotations.size(); i++) { - annotation = annotations.get(annotations.keyAt(i)); - if (annotation instanceof Polyline) { - polylines.add((Polyline) annotation); - } - } - return polylines; - } + // + // Polylines + // - InfoWindowManager getInfoWindowManager() { - return infoWindowManager; + Polyline addPolyline(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap) { + Polyline polyline = polylineOptions.getPolyline(); + if (!polyline.getPoints().isEmpty()) { + long id = nativeMapView != null ? nativeMapView.addPolyline(polyline) : 0; + polyline.setMapboxMap(mapboxMap); + polyline.setId(id); + annotations.put(id, polyline); } + return polyline; + } - MarkerViewManager getMarkerViewManager() { - return markerViewManager; - } - - void adjustTopOffsetPixels(MapboxMap mapboxMap) { - 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( - iconManager.getTopOffsetPixelsForIcon(marker.getIcon())); - } - } + List addPolylines(@NonNull List polylineOptionsList, @NonNull MapboxMap mapboxMap) { + int count = polylineOptionsList.size(); + Polyline polyline; + List polylines = new ArrayList<>(count); - for (Marker marker : selectedMarkers) { - if (marker.isInfoWindowShown()) { - marker.hideInfoWindow(); - marker.showInfoWindow(mapboxMap, mapView); - } + if (count > 0) { + for (PolylineOptions options : polylineOptionsList) { + polyline = options.getPolyline(); + if (!polyline.getPoints().isEmpty()) { + polylines.add(polyline); } - } + } + + long[] ids = null; + if (nativeMapView != null) { + ids = nativeMapView.addPolylines(polylines); + } + + long id = 0; + Polyline p; + + for (int i = 0; i < polylines.size(); i++) { + p = polylines.get(i); + p.setMapboxMap(mapboxMap); + if (ids != null) { + id = ids[i]; + } else { + // unit test + id++; + } + p.setId(id); + annotations.put(id, p); + } + } + return polylines; + } + + void updatePolyline(Polyline polyline) { + if (polyline == null) { + return; + } + + if (polyline.getId() == -1) { + return; + } + + nativeMapView.updatePolyline(polyline); + + int index = annotations.indexOfKey(polyline.getId()); + if (index > -1) { + annotations.setValueAt(index, polyline); + } + } + + List getPolylines() { + List polylines = new ArrayList<>(); + Annotation annotation; + for (int i = 0; i < annotations.size(); i++) { + annotation = annotations.get(annotations.keyAt(i)); + if (annotation instanceof Polyline) { + polylines.add((Polyline) annotation); + } + } + return polylines; + } + + InfoWindowManager getInfoWindowManager() { + return infoWindowManager; + } + + MarkerViewManager getMarkerViewManager() { + return markerViewManager; + } + + void adjustTopOffsetPixels(MapboxMap mapboxMap) { + 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( + iconManager.getTopOffsetPixelsForIcon(marker.getIcon())); + } + } + + for (Marker marker : selectedMarkers) { + if (marker.isInfoWindowShown()) { + marker.hideInfoWindow(); + marker.showInfoWindow(mapboxMap, mapView); + } + } + } + + void reloadMarkers() { + iconManager.reloadIcons(); + 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); + } + } + } + + // + // Click event + // + + boolean onTap(PointF tapPoint, float screenDensity) { + float toleranceSides = 4 * screenDensity; + float toleranceTopBottom = 10 * screenDensity; + + RectF tapRect = new RectF(tapPoint.x - iconManager.getAverageIconWidth() / 2 - toleranceSides, + tapPoint.y - iconManager.getAverageIconHeight() / 2 - toleranceTopBottom, + tapPoint.x + iconManager.getAverageIconWidth() / 2 + toleranceSides, + tapPoint.y + iconManager.getAverageIconHeight() / 2 + toleranceTopBottom); + + List 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 annotations = 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) { + Marker marker = (Marker) annotation; + boolean handledDefaultClick = false; - void reloadMarkers() { - iconManager.reloadIcons(); - 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 (marker instanceof MarkerView) { + handledDefaultClick = markerViewManager.onClickMarkerView((MarkerView) marker); + } else { + if (onMarkerClickListener != null) { + // end developer has provided a custom click listener + handledDefaultClick = onMarkerClickListener.onMarkerClick(marker); + } } - } - } - // - // Click event - // - - boolean onTap(PointF tapPoint, float screenDensity) { - float toleranceSides = 4 * screenDensity; - float toleranceTopBottom = 10 * screenDensity; - - RectF tapRect = new RectF(tapPoint.x - iconManager.getAverageIconWidth() / 2 - toleranceSides, - tapPoint.y - iconManager.getAverageIconHeight() / 2 - toleranceTopBottom, - tapPoint.x + iconManager.getAverageIconWidth() / 2 + toleranceSides, - tapPoint.y + iconManager.getAverageIconHeight() / 2 + toleranceTopBottom); - - List 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 (annotation instanceof MarkerView) { + markerViewManager.onClickMarkerView((MarkerView) annotation); + } else { + if (!handledDefaultClick) { + // only select marker if user didn't handle the click event themselves + selectMarker(marker); + } } - } - if (newSelectedMarkerId >= 0) { - List annotations = 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) { - Marker marker = (Marker) annotation; - boolean handledDefaultClick = false; - - if (marker instanceof MarkerView) { - handledDefaultClick = markerViewManager.onClickMarkerView((MarkerView) marker); - } else { - if (onMarkerClickListener != null) { - // end developer has provided a custom click listener - handledDefaultClick = onMarkerClickListener.onMarkerClick(marker); - } - } - - if (annotation instanceof MarkerView) { - markerViewManager.onClickMarkerView((MarkerView) annotation); - } else { - if (!handledDefaultClick) { - // only select marker if user didn't handle the click event themselves - selectMarker(marker); - } - } - - return true; - } - } - } + return true; + } } - return false; + } } + return false; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java index 5f20155119..006122a4e2 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/FocalPointChangeListener.java @@ -4,5 +4,5 @@ import android.graphics.PointF; public interface FocalPointChangeListener { - void onFocalPointChanged(PointF pointF); + void onFocalPointChanged(PointF pointF); } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java index 71a9d4a2da..c9d81a88bc 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/IconManager.java @@ -26,133 +26,133 @@ import java.util.List; */ class IconManager { - private NativeMapView nativeMapView; - private List icons; - - private int averageIconHeight; - private int averageIconWidth; - - IconManager(NativeMapView nativeMapView) { - this.nativeMapView = nativeMapView; - this.icons = new ArrayList<>(); - // load transparent icon for MarkerView to trace actual markers, see #6352 - loadIcon(IconFactory.recreate(IconFactory.ICON_MARKERVIEW_ID, IconFactory.ICON_MARKERVIEW_BITMAP)); + private NativeMapView nativeMapView; + private List icons; + + private int averageIconHeight; + private int averageIconWidth; + + IconManager(NativeMapView nativeMapView) { + this.nativeMapView = nativeMapView; + this.icons = new ArrayList<>(); + // load transparent icon for MarkerView to trace actual markers, see #6352 + loadIcon(IconFactory.recreate(IconFactory.ICON_MARKERVIEW_ID, IconFactory.ICON_MARKERVIEW_BITMAP)); + } + + 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(nativeMapView.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; } - 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(nativeMapView.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; + 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(); + } } - - Icon loadIconForMarkerView(MarkerView marker) { - Icon icon = marker.getIcon(); - int iconSize = icons.size() + 1; - if (icon == null) { - icon = IconFactory.getInstance(nativeMapView.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; + return icon; + } + + Icon loadIconForMarkerView(MarkerView marker) { + Icon icon = marker.getIcon(); + int iconSize = icons.size() + 1; + if (icon == null) { + icon = IconFactory.getInstance(nativeMapView.getContext()).defaultMarkerView(); + marker.setIcon(icon); } - - int getTopOffsetPixelsForIcon(Icon icon) { - return (int) (nativeMapView.getTopOffsetPixelsForAnnotationSymbol(icon.getId()) * nativeMapView.getPixelRatio()); + 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(); + } } - - void loadIcon(Icon icon) { - 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()); + return icon; + } + + int getTopOffsetPixelsForIcon(Icon icon) { + return (int) (nativeMapView.getTopOffsetPixelsForAnnotationSymbol(icon.getId()) * nativeMapView.getPixelRatio()); + } + + void loadIcon(Icon icon) { + 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); - void reloadIcons() { - int count = icons.size(); - for (int i = 0; i < count; i++) { - Icon icon = icons.get(i); - loadIcon(icon); - } + float density = bitmap.getDensity(); + if (density == Bitmap.DENSITY_NONE) { + density = DisplayMetrics.DENSITY_DEFAULT; } - - void ensureIconLoaded(Marker marker, MapboxMap mapboxMap) { - Icon icon = marker.getIcon(); - if (icon == null) { - icon = IconFactory.getInstance(nativeMapView.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)); - } + 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); } + } - int getAverageIconHeight() { - return averageIconHeight; + void ensureIconLoaded(Marker marker, MapboxMap mapboxMap) { + Icon icon = marker.getIcon(); + if (icon == null) { + icon = IconFactory.getInstance(nativeMapView.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(); + } } - int getAverageIconWidth() { - return averageIconWidth; + // 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)); } + } + + int getAverageIconHeight() { + return averageIconHeight; + } + + int getAverageIconWidth() { + return averageIconWidth; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java index 791f310b4c..fc7d19c325 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/InfoWindowManager.java @@ -15,73 +15,74 @@ import java.util.List; *

* Maintains a {@link List} of opened {@link InfoWindow} and tracks configurations as * allowConcurrentMultipleInfoWindows which allows to have multiple {@link InfoWindow} open at the - * same time. Responsible for managing listeners as {@link com.mapbox.mapboxsdk.maps.MapboxMap.OnInfoWindowClickListener} + * same time. Responsible for managing listeners as + * {@link com.mapbox.mapboxsdk.maps.MapboxMap.OnInfoWindowClickListener} * and {@link com.mapbox.mapboxsdk.maps.MapboxMap.OnInfoWindowLongClickListener}. *

*/ class InfoWindowManager { - private List infoWindows; - private MapboxMap.InfoWindowAdapter infoWindowAdapter; - private boolean allowConcurrentMultipleInfoWindows; + private List infoWindows; + private MapboxMap.InfoWindowAdapter infoWindowAdapter; + private boolean allowConcurrentMultipleInfoWindows; - private MapboxMap.OnInfoWindowClickListener onInfoWindowClickListener; - private MapboxMap.OnInfoWindowLongClickListener onInfoWindowLongClickListener; - private MapboxMap.OnInfoWindowCloseListener onInfoWindowCloseListener; + private MapboxMap.OnInfoWindowClickListener onInfoWindowClickListener; + private MapboxMap.OnInfoWindowLongClickListener onInfoWindowLongClickListener; + private MapboxMap.OnInfoWindowCloseListener onInfoWindowCloseListener; - InfoWindowManager() { - this.infoWindows = new ArrayList<>(); - } + InfoWindowManager() { + this.infoWindows = new ArrayList<>(); + } - void setInfoWindowAdapter(@Nullable MapboxMap.InfoWindowAdapter infoWindowAdapter) { - this.infoWindowAdapter = infoWindowAdapter; - } + void setInfoWindowAdapter(@Nullable MapboxMap.InfoWindowAdapter infoWindowAdapter) { + this.infoWindowAdapter = infoWindowAdapter; + } - MapboxMap.InfoWindowAdapter getInfoWindowAdapter() { - return infoWindowAdapter; - } + MapboxMap.InfoWindowAdapter getInfoWindowAdapter() { + return infoWindowAdapter; + } - void setAllowConcurrentMultipleOpenInfoWindows(boolean allow) { - allowConcurrentMultipleInfoWindows = allow; - } + void setAllowConcurrentMultipleOpenInfoWindows(boolean allow) { + allowConcurrentMultipleInfoWindows = allow; + } - boolean isAllowConcurrentMultipleOpenInfoWindows() { - return allowConcurrentMultipleInfoWindows; - } + boolean isAllowConcurrentMultipleOpenInfoWindows() { + return allowConcurrentMultipleInfoWindows; + } - List getInfoWindows() { - return infoWindows; - } + List getInfoWindows() { + return infoWindows; + } - boolean isInfoWindowValidForMarker(@NonNull Marker marker) { - return !TextUtils.isEmpty(marker.getTitle()) || !TextUtils.isEmpty(marker.getSnippet()); - } + boolean isInfoWindowValidForMarker(@NonNull Marker marker) { + return !TextUtils.isEmpty(marker.getTitle()) || !TextUtils.isEmpty(marker.getSnippet()); + } - void setOnInfoWindowClickListener(@Nullable MapboxMap.OnInfoWindowClickListener listener) { - onInfoWindowClickListener = listener; - } + void setOnInfoWindowClickListener(@Nullable MapboxMap.OnInfoWindowClickListener listener) { + onInfoWindowClickListener = listener; + } - MapboxMap.OnInfoWindowClickListener getOnInfoWindowClickListener() { - return onInfoWindowClickListener; - } + MapboxMap.OnInfoWindowClickListener getOnInfoWindowClickListener() { + return onInfoWindowClickListener; + } - void setOnInfoWindowLongClickListener(@Nullable MapboxMap.OnInfoWindowLongClickListener listener) { - onInfoWindowLongClickListener = listener; - } + void setOnInfoWindowLongClickListener(@Nullable MapboxMap.OnInfoWindowLongClickListener listener) { + onInfoWindowLongClickListener = listener; + } - MapboxMap.OnInfoWindowLongClickListener getOnInfoWindowLongClickListener() { - return onInfoWindowLongClickListener; - } + MapboxMap.OnInfoWindowLongClickListener getOnInfoWindowLongClickListener() { + return onInfoWindowLongClickListener; + } - void setOnInfoWindowCloseListener(@Nullable MapboxMap.OnInfoWindowCloseListener listener) { - onInfoWindowCloseListener = listener; - } + void setOnInfoWindowCloseListener(@Nullable MapboxMap.OnInfoWindowCloseListener listener) { + onInfoWindowCloseListener = listener; + } - MapboxMap.OnInfoWindowCloseListener getOnInfoWindowCloseListener() { - return onInfoWindowCloseListener; - } + MapboxMap.OnInfoWindowCloseListener getOnInfoWindowCloseListener() { + return onInfoWindowCloseListener; + } - public void add(InfoWindow infoWindow) { - infoWindows.add(infoWindow); - } + public void add(InfoWindow infoWindow) { + infoWindows.add(infoWindow); + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java index 4524a59f0d..18b4c294e5 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapFragment.java @@ -35,196 +35,197 @@ import com.mapbox.mapboxsdk.exceptions.InvalidAccessTokenException; */ public final class MapFragment extends Fragment { - private MapView map; - private OnMapReadyCallback onMapReadyCallback; - - /** - * Creates a MapFragment instance - * - * @param mapboxMapOptions The configuration options to be used. - * @return MapFragment created. - */ - public static MapFragment newInstance(@Nullable MapboxMapOptions mapboxMapOptions) { - MapFragment mapFragment = new MapFragment(); - Bundle bundle = new Bundle(); - bundle.putParcelable(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS, mapboxMapOptions); - mapFragment.setArguments(bundle); - return mapFragment; + private MapView map; + private OnMapReadyCallback onMapReadyCallback; + + /** + * Creates a MapFragment instance + * + * @param mapboxMapOptions The configuration options to be used. + * @return MapFragment created. + */ + public static MapFragment newInstance(@Nullable MapboxMapOptions mapboxMapOptions) { + MapFragment mapFragment = new MapFragment(); + Bundle bundle = new Bundle(); + bundle.putParcelable(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS, mapboxMapOptions); + mapFragment.setArguments(bundle); + return mapFragment; + } + + /** + * Creates the fragment view hierarchy. + * + * @param inflater Inflater used to inflate content. + * @param container The parent layout for the map fragment. + * @param savedInstanceState The saved instance state for the map fragment. + * @return The view created + */ + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + super.onCreateView(inflater, container, savedInstanceState); + Context context = inflater.getContext(); + MapboxMapOptions options = null; + + // Get bundle + Bundle bundle = getArguments(); + if (bundle != null && bundle.containsKey(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS)) { + options = bundle.getParcelable(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS); } - /** - * Creates the fragment view hierarchy. - * - * @param inflater Inflater used to inflate content. - * @param container The parent layout for the map fragment. - * @param savedInstanceState The saved instance state for the map fragment. - * @return The view created - */ - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - super.onCreateView(inflater, container, savedInstanceState); - Context context = inflater.getContext(); - MapboxMapOptions options = null; - - // Get bundle - Bundle bundle = getArguments(); - if (bundle != null && bundle.containsKey(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS)) { - options = bundle.getParcelable(MapboxConstants.FRAG_ARG_MAPBOXMAPOPTIONS); - } - - // Assign an AccessToken if needed - if (options == null || options.getAccessToken() == null) { - String token = null; - if (MapboxAccountManager.getInstance() != null) { - token = MapboxAccountManager.getInstance().getAccessToken(); - } else { - token = getToken(inflater.getContext()); - } - if (TextUtils.isEmpty(token)) { - throw new InvalidAccessTokenException(); - } - if (options == null) { - options = new MapboxMapOptions().accessToken(token); - } else { - options.accessToken(token); - } - } - - Drawable foregroundDrawable = options.getMyLocationForegroundDrawable(); - Drawable foregroundBearingDrawable = options.getMyLocationForegroundBearingDrawable(); - if (foregroundDrawable == null || foregroundBearingDrawable == null) { - if (foregroundDrawable == null) { - foregroundDrawable = ContextCompat.getDrawable(context, R.drawable.mapbox_mylocation_icon_default); - } - if (foregroundBearingDrawable == null) { - foregroundBearingDrawable = ContextCompat.getDrawable(context, R.drawable.mapbox_mylocation_icon_bearing); - } - options.myLocationForegroundDrawables(foregroundDrawable, foregroundBearingDrawable); - } - - if (options.getMyLocationBackgroundDrawable() == null) { - options.myLocationBackgroundDrawable(ContextCompat.getDrawable(context, R.drawable.mapbox_mylocation_bg_shape)); - } - - return map = new MapView(inflater.getContext(), options); + // Assign an AccessToken if needed + if (options == null || options.getAccessToken() == null) { + String token = null; + if (MapboxAccountManager.getInstance() != null) { + token = MapboxAccountManager.getInstance().getAccessToken(); + } else { + token = getToken(inflater.getContext()); + } + if (TextUtils.isEmpty(token)) { + throw new InvalidAccessTokenException(); + } + if (options == null) { + options = new MapboxMapOptions().accessToken(token); + } else { + options.accessToken(token); + } } - /** - *

- * Returns the Mapbox access token set in the app resources. - *

- * It will first search the application manifest for a {@link MapboxConstants#KEY_META_DATA_MANIFEST} - * meta-data value. If not found it will then attempt to load the access token from the - * {@code res/raw/token.txt} development file. - * - * @param context The {@link Context} of the {@link android.app.Activity} or {@link android.app.Fragment}. - * @return The Mapbox access token or null if not found. - * @see MapboxConstants#KEY_META_DATA_MANIFEST - * - * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.MapboxAccountManager#start(Context, String)} - */ - @Deprecated - private String getToken(@NonNull Context context) { - try { - // read out AndroidManifest - PackageManager packageManager = context.getPackageManager(); - ApplicationInfo appInfo = packageManager.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); - String token = appInfo.metaData.getString(MapboxConstants.KEY_META_DATA_MANIFEST); - if (token == null || token.isEmpty()) { - throw new IllegalArgumentException(); - } - return token; - } catch (Exception e) { - // use fallback on string resource, used for development - int tokenResId = context.getResources().getIdentifier("mapbox_access_token", "string", context.getPackageName()); - return tokenResId != 0 ? context.getString(tokenResId) : null; - } + Drawable foregroundDrawable = options.getMyLocationForegroundDrawable(); + Drawable foregroundBearingDrawable = options.getMyLocationForegroundBearingDrawable(); + if (foregroundDrawable == null || foregroundBearingDrawable == null) { + if (foregroundDrawable == null) { + foregroundDrawable = ContextCompat.getDrawable(context, R.drawable.mapbox_mylocation_icon_default); + } + if (foregroundBearingDrawable == null) { + foregroundBearingDrawable = ContextCompat.getDrawable(context, R.drawable.mapbox_mylocation_icon_bearing); + } + options.myLocationForegroundDrawables(foregroundDrawable, foregroundBearingDrawable); } - /** - * Called when the fragment view hierarchy is created. - * - * @param view The content view of the fragment - * @param savedInstanceState THe saved instance state of the framgnt - */ - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - map.onCreate(savedInstanceState); + if (options.getMyLocationBackgroundDrawable() == null) { + options.myLocationBackgroundDrawable(ContextCompat.getDrawable(context, R.drawable.mapbox_mylocation_bg_shape)); } - /** - * Called when the fragment is visible for the users. - */ - @Override - public void onStart() { - super.onStart(); - map.onStart(); - map.getMapAsync(onMapReadyCallback); - } - - /** - * Called when the fragment is ready to be interacted with. - */ - @Override - public void onResume() { - super.onResume(); - map.onResume(); - } - - /** - * Called when the fragment is pausing. - */ - @Override - public void onPause() { - super.onPause(); - map.onPause(); - } - - /** - * Called when the fragment state needs to be saved. - * - * @param outState The saved state - */ - @Override - public void onSaveInstanceState(@NonNull Bundle outState) { - super.onSaveInstanceState(outState); - map.onSaveInstanceState(outState); - } - - /** - * Called when the fragment is no longer visible for the user. - */ - @Override - public void onStop() { - super.onStop(); - map.onStop(); - } - - /** - * Called when the fragment receives onLowMemory call from the hosting Activity. - */ - @Override - public void onLowMemory() { - super.onLowMemory(); - map.onLowMemory(); - } - - /** - * Called when the fragment is view hiearchy is being destroyed. - */ - @Override - public void onDestroyView() { - super.onDestroyView(); - map.onDestroy(); - } - - /** - * Sets a callback object which will be triggered when the MapboxMap instance is ready to be used. - * - * @param onMapReadyCallback The callback to be invoked. - */ - public void getMapAsync(@NonNull final OnMapReadyCallback onMapReadyCallback) { - this.onMapReadyCallback = onMapReadyCallback; + return map = new MapView(inflater.getContext(), options); + } + + /** + *

+ * Returns the Mapbox access token set in the app resources. + *

+ * It will first search the application manifest for a {@link MapboxConstants#KEY_META_DATA_MANIFEST} + * meta-data value. If not found it will then attempt to load the access token from the + * {@code res/raw/token.txt} development file. + * + * @param context The {@link Context} of the {@link android.app.Activity} or {@link android.app.Fragment}. + * @return The Mapbox access token or null if not found. + * @see MapboxConstants#KEY_META_DATA_MANIFEST + * @deprecated As of release 4.1.0, replaced by + * {@link com.mapbox.mapboxsdk.MapboxAccountManager#start(Context, String)} + */ + @Deprecated + private String getToken(@NonNull Context context) { + try { + // read out AndroidManifest + PackageManager packageManager = context.getPackageManager(); + ApplicationInfo appInfo = packageManager.getApplicationInfo(context.getPackageName(), + PackageManager.GET_META_DATA); + String token = appInfo.metaData.getString(MapboxConstants.KEY_META_DATA_MANIFEST); + if (token == null || token.isEmpty()) { + throw new IllegalArgumentException(); + } + return token; + } catch (Exception exception) { + // use fallback on string resource, used for development + int tokenResId = context.getResources().getIdentifier("mapbox_access_token", "string", context.getPackageName()); + return tokenResId != 0 ? context.getString(tokenResId) : null; } + } + + /** + * Called when the fragment view hierarchy is created. + * + * @param view The content view of the fragment + * @param savedInstanceState THe saved instance state of the framgnt + */ + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + map.onCreate(savedInstanceState); + } + + /** + * Called when the fragment is visible for the users. + */ + @Override + public void onStart() { + super.onStart(); + map.onStart(); + map.getMapAsync(onMapReadyCallback); + } + + /** + * Called when the fragment is ready to be interacted with. + */ + @Override + public void onResume() { + super.onResume(); + map.onResume(); + } + + /** + * Called when the fragment is pausing. + */ + @Override + public void onPause() { + super.onPause(); + map.onPause(); + } + + /** + * Called when the fragment state needs to be saved. + * + * @param outState The saved state + */ + @Override + public void onSaveInstanceState(@NonNull Bundle outState) { + super.onSaveInstanceState(outState); + map.onSaveInstanceState(outState); + } + + /** + * Called when the fragment is no longer visible for the user. + */ + @Override + public void onStop() { + super.onStop(); + map.onStop(); + } + + /** + * Called when the fragment receives onLowMemory call from the hosting Activity. + */ + @Override + public void onLowMemory() { + super.onLowMemory(); + map.onLowMemory(); + } + + /** + * Called when the fragment is view hiearchy is being destroyed. + */ + @Override + public void onDestroyView() { + super.onDestroyView(); + map.onDestroy(); + } + + /** + * Sets a callback object which will be triggered when the MapboxMap instance is ready to be used. + * + * @param onMapReadyCallback The callback to be invoked. + */ + public void getMapAsync(@NonNull final OnMapReadyCallback onMapReadyCallback) { + this.onMapReadyCallback = onMapReadyCallback; + } } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java index 157a1c4a19..398093344b 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapGestureDetector.java @@ -24,577 +24,585 @@ import com.mapbox.mapboxsdk.telemetry.MapboxEvent; */ final class MapGestureDetector { - private final Transform transform; - private final Projection projection; - private final UiSettings uiSettings; - private final TrackingSettings trackingSettings; - private final AnnotationManager annotationManager; - - private final GestureDetectorCompat gestureDetector; - private final ScaleGestureDetector scaleGestureDetector; - private final RotateGestureDetector rotateGestureDetector; - private final ShoveGestureDetector shoveGestureDetector; - - private MapboxMap.OnMapClickListener onMapClickListener; - private MapboxMap.OnMapLongClickListener onMapLongClickListener; - private MapboxMap.OnFlingListener onFlingListener; - private MapboxMap.OnScrollListener onScrollListener; - - private PointF focalPoint; - - private boolean twoTap = false; - private boolean zoomStarted = false; - private boolean dragStarted = false; - private boolean quickZoom = false; - private boolean scrollInProgress = false; - - MapGestureDetector(Context context, Transform transform, Projection projection, UiSettings uiSettings, - TrackingSettings trackingSettings, AnnotationManager annotationManager) { - this.annotationManager = annotationManager; - this.transform = transform; - this.projection = projection; - this.uiSettings = uiSettings; - this.trackingSettings = trackingSettings; - - // 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()); + private final Transform transform; + private final Projection projection; + private final UiSettings uiSettings; + private final TrackingSettings trackingSettings; + private final AnnotationManager annotationManager; + + private final GestureDetectorCompat gestureDetector; + private final ScaleGestureDetector scaleGestureDetector; + private final RotateGestureDetector rotateGestureDetector; + private final ShoveGestureDetector shoveGestureDetector; + + private MapboxMap.OnMapClickListener onMapClickListener; + private MapboxMap.OnMapLongClickListener onMapLongClickListener; + private MapboxMap.OnFlingListener onFlingListener; + private MapboxMap.OnScrollListener onScrollListener; + + private PointF focalPoint; + + private boolean twoTap = false; + private boolean zoomStarted = false; + private boolean dragStarted = false; + private boolean quickZoom = false; + private boolean scrollInProgress = false; + + MapGestureDetector(Context context, Transform transform, Projection projection, UiSettings uiSettings, + TrackingSettings trackingSettings, AnnotationManager annotationManager) { + this.annotationManager = annotationManager; + this.transform = transform; + this.projection = projection; + this.uiSettings = uiSettings; + this.trackingSettings = trackingSettings; + + // 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()); + } + + /** + * Set the gesture focal point. + *

+ * this is the center point used for calculate transformations from gestures, value is + * overridden if end user provides his own through {@link UiSettings#setFocalPoint(PointF)}. + *

+ * + * @param focalPoint the center point for gestures + */ + void setFocalPoint(PointF focalPoint) { + if (focalPoint == null) { + // resetting focal point, + if (uiSettings.getFocalPoint() != null) { + // using user provided one to reset + focalPoint = uiSettings.getFocalPoint(); + } + } + this.focalPoint = focalPoint; + } + + + /** + * Called when user touches the screen, all positions are absolute. + *

+ * Forwards event to the related gesture detectors. + *

+ * + * @param event the MotionEvent + * @return True if touch event is handled + */ + boolean onTouchEvent(@NonNull MotionEvent event) { + // Check and ignore non touch or left clicks + if ((event.getButtonState() != 0) && (event.getButtonState() != MotionEvent.BUTTON_PRIMARY)) { + return false; } - /** - * Set the gesture focal point. - *

- * this is the center point used for calculate transformations from gestures, value is - * overridden if end user provides his own through {@link UiSettings#setFocalPoint(PointF)}. - *

- * - * @param focalPoint the center point for gestures - */ - void setFocalPoint(PointF focalPoint) { - if (focalPoint == null) { - // resetting focal point, - if (uiSettings.getFocalPoint() != null) { - // using user provided one to reset - focalPoint = uiSettings.getFocalPoint(); - } + // 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 + transform.setGestureInProgress(true); + break; + + case MotionEvent.ACTION_POINTER_DOWN: + // Second pointer down + twoTap = event.getPointerCount() == 2 + && uiSettings.isZoomGesturesEnabled(); + if (twoTap) { + // Confirmed 2nd Finger Down + MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_TWO_FINGER_SINGLETAP, event.getX(), + event.getY(), transform.getZoom()); + } + 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) { + transform.zoom(false, focalPoint.x, focalPoint.y); + } else { + PointF focalPoint = TwoFingerGestureDetector.determineFocalPoint(event); + transform.zoom(false, focalPoint.x, focalPoint.y); + } + twoTap = false; + return true; + } + + // Scroll / Pan Has Stopped + if (scrollInProgress) { + MapboxEvent.trackGestureDragEndEvent(projection, event.getX(), event.getY(), transform.getZoom()); + scrollInProgress = false; } - this.focalPoint = focalPoint; - } + twoTap = false; + transform.setGestureInProgress(false); + break; - /** - * Called when user touches the screen, all positions are absolute. - *

- * Forwards event to the related gesture detectors. - *

- * - * @param event the MotionEvent - * @return True if touch event is handled - */ - boolean onTouchEvent(@NonNull MotionEvent event) { - // Check and ignore non touch or left clicks - if ((event.getButtonState() != 0) && (event.getButtonState() != MotionEvent.BUTTON_PRIMARY)) { + case MotionEvent.ACTION_CANCEL: + twoTap = false; + transform.setGestureInProgress(false); + break; + } + + return gestureDetector.onTouchEvent(event); + } + + /** + * Called for events that don't fit the other handlers. + *

+ * Examples of such events are mouse scroll events, mouse moves, joystick & trackpad. + *

+ * + * @param event The MotionEvent occured + * @return True is the event is handled + */ + boolean onGenericMotionEvent(MotionEvent event) { + // 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 (!uiSettings.isZoomGesturesEnabled()) { 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 - transform.setGestureInProgress(true); - break; - - case MotionEvent.ACTION_POINTER_DOWN: - // Second pointer down - twoTap = event.getPointerCount() == 2 - && uiSettings.isZoomGesturesEnabled(); - if (twoTap) { - // Confirmed 2nd Finger Down - MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_TWO_FINGER_SINGLETAP, event.getX(), event.getY(), transform.getZoom()); - } - 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) { - transform.zoom(false, focalPoint.x, focalPoint.y); - } else { - PointF focalPoint = TwoFingerGestureDetector.determineFocalPoint(event); - transform.zoom(false, focalPoint.x, focalPoint.y); - } - twoTap = false; - return true; - } - - // Scroll / Pan Has Stopped - if (scrollInProgress) { - MapboxEvent.trackGestureDragEndEvent(projection, event.getX(), event.getY(), transform.getZoom()); - scrollInProgress = false; - } - - twoTap = false; - transform.setGestureInProgress(false); - break; - - case MotionEvent.ACTION_CANCEL: - twoTap = false; - transform.setGestureInProgress(false); - break; - } + // Cancel any animation + transform.cancelTransitions(); + + // Get the vertical scroll amount, one click = 1 + float scrollDist = event.getAxisValue(MotionEvent.AXIS_VSCROLL); - return gestureDetector.onTouchEvent(event); + // Scale the map by the appropriate power of two factor + transform.zoomBy(Math.pow(2.0, scrollDist), event.getX(), event.getY()); + + return true; + + default: + // We are not interested in this event + return false; + } } - /** - * Called for events that don't fit the other handlers. - *

- * Examples of such events are mouse scroll events, mouse moves, joystick & trackpad. - *

- * - * @param event The MotionEvent occured - * @return True is the event is handled - */ - boolean onGenericMotionEvent(MotionEvent event) { - // 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 (!uiSettings.isZoomGesturesEnabled()) { - return false; - } - - // Cancel any animation - transform.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 - transform.zoomBy(Math.pow(2.0, scrollDist), event.getX(), event.getY()); - - return true; - - default: - // We are not interested in this event - return false; - } - } + // We are not interested in this event + return false; + } + + + /** + * Responsible for handling one finger gestures. + */ + private class GestureListener extends android.view.GestureDetector.SimpleOnGestureListener { - // We are not interested in this event + @Override + public boolean onDown(MotionEvent event) { + return true; + } + + @Override + public boolean onDoubleTapEvent(MotionEvent motionEvent) { + if (!uiSettings.isZoomGesturesEnabled()) { return false; + } + + switch (motionEvent.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 + transform.zoom(true, focalPoint.x, focalPoint.y); + } else { + // Zoom in on gesture + transform.zoom(true, motionEvent.getX(), motionEvent.getY()); + } + break; + } + + MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_DOUBLETAP, motionEvent.getX(), motionEvent.getY(), + transform.getZoom()); + + return true; } + @Override + public boolean onSingleTapUp(MotionEvent motionEvent) { + // Cancel any animation + transform.cancelTransitions(); + return true; + } - /** - * Responsible for handling one finger gestures. - */ - private class GestureListener extends android.view.GestureDetector.SimpleOnGestureListener { + @Override + public boolean onSingleTapConfirmed(MotionEvent motionEvent) { + PointF tapPoint = new PointF(motionEvent.getX(), motionEvent.getY()); + boolean tapHandled = annotationManager.onTap(tapPoint, uiSettings.getPixelRatio()); - @Override - public boolean onDown(MotionEvent event) { - return true; + if (!tapHandled) { + if (uiSettings.isDeselectMarkersOnTap()) { + // deselect any selected marker + annotationManager.deselectMarkers(); } - @Override - public boolean onDoubleTapEvent(MotionEvent e) { - if (!uiSettings.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 - transform.zoom(true, focalPoint.x, focalPoint.y); - } else { - // Zoom in on gesture - transform.zoom(true, e.getX(), e.getY()); - } - break; - } - - MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_DOUBLETAP, e.getX(), e.getY(), transform.getZoom()); - - return true; + // notify app of map click + if (onMapClickListener != null) { + onMapClickListener.onMapClick(projection.fromScreenLocation(tapPoint)); } + } - @Override - public boolean onSingleTapUp(MotionEvent motionEvent) { - // Cancel any animation - transform.cancelTransitions(); - return true; - } + MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_SINGLETAP, motionEvent.getX(), motionEvent.getY(), + transform.getZoom()); + return true; + } - @Override - public boolean onSingleTapConfirmed(MotionEvent motionEvent) { - PointF tapPoint = new PointF(motionEvent.getX(), motionEvent.getY()); - boolean tapHandled = annotationManager.onTap(tapPoint, uiSettings.getPixelRatio()); - - if (!tapHandled) { - if (uiSettings.isDeselectMarkersOnTap()) { - // deselect any selected marker - annotationManager.deselectMarkers(); - } - - // notify app of map click - if (onMapClickListener != null) { - onMapClickListener.onMapClick(projection.fromScreenLocation(tapPoint)); - } - } - - MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_SINGLETAP, motionEvent.getX(), motionEvent.getY(), transform.getZoom()); - return true; - } + @Override + public void onLongPress(MotionEvent motionEvent) { + if (onMapLongClickListener != null && !quickZoom) { + onMapLongClickListener.onMapLongClick(projection.fromScreenLocation(new PointF(motionEvent.getX(), + motionEvent.getY()))); + } + } - @Override - public void onLongPress(MotionEvent motionEvent) { - if (onMapLongClickListener != null && !quickZoom) { - onMapLongClickListener.onMapLongClick(projection.fromScreenLocation(new PointF(motionEvent.getX(), motionEvent.getY()))); - } - } + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + return false; + } - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { - return false; - } + trackingSettings.resetTrackingModesIfRequired(true, false); - trackingSettings.resetTrackingModesIfRequired(true, false); + // Cancel any animation + transform.cancelTransitions(); - // Cancel any animation - transform.cancelTransitions(); + float screenDensity = uiSettings.getPixelRatio(); - float screenDensity = uiSettings.getPixelRatio(); + double tilt = transform.getTilt(); + // tilt results in a bigger translation, need to limit input #5281, limitFactor ranges from 2 -> 8 + double limitFactor = 2 + ((tilt != 0) ? (tilt / 10) : 0); + double offsetX = velocityX / limitFactor / screenDensity; + double offsetY = velocityY / limitFactor / screenDensity; - double tilt = transform.getTilt(); - // tilt results in a bigger translation, need to limit input #5281, limitFactor ranges from 2 -> 8 - double limitFactor = 2 + ((tilt != 0) ? (tilt / 10) : 0); - double offsetX = velocityX / limitFactor / screenDensity; - double offsetY = velocityY / limitFactor / screenDensity; + transform.setGestureInProgress(true); + transform.moveBy(offsetX, offsetY, MapboxConstants.ANIMATION_DURATION_FLING); + transform.setGestureInProgress(false); - transform.setGestureInProgress(true); - transform.moveBy(offsetX, offsetY, MapboxConstants.ANIMATION_DURATION_FLING); - transform.setGestureInProgress(false); + if (onFlingListener != null) { + onFlingListener.onFling(); + } - if (onFlingListener != null) { - onFlingListener.onFling(); - } + MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_PAN_START, e1.getX(), e1.getY(), + transform.getZoom()); + return true; + } - MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_PAN_START, e1.getX(), e1.getY(), transform.getZoom()); - return true; - } + // Called for drags + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + if (!scrollInProgress) { + scrollInProgress = true; + } + if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + return false; + } - // Called for drags - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - if (!scrollInProgress) { - scrollInProgress = true; - } - if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { - return false; - } - - if (dragStarted) { - return false; - } - - // reset tracking if needed - trackingSettings.resetTrackingModesIfRequired(true, false); - // Cancel any animation - transform.cancelTransitions(); - - // Scroll the map - transform.moveBy(-distanceX, -distanceY, 0 /*no duration*/); - - if (onScrollListener != null) { - onScrollListener.onScroll(); - } - return true; - } + if (dragStarted) { + return false; + } + + // reset tracking if needed + trackingSettings.resetTrackingModesIfRequired(true, false); + // Cancel any animation + transform.cancelTransitions(); + + // Scroll the map + transform.moveBy(-distanceX, -distanceY, 0 /*no duration*/); + + if (onScrollListener != null) { + onScrollListener.onScroll(); + } + return true; } + } - /** - * Responsible for handling two finger gestures and double-tap drag gestures. - */ - private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { + /** + * Responsible for handling two finger gestures and double-tap drag gestures. + */ + private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener { - long beginTime = 0; - float scaleFactor = 1.0f; + long beginTime = 0; + float scaleFactor = 1.0f; - // Called when two fingers first touch the screen - @Override - public boolean onScaleBegin(ScaleGestureDetector detector) { - if (!uiSettings.isZoomGesturesEnabled()) { - return false; - } + // Called when two fingers first touch the screen + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + if (!uiSettings.isZoomGesturesEnabled()) { + return false; + } - beginTime = detector.getEventTime(); - MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_PINCH_START, detector.getFocusX(), detector.getFocusY(), transform.getZoom()); - return true; - } + beginTime = detector.getEventTime(); + MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_PINCH_START, detector.getFocusX(), + detector.getFocusY(), transform.getZoom()); + return true; + } - // Called when fingers leave screen - @Override - public void onScaleEnd(ScaleGestureDetector detector) { - beginTime = 0; - scaleFactor = 1.0f; - zoomStarted = false; - } + // Called when fingers leave screen + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + beginTime = 0; + scaleFactor = 1.0f; + zoomStarted = false; + } - // Called each time a finger moves - // Called for pinch zooms and quickzooms/quickscales - @Override - public boolean onScale(ScaleGestureDetector detector) { - if (!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 - transform.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. - - trackingSettings.resetTrackingModesIfRequired(!quickZoom, false); - // Scale the map - if (focalPoint != null) { - // arround user provided focal point - transform.zoomBy(detector.getScaleFactor(), focalPoint.x, focalPoint.y); - } else if (quickZoom) { - // around center map - transform.zoomBy(detector.getScaleFactor(), uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - } else { - // around gesture - transform.zoomBy(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY()); - } - - return true; - } + // Called each time a finger moves + // Called for pinch zooms and quickzooms/quickscales + @Override + public boolean onScale(ScaleGestureDetector detector) { + if (!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 + transform.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. + + trackingSettings.resetTrackingModesIfRequired(!quickZoom, false); + // Scale the map + if (focalPoint != null) { + // arround user provided focal point + transform.zoomBy(detector.getScaleFactor(), focalPoint.x, focalPoint.y); + } else if (quickZoom) { + // around center map + transform.zoomBy(detector.getScaleFactor(), uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + } else { + // around gesture + transform.zoomBy(detector.getScaleFactor(), detector.getFocusX(), detector.getFocusY()); + } + + return true; } + } - /** - * Responsible for handling rotation 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 (!trackingSettings.isRotateGestureCurrentlyEnabled()) { - return false; - } - - beginTime = detector.getEventTime(); - MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_ROTATION_START, detector.getFocusX(), detector.getFocusY(), transform.getZoom()); - return true; - } + /** + * Responsible for handling rotation gestures. + */ + private class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener { - // Called when the fingers leave the screen - @Override - public void onRotateEnd(RotateGestureDetector detector) { - beginTime = 0; - totalAngle = 0.0f; - started = false; - } + long beginTime = 0; + float totalAngle = 0.0f; + boolean started = false; - // Called each time one of the two fingers moves - // Called for rotation - @Override - public boolean onRotate(RotateGestureDetector detector) { - if (!trackingSettings.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 - transform.cancelTransitions(); - - // rotation constitutes translation of anything except the center of - // rotation, so cancel both location and bearing tracking if required - - trackingSettings.resetTrackingModesIfRequired(true, true); - - // Get rotate value - double bearing = transform.getRawBearing(); - bearing += detector.getRotationDegreesDelta(); - - // Rotate the map - if (focalPoint != null) { - // User provided focal point - transform.setBearing(bearing, focalPoint.x, focalPoint.y); - } else { - // around gesture - transform.setBearing(bearing, detector.getFocusX(), detector.getFocusY()); - } - return true; - } + // Called when two fingers first touch the screen + @Override + public boolean onRotateBegin(RotateGestureDetector detector) { + if (!trackingSettings.isRotateGestureCurrentlyEnabled()) { + return false; + } + + beginTime = detector.getEventTime(); + MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_ROTATION_START, detector.getFocusX(), + detector.getFocusY(), transform.getZoom()); + return true; } - /** - * Responsible for handling 2 finger shove gestures. - */ - private class ShoveGestureListener implements ShoveGestureDetector.OnShoveGestureListener { + // Called when the fingers leave the screen + @Override + public void onRotateEnd(RotateGestureDetector detector) { + beginTime = 0; + totalAngle = 0.0f; + started = false; + } - long beginTime = 0; - float totalDelta = 0.0f; - boolean started = false; + // Called each time one of the two fingers moves + // Called for rotation + @Override + public boolean onRotate(RotateGestureDetector detector) { + if (!trackingSettings.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; + } - @Override - public boolean onShoveBegin(ShoveGestureDetector detector) { - if (!uiSettings.isTiltGesturesEnabled()) { - return false; - } + if (!started) { + return false; + } - beginTime = detector.getEventTime(); - MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_PITCH_START, detector.getFocusX(), detector.getFocusY(), transform.getZoom()); - return true; - } + // Cancel any animation + transform.cancelTransitions(); - @Override - public void onShoveEnd(ShoveGestureDetector detector) { - beginTime = 0; - totalDelta = 0.0f; - started = false; - dragStarted = false; - } + // rotation constitutes translation of anything except the center of + // rotation, so cancel both location and bearing tracking if required - @Override - public boolean onShove(ShoveGestureDetector detector) { - if (!uiSettings.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 - transform.cancelTransitions(); - - // Get tilt value (scale and clamp) - double pitch = transform.getTilt(); - pitch -= 0.1 * detector.getShovePixelsDelta(); - pitch = Math.max(MapboxConstants.MINIMUM_TILT, Math.min(MapboxConstants.MAXIMUM_TILT, pitch)); - - // Tilt the map - transform.setTilt(pitch); - - dragStarted = true; - - return true; - } - } + trackingSettings.resetTrackingModesIfRequired(true, true); - void setOnMapClickListener(MapboxMap.OnMapClickListener onMapClickListener) { - this.onMapClickListener = onMapClickListener; + // Get rotate value + double bearing = transform.getRawBearing(); + bearing += detector.getRotationDegreesDelta(); + + // Rotate the map + if (focalPoint != null) { + // User provided focal point + transform.setBearing(bearing, focalPoint.x, focalPoint.y); + } else { + // around gesture + transform.setBearing(bearing, detector.getFocusX(), detector.getFocusY()); + } + return true; } + } + + /** + * Responsible for handling 2 finger shove gestures. + */ + private class ShoveGestureListener implements ShoveGestureDetector.OnShoveGestureListener { + + long beginTime = 0; + float totalDelta = 0.0f; + boolean started = false; + + @Override + public boolean onShoveBegin(ShoveGestureDetector detector) { + if (!uiSettings.isTiltGesturesEnabled()) { + return false; + } - void setOnMapLongClickListener(MapboxMap.OnMapLongClickListener onMapLongClickListener) { - this.onMapLongClickListener = onMapLongClickListener; + beginTime = detector.getEventTime(); + MapboxEvent.trackGestureEvent(projection, MapboxEvent.GESTURE_PITCH_START, detector.getFocusX(), + detector.getFocusY(), transform.getZoom()); + return true; } - void setOnFlingListener(MapboxMap.OnFlingListener onFlingListener) { - this.onFlingListener = onFlingListener; + @Override + public void onShoveEnd(ShoveGestureDetector detector) { + beginTime = 0; + totalDelta = 0.0f; + started = false; + dragStarted = false; } - void setOnScrollListener(MapboxMap.OnScrollListener onScrollListener) { - this.onScrollListener = onScrollListener; + @Override + public boolean onShove(ShoveGestureDetector detector) { + if (!uiSettings.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 + transform.cancelTransitions(); + + // Get tilt value (scale and clamp) + double pitch = transform.getTilt(); + pitch -= 0.1 * detector.getShovePixelsDelta(); + pitch = Math.max(MapboxConstants.MINIMUM_TILT, Math.min(MapboxConstants.MAXIMUM_TILT, pitch)); + + // Tilt the map + transform.setTilt(pitch); + + dragStarted = true; + + return true; } + } + + void setOnMapClickListener(MapboxMap.OnMapClickListener onMapClickListener) { + this.onMapClickListener = onMapClickListener; + } + + void setOnMapLongClickListener(MapboxMap.OnMapLongClickListener onMapLongClickListener) { + this.onMapLongClickListener = onMapLongClickListener; + } + + void setOnFlingListener(MapboxMap.OnFlingListener onFlingListener) { + this.onFlingListener = onFlingListener; + } + + void setOnScrollListener(MapboxMap.OnScrollListener onScrollListener) { + this.onScrollListener = onScrollListener; + } } \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java index 09b4a2c9ca..c993cd3ec6 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapKeyListener.java @@ -18,247 +18,248 @@ import android.view.ViewConfiguration; */ final class MapKeyListener { - private final TrackingSettings trackingSettings; - private final Transform transform; - private final UiSettings uiSettings; + private final TrackingSettings trackingSettings; + private final Transform transform; + private final UiSettings uiSettings; + + private TrackballLongPressTimeOut currentTrackballLongPressTimeOut; + + MapKeyListener(@NonNull Transform transform, @NonNull TrackingSettings trackingSettings, + @NonNull UiSettings uiSettings) { + this.transform = transform; + this.trackingSettings = trackingSettings; + this.uiSettings = uiSettings; + } + + /** + * Called when the user presses a key, alse called for repeated keys held down. + * + * @param keyCode the id of the pressed key + * @param event the related key event + * @return true if the wevent is handled + */ + boolean onKeyDown(int keyCode, @NonNull KeyEvent event) { + // If the user has held the scroll key down for a while then accelerate + // the scroll speed + double scrollDist = event.getRepeatCount() >= 5 ? 50.0 : 10.0; + + // 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 (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + return false; + } - private TrackballLongPressTimeOut currentTrackballLongPressTimeOut; + // Cancel any animation + transform.cancelTransitions(); - MapKeyListener(@NonNull Transform transform, @NonNull TrackingSettings trackingSettings, @NonNull UiSettings uiSettings) { - this.transform = transform; - this.trackingSettings = trackingSettings; - this.uiSettings = uiSettings; - } + // Move left + transform.moveBy(scrollDist, 0.0, 0 /*no animation*/); + return true; - /** - * Called when the user presses a key, alse called for repeated keys held down. - * - * @param keyCode the id of the pressed key - * @param event the related key event - * @return true if the wevent is handled - */ - boolean onKeyDown(int keyCode, @NonNull KeyEvent event) { - // If the user has held the scroll key down for a while then accelerate - // the scroll speed - double scrollDist = event.getRepeatCount() >= 5 ? 50.0 : 10.0; - - // 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 (!trackingSettings.isScrollGestureCurrentlyEnabled()) { - return false; - } - - // Cancel any animation - transform.cancelTransitions(); - - // Move left - transform.moveBy(scrollDist, 0.0, 0 /*no animation*/); - return true; - - case KeyEvent.KEYCODE_DPAD_RIGHT: - if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { - return false; - } - - // Cancel any animation - transform.cancelTransitions(); - - // Move right - transform.moveBy(-scrollDist, 0.0, 0 /*no animation*/); - return true; - - case KeyEvent.KEYCODE_DPAD_UP: - if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { - return false; - } - - // Cancel any animation - transform.cancelTransitions(); - - // Move up - transform.moveBy(0.0, scrollDist, 0 /*no animation*/); - return true; - - case KeyEvent.KEYCODE_DPAD_DOWN: - if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { - return false; - } - - // Cancel any animation - transform.cancelTransitions(); - - // Move down - transform.moveBy(0.0, -scrollDist, 0 /*no animation*/); - return true; - - default: - // We are not interested in this key - return false; + case KeyEvent.KEYCODE_DPAD_RIGHT: + if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + return false; } - } - /** - * Called when the user long presses a key that is being tracked. - * - * @param keyCode the id of the long pressed key - * @param event the related key event - * @return true if event is handled - */ - 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 (!uiSettings.isZoomGesturesEnabled()) { - return false; - } - - // Zoom out - transform.zoom(false, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - return true; - - default: - // We are not interested in this key - return false; + // Cancel any animation + transform.cancelTransitions(); + + // Move right + transform.moveBy(-scrollDist, 0.0, 0 /*no animation*/); + return true; + + case KeyEvent.KEYCODE_DPAD_UP: + if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + return false; } - } - /** - * Called when the user releases a key. - * - * @param keyCode the id of the released key - * @param event the related key event - * @return true if the event is handled - */ - boolean onKeyUp(int keyCode, KeyEvent event) { - // Check if the key action was canceled (used for virtual keyboards) - if (event.isCanceled()) { - return false; + // Cancel any animation + transform.cancelTransitions(); + + // Move up + transform.moveBy(0.0, scrollDist, 0 /*no animation*/); + return true; + + case KeyEvent.KEYCODE_DPAD_DOWN: + if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + return false; } - // 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 (!uiSettings.isZoomGesturesEnabled()) { - return false; - } - - // Zoom in - transform.zoom(true, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - return true; + // Cancel any animation + transform.cancelTransitions(); + + // Move down + transform.moveBy(0.0, -scrollDist, 0 /*no animation*/); + return true; + + default: + // We are not interested in this key + return false; + } + } + + /** + * Called when the user long presses a key that is being tracked. + * + * @param keyCode the id of the long pressed key + * @param event the related key event + * @return true if event is handled + */ + 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 (!uiSettings.isZoomGesturesEnabled()) { + return false; } + // Zoom out + transform.zoom(false, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + return true; + + default: // We are not interested in this key return false; } + } + + /** + * Called when the user releases a key. + * + * @param keyCode the id of the released key + * @param event the related key event + * @return true if the event is handled + */ + boolean onKeyUp(int keyCode, KeyEvent event) { + // Check if the key action was canceled (used for virtual keyboards) + if (event.isCanceled()) { + return false; + } - /** - * Called for trackball events, all motions are relative in device specific units. - * - * @param event the related motion event - * @return true if the event is handled - */ - boolean onTrackballEvent(MotionEvent event) { - // Choose the action - switch (event.getActionMasked()) { - // The trackball was rotated - case MotionEvent.ACTION_MOVE: - if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { - return false; - } - - // Cancel any animation - transform.cancelTransitions(); - - // Scroll the map - transform.moveBy(-10.0 * event.getX(), -10.0 * event.getY(), 0 /*no animation*/); - 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(); - new Handler().postDelayed(currentTrackballLongPressTimeOut, - ViewConfiguration.getLongPressTimeout()); - return true; - - // Trackball was released - case MotionEvent.ACTION_UP: - if (!uiSettings.isZoomGesturesEnabled()) { - return false; - } - - // Only handle if we have not already long pressed - if (currentTrackballLongPressTimeOut != null) { - // Zoom in - transform.zoom(true, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - } - 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 false; + // 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 (!uiSettings.isZoomGesturesEnabled()) { + return false; } - } - /** - * This class implements the trackball long press time out callback - */ - private class TrackballLongPressTimeOut implements Runnable { + // Zoom in + transform.zoom(true, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + return true; + } - // Track if we have been cancelled - private boolean cancelled; + // We are not interested in this key + return false; + } + + /** + * Called for trackball events, all motions are relative in device specific units. + * + * @param event the related motion event + * @return true if the event is handled + */ + boolean onTrackballEvent(MotionEvent event) { + // Choose the action + switch (event.getActionMasked()) { + // The trackball was rotated + case MotionEvent.ACTION_MOVE: + if (!trackingSettings.isScrollGestureCurrentlyEnabled()) { + return false; + } - TrackballLongPressTimeOut() { - cancelled = false; + // Cancel any animation + transform.cancelTransitions(); + + // Scroll the map + transform.moveBy(-10.0 * event.getX(), -10.0 * event.getY(), 0 /*no animation*/); + 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(); + new Handler().postDelayed(currentTrackballLongPressTimeOut, + ViewConfiguration.getLongPressTimeout()); + return true; + + // Trackball was released + case MotionEvent.ACTION_UP: + if (!uiSettings.isZoomGesturesEnabled()) { + return false; } - // Cancel the timeout - public void cancel() { - cancelled = true; + // Only handle if we have not already long pressed + if (currentTrackballLongPressTimeOut != null) { + // Zoom in + transform.zoom(true, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); } + return true; - // Called when long press time out expires - @Override - public void run() { - // Check if the trackball is still pressed - if (!cancelled) { - // Zoom out - transform.zoom(false, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); - - // Ensure the up action is not run - currentTrackballLongPressTimeOut = null; - } + // 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 false; + } + } + + /** + * This class implements the trackball long press time out callback + */ + private class TrackballLongPressTimeOut implements Runnable { + + // Track if we have been cancelled + private boolean cancelled; + + TrackballLongPressTimeOut() { + cancelled = false; + } + + // Cancel the timeout + public void cancel() { + cancelled = true; + } + + // Called when long press time out expires + @Override + public void run() { + // Check if the trackball is still pressed + if (!cancelled) { + // Zoom out + transform.zoom(false, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2); + + // Ensure the up action is not run + currentTrackballLongPressTimeOut = null; + } } + } } 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 58144d7a2c..5bbba8682a 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 @@ -46,7 +46,6 @@ import com.mapbox.mapboxsdk.annotations.InfoWindow; 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; @@ -67,6 +66,45 @@ import java.util.List; import timber.log.Timber; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.ANIMATION_DURATION; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_ATTRIBUTION_ENABLED; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_ATTRIBUTION_GRAVITY; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_ATTRIBUTION_MARGIN_BOTTOM; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_ATTRIBUTION_MARGIN_LEFT; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_ATTRIBUTION_MARGIN_RIGHT; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_ATTRIBUTION_MARGIN_TOP; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_CAMERA_POSITION; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_COMPASS_ENABLED; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_COMPASS_FADE_WHEN_FACING_NORTH; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_COMPASS_GRAVITY; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_COMPASS_MARGIN_BOTTOM; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_COMPASS_MARGIN_LEFT; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_COMPASS_MARGIN_RIGHT; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_COMPASS_MARGIN_TOP; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_DEBUG_ACTIVE; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_HAS_SAVED_STATE; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_LOGO_ENABLED; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_LOGO_GRAVITY; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_LOGO_MARGIN_BOTTOM; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_LOGO_MARGIN_LEFT; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_LOGO_MARGIN_RIGHT; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_LOGO_MARGIN_TOP; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_MY_BEARING_TRACKING_DISMISS; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_MY_BEARING_TRACKING_MODE; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_MY_LOCATION_ENABLED; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_MY_LOCATION_TRACKING_DISMISS; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_MY_LOCATION_TRACKING_MODE; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_ROTATE_ENABLED; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_ROTATE_ENABLED_CHANGE; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_SCROLL_ENABLED; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_SCROLL_ENABLED_CHANGE; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_STYLE_URL; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_TILT_ENABLED; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_TILT_ENABLED_CHANGE; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_ZOOM_CONTROLS_ENABLED; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_ZOOM_ENABLED; +import static com.mapbox.mapboxsdk.constants.MapboxConstants.STATE_ZOOM_ENABLED_CHANGE; + /** *

* A {@code MapView} provides an embeddable map interface. @@ -83,1272 +121,1277 @@ import timber.log.Timber; */ public class MapView extends FrameLayout { - private MapboxMap mapboxMap; + private MapboxMap mapboxMap; - private boolean initialLoad; - private boolean destroyed; + private boolean initialLoad; + private boolean destroyed; - private NativeMapView nativeMapView; - private boolean hasSurface = false; + private NativeMapView nativeMapView; + private boolean hasSurface = false; - private CompassView compassView; - private MyLocationView myLocationView; - private LocationListener myLocationListener; + private CompassView compassView; + private MyLocationView myLocationView; + private LocationListener myLocationListener; - private MapGestureDetector mapGestureDetector; - private MapKeyListener mapKeyListener; + private MapGestureDetector mapGestureDetector; + private MapKeyListener mapKeyListener; - private ConnectivityReceiver connectivityReceiver; + private ConnectivityReceiver connectivityReceiver; - private List onMapReadyCallbackList = new ArrayList<>(); - private SnapshotRequest snapshotRequest; - private ZoomButtonsController zoomButtonsController; + private List onMapReadyCallbackList = new ArrayList<>(); + private SnapshotRequest snapshotRequest; + private ZoomButtonsController zoomButtonsController; - private boolean onStartCalled; - private boolean onStopCalled; + private boolean onStartCalled; + private boolean onStopCalled; - @UiThread - public MapView(@NonNull Context context) { - super(context); - initialize(context, MapboxMapOptions.createFromAttributes(context, null)); - } + @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) { + 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 AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + initialize(context, MapboxMapOptions.createFromAttributes(context, attrs)); + } - @UiThread - public MapView(@NonNull Context context, @NonNull MapboxMapOptions options) { - super(context); - initialize(context, options); - } - - private void initialize(@NonNull final Context context, @NonNull final MapboxMapOptions options) { - if (isInEditMode()) { - // if we are in an editor mode we show an image of a map - LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_preview, this); - return; - } - - // TODO distill into singular purpose methods/classes - initialLoad = true; - View view = LayoutInflater.from(context).inflate(R.layout.mapbox_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); - } + @UiThread + public MapView(@NonNull Context context, @NonNull MapboxMapOptions options) { + super(context); + initialize(context, options); + } - nativeMapView = new NativeMapView(this); - - // inflate overlain Views - compassView = (CompassView) view.findViewById(R.id.compassView); - myLocationView = (MyLocationView) view.findViewById(R.id.userLocationView); - ImageView logoView = (ImageView) view.findViewById(R.id.logoView); - ImageView attributionsView = (ImageView) view.findViewById(R.id.attributionView); - attributionsView.setOnClickListener(new AttributionOnClickListener(this)); - ViewGroup markerViewContainer = (ViewGroup) findViewById(R.id.markerViewContainer); - - // interface for focal point invalidation - FocalPointInvalidator focalPointInvalidator = new FocalPointInvalidator(); - - // interface for registering touch listeners - RegisterTouchListener registerTouchListener = new RegisterTouchListener(); - - // setup components for MapboxMap creation - Projection projection = new Projection(nativeMapView); - UiSettings uiSettings = new UiSettings(projection, focalPointInvalidator, compassView, attributionsView, logoView); - TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPointInvalidator); - MyLocationViewSettings myLocationViewSettings = new MyLocationViewSettings(myLocationView, projection, focalPointInvalidator); - MarkerViewManager markerViewManager = new MarkerViewManager(markerViewContainer); - AnnotationManager annotationManager = new AnnotationManager(nativeMapView, this, markerViewManager); - Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings); - mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, trackingSettings, myLocationViewSettings, projection, registerTouchListener, annotationManager); - - // active user input - mapGestureDetector = new MapGestureDetector(context, mapboxMap.getTransform(), projection, uiSettings, trackingSettings, annotationManager); - mapKeyListener = new MapKeyListener(mapboxMap.getTransform(), trackingSettings, uiSettings); - - // attach widgets to MapboxMap - compassView.setMapboxMap(mapboxMap); - myLocationView.setMapboxMap(mapboxMap); - - // Ensure this view is interactable - setClickable(true); - setLongClickable(true); - setFocusable(true); - setFocusableInTouchMode(true); - requestDisallowInterceptTouchEvent(true); - requestFocus(); - - // Connectivity - onConnectivityChanged(isConnected()); - - // configure the zoom button controller - zoomButtonsController = new ZoomButtonsController(MapView.this); - zoomButtonsController.setZoomSpeed(MapboxConstants.ANIMATION_DURATION); - zoomButtonsController.setOnZoomListener(new OnZoomListener(mapboxMap)); - - mapboxMap.initialise(context, options); - - // Shows the zoom controls - if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)) { - uiSettings.setZoomControlsEnabled(true); - } + private void initialize(@NonNull final Context context, @NonNull final MapboxMapOptions options) { + if (isInEditMode()) { + // if we are in an editor mode we show an image of a map + LayoutInflater.from(context).inflate(R.layout.mapbox_mapview_preview, this); + return; } - // - // Lifecycle events - // - - /** - *

- * You must call this method from the parent's {@link android.app.Activity#onCreate(Bundle)} or - * {@link android.app.Fragment#onCreate(Bundle)}. - *

- * 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) { - // TODO distill into singular purpose methods/classes - String accessToken = mapboxMap.getAccessToken(); - if (TextUtils.isEmpty(accessToken)) { - accessToken = MapboxAccountManager.getInstance().getAccessToken(); - nativeMapView.setAccessToken(accessToken); - } else { - // user provided access token through xml attributes, need to start MapboxAccountManager - MapboxAccountManager.start(getContext(), accessToken); - nativeMapView.setAccessToken(accessToken); - } - - // Force a check for an access token - MapboxAccountManager.validateAccessToken(accessToken); - nativeMapView.setAccessToken(accessToken); - - if (savedInstanceState != null && savedInstanceState.getBoolean(MapboxConstants.STATE_HAS_SAVED_STATE)) { + // TODO distill into singular purpose methods/classes + initialLoad = true; + View view = LayoutInflater.from(context).inflate(R.layout.mapbox_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); + } - // Get previous camera position - CameraPosition cameraPosition = savedInstanceState.getParcelable(MapboxConstants.STATE_CAMERA_POSITION); - if (cameraPosition != null) { - mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder(cameraPosition).build())); - } + nativeMapView = new NativeMapView(this); + + // inflate overlain Views + compassView = (CompassView) view.findViewById(R.id.compassView); + myLocationView = (MyLocationView) view.findViewById(R.id.userLocationView); + ImageView logoView = (ImageView) view.findViewById(R.id.logoView); + ImageView attributionsView = (ImageView) view.findViewById(R.id.attributionView); + attributionsView.setOnClickListener(new AttributionOnClickListener(this)); + ViewGroup markerViewContainer = (ViewGroup) findViewById(R.id.markerViewContainer); + + // interface for focal point invalidation + FocalPointInvalidator focalPointInvalidator = new FocalPointInvalidator(); + + // interface for registering touch listeners + RegisterTouchListener registerTouchListener = new RegisterTouchListener(); + + // setup components for MapboxMap creation + Projection projection = new Projection(nativeMapView); + UiSettings uiSettings = new UiSettings(projection, focalPointInvalidator, compassView, attributionsView, logoView); + TrackingSettings trackingSettings = new TrackingSettings(myLocationView, uiSettings, focalPointInvalidator); + MyLocationViewSettings myLocationViewSettings = new MyLocationViewSettings(myLocationView, projection, + focalPointInvalidator); + MarkerViewManager markerViewManager = new MarkerViewManager(markerViewContainer); + AnnotationManager annotationManager = new AnnotationManager(nativeMapView, this, markerViewManager); + Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings); + mapboxMap = new MapboxMap(nativeMapView, transform, uiSettings, trackingSettings, myLocationViewSettings, + projection, registerTouchListener, annotationManager); + + // active user input + mapGestureDetector = new MapGestureDetector(context, mapboxMap.getTransform(), projection, uiSettings, + trackingSettings, annotationManager); + mapKeyListener = new MapKeyListener(mapboxMap.getTransform(), trackingSettings, uiSettings); + + // attach widgets to MapboxMap + compassView.setMapboxMap(mapboxMap); + myLocationView.setMapboxMap(mapboxMap); + + // Ensure this view is interactable + setClickable(true); + setLongClickable(true); + setFocusable(true); + setFocusableInTouchMode(true); + requestDisallowInterceptTouchEvent(true); + requestFocus(); + + // Connectivity + onConnectivityChanged(isConnected()); + + // configure the zoom button controller + zoomButtonsController = new ZoomButtonsController(MapView.this); + zoomButtonsController.setZoomSpeed(ANIMATION_DURATION); + zoomButtonsController.setOnZoomListener(new OnZoomListener(mapboxMap)); + + mapboxMap.initialise(context, options); + + // Shows the zoom controls + if (!context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN_MULTITOUCH)) { + uiSettings.setZoomControlsEnabled(true); + } + } + + // + // Lifecycle events + // + + /** + *

+ * You must call this method from the parent's {@link android.app.Activity#onCreate(Bundle)} or + * {@link android.app.Fragment#onCreate(Bundle)}. + *

+ * 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) { + // TODO distill into singular purpose methods/classes + String accessToken = mapboxMap.getAccessToken(); + if (TextUtils.isEmpty(accessToken)) { + accessToken = MapboxAccountManager.getInstance().getAccessToken(); + nativeMapView.setAccessToken(accessToken); + } else { + // user provided access token through xml attributes, need to start MapboxAccountManager + MapboxAccountManager.start(getContext(), accessToken); + nativeMapView.setAccessToken(accessToken); + } - 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)); - - String styleUrl = savedInstanceState.getString(MapboxConstants.STATE_STYLE_URL); - if (!TextUtils.isEmpty(styleUrl)) { - nativeMapView.setStyleUrl(savedInstanceState.getString(MapboxConstants.STATE_STYLE_URL)); - } + // Force a check for an access token + MapboxAccountManager.validateAccessToken(accessToken); + nativeMapView.setAccessToken(accessToken); + + if (savedInstanceState != null && savedInstanceState.getBoolean(STATE_HAS_SAVED_STATE)) { + + // Get previous camera position + CameraPosition cameraPosition = savedInstanceState.getParcelable(STATE_CAMERA_POSITION); + if (cameraPosition != null) { + mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(new CameraPosition.Builder(cameraPosition).build())); + } + + UiSettings uiSettings = mapboxMap.getUiSettings(); + uiSettings.setZoomGesturesEnabled(savedInstanceState.getBoolean(STATE_ZOOM_ENABLED)); + uiSettings.setZoomGestureChangeAllowed(savedInstanceState.getBoolean(STATE_ZOOM_ENABLED_CHANGE)); + uiSettings.setScrollGesturesEnabled(savedInstanceState.getBoolean(STATE_SCROLL_ENABLED)); + uiSettings.setScrollGestureChangeAllowed(savedInstanceState.getBoolean(STATE_SCROLL_ENABLED_CHANGE)); + uiSettings.setRotateGesturesEnabled(savedInstanceState.getBoolean(STATE_ROTATE_ENABLED)); + uiSettings.setRotateGestureChangeAllowed(savedInstanceState.getBoolean(STATE_ROTATE_ENABLED_CHANGE)); + uiSettings.setTiltGesturesEnabled(savedInstanceState.getBoolean(STATE_TILT_ENABLED)); + uiSettings.setTiltGestureChangeAllowed(savedInstanceState.getBoolean(STATE_TILT_ENABLED_CHANGE)); + uiSettings.setZoomControlsEnabled(savedInstanceState.getBoolean(STATE_ZOOM_CONTROLS_ENABLED)); + + // Compass + uiSettings.setCompassEnabled(savedInstanceState.getBoolean(STATE_COMPASS_ENABLED)); + uiSettings.setCompassGravity(savedInstanceState.getInt(STATE_COMPASS_GRAVITY)); + uiSettings.setCompassMargins(savedInstanceState.getInt(STATE_COMPASS_MARGIN_LEFT), + savedInstanceState.getInt(STATE_COMPASS_MARGIN_TOP), + savedInstanceState.getInt(STATE_COMPASS_MARGIN_RIGHT), + savedInstanceState.getInt(STATE_COMPASS_MARGIN_BOTTOM)); + uiSettings.setCompassFadeFacingNorth(savedInstanceState.getBoolean(STATE_COMPASS_FADE_WHEN_FACING_NORTH)); + + // Logo + uiSettings.setLogoEnabled(savedInstanceState.getBoolean(STATE_LOGO_ENABLED)); + uiSettings.setLogoGravity(savedInstanceState.getInt(STATE_LOGO_GRAVITY)); + uiSettings.setLogoMargins(savedInstanceState.getInt(STATE_LOGO_MARGIN_LEFT), + savedInstanceState.getInt(STATE_LOGO_MARGIN_TOP), + savedInstanceState.getInt(STATE_LOGO_MARGIN_RIGHT), + savedInstanceState.getInt(STATE_LOGO_MARGIN_BOTTOM)); + + // Attribution + uiSettings.setAttributionEnabled(savedInstanceState.getBoolean(STATE_ATTRIBUTION_ENABLED)); + uiSettings.setAttributionGravity(savedInstanceState.getInt(STATE_ATTRIBUTION_GRAVITY)); + uiSettings.setAttributionMargins(savedInstanceState.getInt(STATE_ATTRIBUTION_MARGIN_LEFT), + savedInstanceState.getInt(STATE_ATTRIBUTION_MARGIN_TOP), + savedInstanceState.getInt(STATE_ATTRIBUTION_MARGIN_RIGHT), + savedInstanceState.getInt(STATE_ATTRIBUTION_MARGIN_BOTTOM)); + + mapboxMap.setDebugActive(savedInstanceState.getBoolean(STATE_DEBUG_ACTIVE)); + + String styleUrl = savedInstanceState.getString(STATE_STYLE_URL); + if (!TextUtils.isEmpty(styleUrl)) { + nativeMapView.setStyleUrl(savedInstanceState.getString(STATE_STYLE_URL)); + } + + // User location + try { + mapboxMap.setMyLocationEnabled(savedInstanceState.getBoolean(STATE_MY_LOCATION_ENABLED)); + } catch (SecurityException ignore) { + // User did not accept location permissions + } + + TrackingSettings trackingSettings = mapboxMap.getTrackingSettings(); + //noinspection ResourceType + trackingSettings.setMyLocationTrackingMode( + savedInstanceState.getInt(STATE_MY_LOCATION_TRACKING_MODE, MyLocationTracking.TRACKING_NONE)); + //noinspection ResourceType + trackingSettings.setMyBearingTrackingMode( + savedInstanceState.getInt(STATE_MY_BEARING_TRACKING_MODE, MyBearingTracking.NONE)); + trackingSettings.setDismissLocationTrackingOnGesture( + savedInstanceState.getBoolean(STATE_MY_LOCATION_TRACKING_DISMISS, true)); + trackingSettings.setDismissBearingTrackingOnGesture( + savedInstanceState.getBoolean(STATE_MY_BEARING_TRACKING_DISMISS, true)); + } else if (savedInstanceState == null) { + // Start Telemetry (authorization determined in initial MapboxEventManager constructor) + Timber.i("MapView start Telemetry..."); + MapboxEventManager eventManager = MapboxEventManager.getMapboxEventManager(); + eventManager.initialize(getContext(), getAccessToken()); + } - // User location - try { - mapboxMap.setMyLocationEnabled(savedInstanceState.getBoolean(MapboxConstants.STATE_MY_LOCATION_ENABLED)); - } catch (SecurityException ignore) { - // User did not accept location permissions + // Initialize EGL + nativeMapView.initializeDisplay(); + nativeMapView.initializeContext(); + + // Add annotation deselection listener + addOnMapChangedListener(new OnMapChangedListener() { + @Override + public void onMapChanged(@MapChange int change) { + + // TODO extract logic into separate OnMapReady and Update Component + if (change == DID_FINISH_LOADING_STYLE && initialLoad) { + initialLoad = false; + mapboxMap.getAnnotationManager().reloadMarkers(); + mapboxMap.getAnnotationManager().adjustTopOffsetPixels(mapboxMap); + + // Notify listeners the map is ready + if (onMapReadyCallbackList.size() > 0) { + Iterator iterator = onMapReadyCallbackList.iterator(); + while (iterator.hasNext()) { + OnMapReadyCallback callback = iterator.next(); + callback.onMapReady(mapboxMap); + iterator.remove(); } + } - 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) - Timber.i("MapView start Telemetry..."); - MapboxEventManager eventManager = MapboxEventManager.getMapboxEventManager(); - eventManager.initialize(getContext(), getAccessToken()); - } + // invalidate camera to update overlain views with correct tilt value + mapboxMap.invalidateCameraPosition(); - // Initialize EGL - nativeMapView.initializeDisplay(); - nativeMapView.initializeContext(); - - // Add annotation deselection listener - addOnMapChangedListener(new OnMapChangedListener() { - @Override - public void onMapChanged(@MapChange int change) { - - // TODO extract logic into separate OnMapReady and Update Component - if (change == DID_FINISH_LOADING_STYLE && initialLoad) { - initialLoad = false; - mapboxMap.getAnnotationManager().reloadMarkers(); - mapboxMap.getAnnotationManager().adjustTopOffsetPixels(mapboxMap); - - // Notify listeners the map is ready - if (onMapReadyCallbackList.size() > 0) { - Iterator 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 - mapboxMap.invalidateCameraPosition(); - - } else if (change == REGION_IS_CHANGING || change == REGION_DID_CHANGE || change == DID_FINISH_LOADING_MAP) { - mapboxMap.getMarkerViewManager().scheduleViewMarkerInvalidation(); - - compassView.update(mapboxMap.getTransform().getBearing()); - myLocationView.update(); - mapboxMap.getMarkerViewManager().update(); - - for (InfoWindow infoWindow : mapboxMap.getInfoWindows()) { - infoWindow.update(); - } - } + } else if (change == REGION_IS_CHANGING || change == REGION_DID_CHANGE || change == DID_FINISH_LOADING_MAP) { + mapboxMap.getMarkerViewManager().scheduleViewMarkerInvalidation(); - } - }); + compassView.update(mapboxMap.getTransform().getBearing()); + myLocationView.update(); + mapboxMap.getMarkerViewManager().update(); - // Fire MapLoad - if (savedInstanceState == null) { - Hashtable evt = new Hashtable<>(); - evt.put(MapboxEvent.ATTRIBUTE_EVENT, MapboxEvent.TYPE_MAP_LOAD); - evt.put(MapboxEvent.ATTRIBUTE_CREATED, MapboxEventManager.generateCreateDate()); - MapboxEventManager.getMapboxEventManager().pushEvent(evt); + for (InfoWindow infoWindow : mapboxMap.getInfoWindows()) { + infoWindow.update(); + } } - } - /** - * 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, nativeMapView.getStyleUrl()); - 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()); + // Fire MapLoad + if (savedInstanceState == null) { + Hashtable 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 Activity#onStart()} or {@link Fragment#onStart()} - */ - @UiThread - public void onStart() { - onStartCalled = true; - - // Register for connectivity changes - connectivityReceiver = new ConnectivityReceiver(); - getContext().registerReceiver(connectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); - - nativeMapView.update(); - myLocationView.onStart(); - - if (TextUtils.isEmpty(nativeMapView.getStyleUrl())) { - // if user hasn't loaded a Style yet, load default for them instead - nativeMapView.setStyleUrl(Style.MAPBOX_STREETS); - } + } + + /** + * 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(STATE_HAS_SAVED_STATE, true); + outState.putParcelable(STATE_CAMERA_POSITION, mapboxMap.getCameraPosition()); + outState.putBoolean(STATE_DEBUG_ACTIVE, mapboxMap.isDebugActive()); + outState.putString(STATE_STYLE_URL, nativeMapView.getStyleUrl()); + outState.putBoolean(STATE_MY_LOCATION_ENABLED, mapboxMap.isMyLocationEnabled()); + + // TrackingSettings + TrackingSettings trackingSettings = mapboxMap.getTrackingSettings(); + outState.putInt(STATE_MY_LOCATION_TRACKING_MODE, trackingSettings.getMyLocationTrackingMode()); + outState.putInt(STATE_MY_BEARING_TRACKING_MODE, trackingSettings.getMyBearingTrackingMode()); + outState.putBoolean(STATE_MY_LOCATION_TRACKING_DISMISS, trackingSettings.isDismissLocationTrackingOnGesture()); + outState.putBoolean(STATE_MY_BEARING_TRACKING_DISMISS, trackingSettings.isDismissBearingTrackingOnGesture()); + + // UiSettings + UiSettings uiSettings = mapboxMap.getUiSettings(); + outState.putBoolean(STATE_ZOOM_ENABLED, uiSettings.isZoomGesturesEnabled()); + outState.putBoolean(STATE_ZOOM_ENABLED_CHANGE, uiSettings.isZoomGestureChangeAllowed()); + outState.putBoolean(STATE_SCROLL_ENABLED, uiSettings.isScrollGesturesEnabled()); + outState.putBoolean(STATE_SCROLL_ENABLED_CHANGE, uiSettings.isScrollGestureChangeAllowed()); + outState.putBoolean(STATE_ROTATE_ENABLED, uiSettings.isRotateGesturesEnabled()); + outState.putBoolean(STATE_ROTATE_ENABLED_CHANGE, uiSettings.isRotateGestureChangeAllowed()); + outState.putBoolean(STATE_TILT_ENABLED, uiSettings.isTiltGesturesEnabled()); + outState.putBoolean(STATE_TILT_ENABLED_CHANGE, uiSettings.isTiltGestureChangeAllowed()); + outState.putBoolean(STATE_ZOOM_CONTROLS_ENABLED, uiSettings.isZoomControlsEnabled()); + + // UiSettings - Compass + outState.putBoolean(STATE_COMPASS_ENABLED, uiSettings.isCompassEnabled()); + outState.putInt(STATE_COMPASS_GRAVITY, uiSettings.getCompassGravity()); + outState.putInt(STATE_COMPASS_MARGIN_LEFT, uiSettings.getCompassMarginLeft()); + outState.putInt(STATE_COMPASS_MARGIN_TOP, uiSettings.getCompassMarginTop()); + outState.putInt(STATE_COMPASS_MARGIN_BOTTOM, uiSettings.getCompassMarginBottom()); + outState.putInt(STATE_COMPASS_MARGIN_RIGHT, uiSettings.getCompassMarginRight()); + outState.putBoolean(STATE_COMPASS_FADE_WHEN_FACING_NORTH, uiSettings.isCompassFadeWhenFacingNorth()); + + // UiSettings - Logo + outState.putInt(STATE_LOGO_GRAVITY, uiSettings.getLogoGravity()); + outState.putInt(STATE_LOGO_MARGIN_LEFT, uiSettings.getLogoMarginLeft()); + outState.putInt(STATE_LOGO_MARGIN_TOP, uiSettings.getLogoMarginTop()); + outState.putInt(STATE_LOGO_MARGIN_RIGHT, uiSettings.getLogoMarginRight()); + outState.putInt(STATE_LOGO_MARGIN_BOTTOM, uiSettings.getLogoMarginBottom()); + outState.putBoolean(STATE_LOGO_ENABLED, uiSettings.isLogoEnabled()); + + // UiSettings - Attribution + outState.putInt(STATE_ATTRIBUTION_GRAVITY, uiSettings.getAttributionGravity()); + outState.putInt(STATE_ATTRIBUTION_MARGIN_LEFT, uiSettings.getAttributionMarginLeft()); + outState.putInt(STATE_ATTRIBUTION_MARGIN_TOP, uiSettings.getAttributionMarginTop()); + outState.putInt(STATE_ATTRIBUTION_MARGIN_RIGHT, uiSettings.getAttributionMarginRight()); + outState.putInt(STATE_ATTRIBUTION_MARGIN_BOTTOM, uiSettings.getAttributionMarginBottom()); + outState.putBoolean(STATE_ATTRIBUTION_ENABLED, uiSettings.isAttributionEnabled()); + } + + /** + * You must call this method from the parent's {@link Activity#onStart()} or {@link Fragment#onStart()} + */ + @UiThread + public void onStart() { + onStartCalled = true; + + // Register for connectivity changes + connectivityReceiver = new ConnectivityReceiver(); + getContext().registerReceiver(connectivityReceiver, new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)); + + nativeMapView.update(); + myLocationView.onStart(); + + if (TextUtils.isEmpty(nativeMapView.getStyleUrl())) { + // if user hasn't loaded a Style yet, load default for them instead + nativeMapView.setStyleUrl(Style.MAPBOX_STREETS); } - - /** - * 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#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#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; + + // Unregister for connectivity changes + if (connectivityReceiver != null) { + getContext().unregisterReceiver(connectivityReceiver); + connectivityReceiver = null; } - /** - * You must call this method from the parent's {@link Activity#onStop()} or {@link Fragment#onStop()}. - */ - @UiThread - public void onStop() { - onStopCalled = true; - - // Unregister for connectivity changes - if (connectivityReceiver != null) { - getContext().unregisterReceiver(connectivityReceiver); - connectivityReceiver = null; - } + myLocationView.onStop(); + } + + /** + * 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()}."); + } - myLocationView.onStop(); + destroyed = true; + nativeMapView.terminateContext(); + nativeMapView.terminateDisplay(); + nativeMapView.destroySurface(); + nativeMapView.destroy(); + nativeMapView = null; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_DOWN) { + if (mapboxMap.getUiSettings().isZoomControlsEnabled()) { + zoomButtonsController.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: + // Show the zoom controls + if (mapboxMap.getUiSettings().isZoomControlsEnabled()) { + zoomButtonsController.setVisible(true); + } + return true; - /** - * 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()}."); + case MotionEvent.ACTION_HOVER_EXIT: + // Hide the zoom controls + if (mapboxMap.getUiSettings().isZoomControlsEnabled()) { + zoomButtonsController.setVisible(false); } + return true; - destroyed = true; - nativeMapView.terminateContext(); - nativeMapView.terminateDisplay(); - nativeMapView.destroySurface(); - nativeMapView.destroy(); - nativeMapView = null; + default: + // We are not interested in this event + return false; } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_DOWN) { - if (mapboxMap.getUiSettings().isZoomControlsEnabled()) { - zoomButtonsController.setVisible(true); - } + } + + /** + * 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); } - return mapGestureDetector.onTouchEvent(event) || super.onTouchEvent(event); + } + }); + } + + /** + *

+ * Loads a new map style from the specified URL. + *

+ * {@code url} can take the following forms: + *
    + *
  • {@code Style.*}: load one of the bundled styles in {@link Style}.
  • + *
  • {@code mapbox://styles//