From 5782c9a6baa4a6cf23f54289032aaa757d40861e Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Thu, 9 Jun 2016 10:26:40 +0200 Subject: [PATCH 01/43] [android] #5285 - bring selected MarkerView to the front Fixes #5285 --- .../com/mapbox/mapboxsdk/annotations/MarkerViewManager.java | 1 + .../testapp/activity/annotation/MarkerViewActivity.java | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) 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 bcb3176bf..01fb5d8a7 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 @@ -210,6 +210,7 @@ public class MarkerViewManager { mapboxMap.selectMarker(marker); } marker.setSelected(true); + convertView.bringToFront(); } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java index 2b5ec2ef8..19ae121e8 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java @@ -55,7 +55,8 @@ public class MarkerViewActivity extends AppCompatActivity { new LatLng(38.909698, -77.029642), new LatLng(38.907227, -77.036530), new LatLng(38.905607, -77.031916), - new LatLng(38.889441, -77.050134) + new LatLng(38.889441, -77.050134), + new LatLng(38.888000, -77.050000) //Slight overlap to show re-ordering on selection }; @Override From 8c8625210324eaad6cd926ea823fa77d75512966 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Thu, 9 Jun 2016 12:26:53 +0200 Subject: [PATCH 02/43] [android] #5296 - Add a container ViewGroup for MarkerViews Fixes #5296 --- .../mapboxsdk/annotations/MarkerViewManager.java | 2 +- .../main/java/com/mapbox/mapboxsdk/maps/MapView.java | 11 +++++++++++ .../src/main/res/layout/mapview_internal.xml | 5 +++++ 3 files changed, 17 insertions(+), 1 deletion(-) 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 01fb5d8a7..f1794b808 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 @@ -387,7 +387,7 @@ public class MarkerViewManager { markerViewMap.put(marker, adaptedView); if (convertView == null) { - mapView.addView(adaptedView); + mapView.getMarkerViewContainer().addView(adaptedView); } } } 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 68a2a47cf..b42e764c3 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 @@ -48,6 +48,7 @@ import android.view.Surface; import android.view.TextureView; import android.view.View; import android.view.ViewConfiguration; +import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.FrameLayout; @@ -124,6 +125,7 @@ public class MapView extends FrameLayout { private NativeMapView mNativeMapView; private boolean mHasSurface = false; + private ViewGroup mMarkerViewContainer; private CompassView mCompassView; private ImageView mLogoView; private ImageView mAttributionsView; @@ -224,6 +226,8 @@ public class MapView extends FrameLayout { // Connectivity onConnectivityChanged(isConnected()); + mMarkerViewContainer = (ViewGroup) view.findViewById(R.id.markerViewContainer); + mMyLocationView = (MyLocationView) view.findViewById(R.id.userLocationView); mMyLocationView.setMapboxMap(mMapboxMap); @@ -1132,6 +1136,13 @@ public class MapView extends FrameLayout { return new ArrayList<>(annotations); } + /** + * @return the ViewGroup containing the marker views + */ + public ViewGroup getMarkerViewContainer() { + return mMarkerViewContainer; + } + int getTopOffsetPixelsForIcon(Icon icon) { if (mDestroyed) { diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml index e944a5b4d..8787b0ba7 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml +++ b/platform/android/MapboxGLAndroidSDK/src/main/res/layout/mapview_internal.xml @@ -6,6 +6,11 @@ android:layout_width="match_parent" android:layout_height="match_parent" /> + + Date: Mon, 13 Jun 2016 16:20:21 -0400 Subject: [PATCH 03/43] [android] #4159 - expose an api to enable selection/deselection of markers on map tap (#5312) --- .../com/mapbox/mapboxsdk/maps/MapView.java | 6 +++-- .../com/mapbox/mapboxsdk/maps/UiSettings.java | 22 +++++++++++++++++++ .../infowindow/InfoWindowActivity.java | 8 +++++++ .../src/main/res/menu/menu_infowindow.xml | 6 +++++ .../src/main/res/values/strings.xml | 3 ++- 5 files changed, 42 insertions(+), 3 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index b42e764c3..658d67e75 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 @@ -1688,8 +1688,10 @@ public class MapView extends FrameLayout { } } } else { - // deselect any selected marker - mMapboxMap.deselectMarkers(); + if (mMapboxMap.getUiSettings().isDeselectMarkersOnTap()) { + // deselect any selected marker + mMapboxMap.deselectMarkers(); + } // notify app of map click MapboxMap.OnMapClickListener listener = mMapboxMap.getOnMapClickListener(); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java index 3cd9efb13..0a20d13b6 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java @@ -33,6 +33,8 @@ public class UiSettings { private boolean zoomControlsEnabled; + private boolean deselectMarkersOnTap = true; + UiSettings(@NonNull MapView mapView) { this.mapView = mapView; this.compassSettings = new ViewSettings(); @@ -483,6 +485,26 @@ public class UiSettings { return zoomControlsEnabled; } + /** + * Gets whether the markers are automatically deselected (and therefore, their infowindows + * closed) when a map tap is detected. + + * @return If true, markers are deselected on a map tap. + */ + public boolean isDeselectMarkersOnTap() { + return deselectMarkersOnTap; + } + + /** + * Sets whether the markers are automatically deselected (and therefore, their infowindows + * closed) when a map tap is detected. + * + * @param deselectMarkersOnTap + */ + public void setDeselectMarkersOnTap(boolean deselectMarkersOnTap) { + this.deselectMarkersOnTap = deselectMarkersOnTap; + } + /** *

* Changes whether the user may scroll around the map. diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java index 7ac3c5966..a496fc3f9 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java @@ -82,6 +82,10 @@ public class InfoWindowActivity extends AppCompatActivity implements OnMapReadyC mapboxMap.setAllowConcurrentMultipleOpenInfoWindows(allowConcurrentInfoWindow); } + private void toggleDeselectMarkersOnTap(boolean deselectMarkersOnTap) { + mapboxMap.getUiSettings().setDeselectMarkersOnTap(deselectMarkersOnTap); + } + @Override public boolean onInfoWindowClick(@NonNull Marker marker) { Toast.makeText(getApplicationContext(), "OnClick: " + marker.getTitle(), Toast.LENGTH_LONG).show(); @@ -157,6 +161,10 @@ public class InfoWindowActivity extends AppCompatActivity implements OnMapReadyC toggleConcurrentInfoWindow(!item.isChecked()); item.setChecked(!item.isChecked()); return true; + case R.id.action_toggle_deselect_markers_on_tap: + toggleDeselectMarkersOnTap(!item.isChecked()); + item.setChecked(!item.isChecked()); + return true; case android.R.id.home: onBackPressed(); return true; diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml index 583b760d7..adca8d2e0 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/menu/menu_infowindow.xml @@ -8,6 +8,12 @@ android:id="@+id/action_toggle_concurrent_infowindow" app:showAsAction="never" android:checkable="true"/> + \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml index ce57e160c..b856e7579 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml @@ -81,7 +81,8 @@ Restart map view after temporarily leaving to another activity Use an Android SDK View as marker - Concurrent Open InfoWindowsr + Concurrent Open InfoWindows + Deselect Markers On Tap Dismiss location tracking on gesture Dismiss bearing tracking on gesture Reset From b3467a555ac48d34470210bab0c7172161b0540c Mon Sep 17 00:00:00 2001 From: Tobrun Van Nuland Date: Mon, 13 Jun 2016 14:11:18 +0200 Subject: [PATCH 04/43] [android] #4924 - Make Gesture Focal Point Configurable --- .../com/mapbox/mapboxsdk/maps/MapView.java | 68 ++++++++++++------- .../com/mapbox/mapboxsdk/maps/UiSettings.java | 23 +++++++ .../annotation/MarkerViewActivity.java | 3 + 3 files changed, 69 insertions(+), 25 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapView.java index 658d67e75..ae71ee384 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 @@ -152,6 +152,8 @@ public class MapView extends FrameLayout { private int mContentPaddingRight; private int mContentPaddingBottom; + private PointF mFocalPoint; + private StyleInitializer mStyleInitializer; private List mOnMapReadyCallbackList; @@ -566,6 +568,18 @@ public class MapView extends FrameLayout { } } + void setFocalPoint(PointF focalPoint) { + if (focalPoint == null) { + // resetting focal point, + UiSettings uiSettings = mMapboxMap.getUiSettings(); + // need to validate if we need to reset focal point with user provided one + if (uiSettings.getFocalPoint() != null) { + focalPoint = uiSettings.getFocalPoint(); + } + } + mFocalPoint = focalPoint; + } + /** * You must call this method from the parent's {@link Activity#onLowMemory()} or {@link Fragment#onLowMemory()}. */ @@ -1548,8 +1562,12 @@ public class MapView extends FrameLayout { || mShoveGestureDetector.isInProgress(); if (mTwoTap && isTap && !inProgress) { - PointF focalPoint = TwoFingerGestureDetector.determineFocalPoint(event); - zoom(false, focalPoint.x, focalPoint.y); + if (mFocalPoint != null) { + zoom(false, mFocalPoint.x / mScreenDensity, mFocalPoint.y / mScreenDensity); + } else { + PointF focalPoint = TwoFingerGestureDetector.determineFocalPoint(event); + zoom(false, focalPoint.x, focalPoint.y); + } mTwoTap = false; return true; } @@ -1608,12 +1626,12 @@ public class MapView extends FrameLayout { } // Single finger double tap - if (mMapboxMap.getTrackingSettings().isLocationTrackingDisabled()) { + if (mFocalPoint != null) { + // User provided focal point + zoom(true, mFocalPoint.x, mFocalPoint.y); + } else { // Zoom in on gesture zoom(true, e.getX(), e.getY()); - } else { - // Zoom in on user location view - zoom(true, mMyLocationView.getCenterX(), mMyLocationView.getCenterY()); } break; } @@ -1839,23 +1857,18 @@ public class MapView extends FrameLayout { // Gesture is a quickzoom if there aren't two fingers mQuickZoom = !mTwoTap; - TrackingSettings trackingSettings = mMapboxMap.getTrackingSettings(); - // Scale the map - if (uiSettings.isScrollGesturesEnabled() && !mQuickZoom && trackingSettings.isLocationTrackingDisabled()) { + if (mFocalPoint != null) { + // arround user provided focal point + mNativeMapView.scaleBy(detector.getScaleFactor(), mFocalPoint.x / mScreenDensity, mFocalPoint.y / mScreenDensity); + } else if (mQuickZoom) { + // around center map + mNativeMapView.scaleBy(detector.getScaleFactor(), (getWidth() / 2) / mScreenDensity, (getHeight() / 2) / mScreenDensity); + } else { // around gesture mNativeMapView.scaleBy(detector.getScaleFactor(), detector.getFocusX() / mScreenDensity, detector.getFocusY() / mScreenDensity); - } else { - if (trackingSettings.isLocationTrackingDisabled()) { - // around center map - mNativeMapView.scaleBy(detector.getScaleFactor(), (getWidth() / 2) / mScreenDensity, (getHeight() / 2) / mScreenDensity); - } else { - // around user location view - float x = mMyLocationView.getX() + mMyLocationView.getWidth() / 2; - float y = mMyLocationView.getY() + mMyLocationView.getHeight() / 2; - mNativeMapView.scaleBy(detector.getScaleFactor(), x / mScreenDensity, y / mScreenDensity); - } } + return true; } } @@ -1925,16 +1938,14 @@ public class MapView extends FrameLayout { bearing += detector.getRotationDegreesDelta(); // Rotate the map - if (mMapboxMap.getTrackingSettings().isLocationTrackingDisabled()) { + if (mFocalPoint != null) { + // User provided focal point + mNativeMapView.setBearing(bearing, mFocalPoint.x / mScreenDensity, mFocalPoint.y / mScreenDensity); + } else { // around gesture mNativeMapView.setBearing(bearing, detector.getFocusX() / mScreenDensity, detector.getFocusY() / mScreenDensity); - } else { - // around center userlocation - float x = mMyLocationView.getX() + mMyLocationView.getWidth() / 2; - float y = mMyLocationView.getY() + mMyLocationView.getHeight() / 2; - mNativeMapView.setBearing(bearing, x / mScreenDensity, y / mScreenDensity); } return true; } @@ -2426,6 +2437,13 @@ public class MapView extends FrameLayout { mMapboxMap.setMyLocationEnabled(true); } mMyLocationView.setMyLocationTrackingMode(myLocationTrackingMode); + + if (myLocationTrackingMode == MyLocationTracking.TRACKING_FOLLOW) { + setFocalPoint(new PointF(mMyLocationView.getCenterX(), mMyLocationView.getCenterY())); + } else { + setFocalPoint(null); + } + MapboxMap.OnMyLocationTrackingModeChangeListener listener = mMapboxMap.getOnMyLocationTrackingModeChangeListener(); if (listener != null) { listener.onMyLocationTrackingModeChange(myLocationTrackingMode); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java index 0a20d13b6..4ce631fc3 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/UiSettings.java @@ -1,7 +1,9 @@ package com.mapbox.mapboxsdk.maps; +import android.graphics.PointF; import android.support.annotation.ColorInt; import android.support.annotation.NonNull; +import android.support.annotation.Nullable; import android.support.annotation.UiThread; import android.view.Gravity; import android.view.View; @@ -35,6 +37,8 @@ public class UiSettings { private boolean deselectMarkersOnTap = true; + private PointF focalPoint; + UiSettings(@NonNull MapView mapView) { this.mapView = mapView; this.compassSettings = new ViewSettings(); @@ -563,6 +567,25 @@ public class UiSettings { setZoomGesturesEnabled(enabled); } + /** + * Sets the focal point used as center for a gesture + * + * @param focalPoint the focal point to be used. + */ + public void setFocalPoint(@Nullable PointF focalPoint) { + this.focalPoint = focalPoint; + mapView.setFocalPoint(focalPoint); + } + + /** + * Returns the gesture focal point + * + * @return The focal point + */ + public PointF getFocalPoint() { + return focalPoint; + } + /** * Returns the measured height of the MapView * diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java index 19ae121e8..0f08c6ae8 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/MarkerViewActivity.java @@ -5,6 +5,7 @@ import android.animation.AnimatorInflater; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; +import android.graphics.PointF; import android.os.Bundle; import android.os.Handler; import android.support.annotation.NonNull; @@ -161,6 +162,8 @@ public class MarkerViewActivity extends AppCompatActivity { .icon(IconFactory.getInstance(mMapView.getContext()) .fromResource(R.drawable.ic_arsenal)) ); + + mMapboxMap.getUiSettings().setFocalPoint(new PointF(mMapView.getMeasuredWidth() / 2, mMapView.getMeasuredHeight() / 4)); } }); } From 4f622a75dba03fe3f8dfb73c470b42eee676a576 Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Mon, 13 Jun 2016 14:53:30 -0500 Subject: [PATCH 05/43] [android] #4959 - Dynamic Sizing Of Default InfoWindow Based On Availability Of Title And Snippet Data --- .../mapboxsdk/annotations/InfoWindow.java | 18 ++++++++++++++++-- .../infowindow/InfoWindowActivity.java | 8 ++++++-- 2 files changed, 22 insertions(+), 4 deletions(-) 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 7452ab8fa..aaa5525b4 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 @@ -3,6 +3,7 @@ package com.mapbox.mapboxsdk.annotations; import android.content.res.Resources; import android.graphics.PointF; import android.support.annotation.LayoutRes; +import android.text.TextUtils; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -222,9 +223,22 @@ public class InfoWindow { } mMapboxMap = new WeakReference<>(mapboxMap); String title = overlayItem.getTitle(); - ((TextView) view.findViewById(R.id.infowindow_title)).setText(title); + 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) view.findViewById(R.id.infowindow_description)).setText(snippet); + 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); + } } InfoWindow setBoundMarker(Marker boundMarker) { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java index a496fc3f9..7ff0acdb2 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/InfoWindowActivity.java @@ -8,7 +8,6 @@ import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; import android.widget.Toast; - import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.MarkerOptions; @@ -16,7 +15,6 @@ import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.testapp.R; import com.mapbox.mapboxsdk.maps.MapView; - import java.text.DecimalFormat; public class InfoWindowActivity extends AppCompatActivity implements OnMapReadyCallback, MapboxMap.OnInfoWindowCloseListener, MapboxMap.OnMapLongClickListener, MapboxMap.OnInfoWindowClickListener, MapboxMap.OnInfoWindowLongClickListener { @@ -61,6 +59,12 @@ public class InfoWindowActivity extends AppCompatActivity implements OnMapReadyC .snippet("E St NW with 17th St NW") .position(new LatLng(38.8954236, -77.0394623))); + mapboxMap.addMarker(new MarkerOptions().title("The Ellipse").position(new LatLng(38.89393, -77.03654))); + + mapboxMap.addMarker(new MarkerOptions().position(new LatLng(38.89596, -77.03434))); + + mapboxMap.addMarker(new MarkerOptions().snippet("Lafayette Square").position(new LatLng(38.89949, -77.03656))); + Marker marker = mapboxMap.addMarker(new MarkerOptions() .title("White House") .snippet("The official residence and principal workplace of the President of the United States, located at 1600 Pennsylvania Avenue NW in Washington, D.C. It has been the residence of every U.S. president since John Adams in 1800.") From 7942ce94558739b0171abcee1281e1aa4c60d409 Mon Sep 17 00:00:00 2001 From: Tobrun Van Nuland Date: Mon, 13 Jun 2016 13:05:25 +0200 Subject: [PATCH 06/43] [android] #5279 - expose MarkerView alpha --- .../annotations/BaseMarkerViewOptions.java | 23 ++++++++++++++++++- .../annotations/MarkerViewOptions.java | 3 +++ .../annotation/MarkerViewActivity.java | 1 + .../annotations/CountryMarkerViewOptions.java | 8 +++++-- .../annotations/TextMarkerViewOptions.java | 5 ++++ 5 files changed, 37 insertions(+), 3 deletions(-) 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 2a41fad23..a5c6397b6 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 @@ -29,6 +29,7 @@ public abstract class BaseMarkerViewOptions { @@ -23,8 +24,10 @@ public class CountryMarkerViewOptions extends BaseMarkerViewOptions { @@ -24,6 +25,8 @@ public class TextMarkerViewOptions extends BaseMarkerViewOptions Date: Mon, 13 Jun 2016 12:46:38 +0200 Subject: [PATCH 07/43] [android] #5276 - icon should be optional for MarkerView --- .../mapboxsdk/annotations/IconFactory.java | 8 ++++++++ .../com/mapbox/mapboxsdk/maps/MapboxMap.java | 8 +++++++- .../res/drawable-hdpi/default_markerview.png | Bin 0 -> 1669 bytes .../res/drawable-mdpi/default_markerview.png | Bin 0 -> 1115 bytes .../res/drawable-xhdpi/default_markerview.png | Bin 0 -> 2163 bytes .../res/drawable-xxhdpi/default_markerview.png | Bin 0 -> 3163 bytes .../res/drawable-xxxhdpi/default_markerview.png | Bin 0 -> 4071 bytes 7 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/default_markerview.png create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/default_markerview.png create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/default_markerview.png create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/default_markerview.png create mode 100644 platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/default_markerview.png 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 d7d41b98b..93c6deddc 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 @@ -33,6 +33,7 @@ public final class IconFactory { private Context mContext; private static IconFactory sInstance; private Icon mDefaultMarker; + private Icon mDefaultMarkerView; private BitmapFactory.Options mOptions; private int mNextId = 0; @@ -121,6 +122,13 @@ public final class IconFactory { return mDefaultMarker; } + public Icon defaultMarkerView() { + if (mDefaultMarkerView == null) { + mDefaultMarkerView = fromResource(R.drawable.default_markerview); + } + return mDefaultMarkerView; + } + private Icon fromInputStream(@NonNull InputStream is) { Bitmap bitmap = BitmapFactory.decodeStream(is, null, mOptions); return fromBitmap(bitmap); diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 3fbdebe2b..72eabf579 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -20,6 +20,7 @@ import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.BaseMarkerOptions; import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions; import com.mapbox.mapboxsdk.annotations.Icon; +import com.mapbox.mapboxsdk.annotations.IconFactory; import com.mapbox.mapboxsdk.annotations.InfoWindow; import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.MarkerOptions; @@ -1208,7 +1209,12 @@ public class MapboxMap { private MarkerView prepareViewMarker(BaseMarkerViewOptions markerViewOptions) { MarkerView marker = markerViewOptions.getMarker(); - marker.setIcon(markerViewOptions.getIcon()); + + Icon icon = markerViewOptions.getIcon(); + if (icon == null) { + icon = IconFactory.getInstance(mMapView.getContext()).defaultMarkerView(); + } + marker.setIcon(icon); return marker; } diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-hdpi/default_markerview.png new file mode 100644 index 0000000000000000000000000000000000000000..651482f3ee218d6f646965a7bf97fada5c6f0828 GIT binary patch literal 1669 zcmV;027394P)pbBO=|1`fA+W@JDxgzcG}b_Etzb>0$M?&vJ#-E%`S&MRIBY0X~m%u;jrS6 zOM5_j1fRN>mAZ#W3#e*(0`{^&ttzbqS{l$UXd5*|ffQ`*xF)G<%QKnyPvd{n>>=Zj zrkSx5n(t_T@B6*?{e5pdbRd(_Xg_cU_#H3|M7F7zz#Q-~Fg;-y>2@|f9RS}3#sQQ- zfOvN|;XvRay<)XWc6F6veUr>N2qfyHBI!2{3d^#BHzrMEi@gv~LX!H#5=f?$gfPZ~`ZS6LI*M>%b%Ss@? zi>k`wmKRkOWup=<+pG;Ra1MyP)UV=~Bv&JK%OYJYGMmpco6qyTX;QZ=*EN1g;-!8S zyZ+As`0W2)k0}brV^LQFv-v#pg#xv0AX$=luBV3+hYvfhJsyh^Qxx=a`E}qO&tx<@ z3jFKT&=7+z3vVnfvAD8=Ix@oW_&CR3c?E#Xr=K!6HHG%Y7d#^br=EDi(MBqt=SDIK z@GI$bFgOm3o_y*lB(K-;q+b^bJpbBj{AO~J?ty{L|GEbT`1z}^QqAR9xOo$g$3ve( z-7A3r^Gizrcf7!Cj&I!=_URZ{u$Fo&ohwnUR{1uYeQe-wv)NW`6OJv@-qB|ZOUqkd1$&lqwaUWMGQekBPwUjH&)2Lb zU#0K-WbjNX)jI9@wnJjVFy?@ZX}v&3H}(w8=my!+)1SPg*au-b>Say$GCdxxAAs zFITIZHM>(nIX>E2qN=JSgoyt;5I7QDUr&o>0G>tpDj^Xvb_faTx z&9;3II3$F4V47yd5v;0eKX7Dw2yV&p?1_5)MBX&}`XUh&S$?E+zSJ~o9?$H%;c#My zaCQqJWYhfdjwNk@9s>?JxiRna-FT*6AIs>5JkZmF-{;$W{eQA}o96n1(zK$yVS2rF z2NPXF2%l-1#m(eWRkaIn4PaW5O1EVB&6?HZlkdKxZdn`kYImnwvixRRl1gpz@376< zII$4okR1OE znr1@?;R8bKujDmN(;q4)(=>}h2pQP4 P00000NkvXXu0mjfykRrp literal 0 HcmV?d00001 diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-mdpi/default_markerview.png new file mode 100644 index 0000000000000000000000000000000000000000..63cb7b5f4bda0f8975e5a64e8278abd0f48c4588 GIT binary patch literal 1115 zcmV-h1f=_kP))!wX1L#Ra zK~zY`t(H$nBX<3qf=rsj+)dlI;ICFA&H4v+AqxI_ul*d z-h1EoW~PY-h^p#+pdYvm`0Qf?m;xpux;|DfuBi^u05IZryW7KUZK$%0D$4-q`8;|) z&!VQ0&E=B7HxXSQZ%7zb)$d$_c>h*sCm;D$&cjAlXL@CYL+f}fqU(dDbD@H4#P4=L zxEsE~Rj-GO&~oJiIsyUy+TZW}Ob~o84-S4Q6Gl~az$J*Icf&VuOA?obQxv)G^Rb%V z?)y@5ExbH9h&ycCNMA>&E?L2{(DHe-e4c`3ow2(miN1~yzzBd4Rn-BvBt5v**?Go! zHl1ej{d;z8#Ynu4GyQ|15N&Vg3WKFZ`+~(+Y@IS)=7`d9;{E|dA7DJE6&jjf4IN4YX zf6YYL9EJm!*Ykf@&zB(36A18XXsC*`BuY;pfKw2vFFNIz7lDc7j()p#)o!-7LORV) z_wM2E?mq2pEJjZta7JN(g(Ev7c>uGU2;SQd+^O@L=5m5J#3)S-1e)hNsJ z5Ysdct>dYPu1}Q-Z4Az?uTwih=OJgB%&xBk3|7t|c9uzCbb595(uB6}s2xjfh5(PW z-QDE7OO*aj)6jNzlfa|eO`#%70~nlJ-#EAQoM|$*z5y_3$IvK49=Ei-F;1)(=aoLW zw1jbDy?ETx@}|~S9;{F(Bq)mVG0?s(ic4*|+^1qwlfU*&G@nWl&t#T=mgR2^hr_2R zic3+HeZw${Wx`M>AUd(2{2>N_3x64)j(*649>i&Yu^>EJVEH(NH za8*&1J;N}LN+q{fW()9Il9smw@#$pj4|1kS&NP``Sz${MpT3r)@bP>wS2MIp41wn-pOEhc~|kB+ETC4C6>qlx?8dR_)&)3#=p(iQ~F|U-k(3?8kFX hc?Mu45{W{k;UCZ-pyl3)q~ZVo002ovPDHLkV1j|39e4l$ literal 0 HcmV?d00001 diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xhdpi/default_markerview.png new file mode 100644 index 0000000000000000000000000000000000000000..175f88ff88593e8d404333168ff0bd3f8c80c958 GIT binary patch literal 2163 zcmV-(2#oiMP)_x@ zSPO(}Pm9lox2A@jKHsKy=A%*KsT6b3 zDAS8etYw~?KfVg|_9%+_%7A^r;0fRh-HbH*{Tyg+VNZR~minfb6h^{xgjZIKTPpBD zkD}Zy8?Y}JyrgRmZ%qxyJ30z9Wmo2-QSOb86Hld#TfIGsa>+JeUodz>_cuD4nm8H? z;S@zGAzCKGpe!@KuwdNk?@^R9TRkh5f;-;P!J*x|5giUHC8EQ@o53Kyni`%d3P9&6 zx4ZRrGI_HkU|%r!A@C;yuD!95*Cj!ZCm(X zoHQ;EnR8~o-EIK1);DY$9KinOW?JhTHZc?c>Za{Ud#8bbx2DEcP=pf+9xf~} zn@DW=`7V!#!%a;zdpwrbYj131=!YMOr&58wVDNO0qV$UZr`+xvz|LRn*+XMpou$RT z4u`ovJ4-B`24L^Wlk9u{ecn8F40j;F;=}~8begBj%V^mwyDhFO2m&+9%K)vnlgYmc zdIKN>{NdlMF5U;cXRmMIjZw2Ogb9n;k9c#xPBdgw;LKbW+CvjOoo3B z<}yvl0h};utQEL$B9VhTb>#~0Uc6WU2T<+v@$SWooVs!afbSL;2^VpNd|zz#`;E&J z4&Wd_OCVs$1P}G{bfmkR_O7nde$~~*k?!tI@0Jo1%Rz_HXj*9k;+mEVh{Na3Sq>)S z+1W(GQgoYGI&*+l%saQbnhS_(8(mGc&&S@ACpWE8%FJfKfKeAqNlgFtjr;c5PQ=DL zF$)?ru>>6a#Kjh1ozn?G9s2PQB~jXWy-p{)bpLpG?V4pkJ5B|p@%Sr%4T8UON2)>l{AdGH{j z%T-|32bV8%_v4RqrEXu)+DULwmPu|z`(Fh8%)1QmyLaBfTT^4XSujeTksFOv5_$3@ z=W}-Iu;G9I9vU((B|&euz5u%Hw)vHAxANNmfgVNqph~}g6X+V5o3jPj?D6oMwl?CL z#@y;^E(zB;owU@}S_+7K8JU~I#DoDj09=WuQi1ts)b`=r>vZx~88BNN>h%<(>P#Dn zTAz{h1AIF@{eP<(roH=(xsAD!dZbfplOfZtwzJe`oXJ!8c(GdevJV$JTqg?dsi(tta=VQ4=^$_`&!aYJe6W( zX4beoUu<4ow4?4(lz!muTIM2t(yY zwGp*zf-v-n-#-uvg)B|0#1dfjk|ebQJAm3qRn@(pY1(g-n&wJpGQ1&4mf-#)%RF0J zVjW@wUhf&z;ShnKBuNdDBxO`pP1*tsg+jF^F!9AH+M%^%v(Kb#_E(Wuj0TSvf35qa zaMMc)gYrhyPE}X``5TvOEN}mSBuN2Dl2%n!O_u}=g+lc}8{pb%!|$uBr}n4Qbv5hj zKc8Jzc|($L7issEM1rrrA0@M%WyRt6{9j)0=fwtKx<=Fa+7!2dYc1uQ-@07i{8H0S ztY@?JKgQ#JOm_3(#((!6Py#+ZPn>-dOT;> zA+{8c=S-M?_+E;~S%=t7kLRq7c-pPA6hv`Lsh}~-lqklYI-M7c4&0m{ABV%a4*99m zd0|QvV>SRqouvRUU^jK#a=V8jV%6o1QaH(cG|GH5n)}@?B350#<#rF1k<$YOJ}61j zu5zlwf1S>ew>7QB32#j=DNO#jNM=1tTo7*ky{_&W<%vU8)v)aWW-5lbud>ihkLPS!5XRDiFlI9-wvtRiHxmklT7i0g8nPtI@>ISC z=U!Ed6_Sk3vN=dpRn16}lrATlD=gEpEXTL3B&w<=B}vkNx=IC*P0dZqvb^-tTC77x z0gqlIw?kHeNm-VowpxC@Hn#xI*94{kbNO1ceJ0VHOXE+hfGJf#m1X(W|95K(*gD-u p-MVILEtpROl0ZzBWjl45{{hYSg6BmCMlb*X002ovPDHLkV1h??2uA<_ literal 0 HcmV?d00001 diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxhdpi/default_markerview.png new file mode 100644 index 0000000000000000000000000000000000000000..be782e1d4b3d842c5d07906870d86efadceee30b GIT binary patch literal 3163 zcmV-h45agkP)8FJ3+PEi zK~#9!<(y4y8^;yL|KyTOQluyjsgHP_Bu8>=eIQH86e-E(YDJMIwep5N zXm`C_EhX*;DJgw`U~;)0&TrqFH}Acfp$%1%^TA*MKo5Z90GQLIE>NOBhck%fY_~AZo6>e-sDsnqF<&bi$qyO<0zY&xfOth~=PK;5Qit>1S3REgEBX9o!@%c*!FK`t zT6+I%OACJ7)diZOu-!u0?dWJ~LVj%xY%ZsSwq42Rhjas<4+i^0_b+?lm-p`nWw&Fe z2xYfpZ!n1YOa|H2Rq68aS3REFSMvFL6^~&tL>!Ug-jL6SpB_B8BQ&ceyddDp__)%8 za{vwxuxwm?Z#i{ckYHVu1269oGcG4IMd9VHF1RR%bSWS*Y;DrwTq}>;6J1?s^4DXh z3+-?q;HkrR4`rK|yV0l5nSUQbw9zMjXAZXq*C(fZRio&7BMs$ZlrXA#St*y#T zDT{-8kNDN zHjF~k6oqG7S}?V+00rZyWYThP+DXuq87pDK-QDQFeq9?@CHwmN(0~0p!rk5SwYy78 zrp#N#(gy%`F^rU}7f%Hm44crGPv$>_ySveM=@Oheysy*mN8hDOCD30cli(}x0a~JB zX+Iwfw%f5@E0z-kqvkx8PRq{86A0*rRYQ9M0oj?2rPGGZy0xJMx~BvV3p7(1_w3U)+;Ke9y``o1xx|QGno?YRx)NQ8PiHF$1@o#fSo+C#r16H<`+*qxw47il3#}W-IMG7jc z5G&f!((wP4SPq<^^pX@;zq0=T+Co9oUsy?*RtaiVnHB(M(=0x_cUOAL4X`W$O6$@w z$*ki`tR=uSMWMI38NJQTH7&$T3@SFLfj^Xhrxq4)G!n6N#jxG)N4wvT-sa}2CkVVC zD65qcTWKsU?sAi(u5VMRU7Hc9`W{#A;8Q0L?@KQxN}tfK5>?;d-z;0Yi1o!MWD5mM zFD~vn*y+VZrDx_uCT(DGg-w1U!}ss+I$%|w-&b!>)XInDC$ihLtkN#j+SLRWH-cQ; zjapXq^`f3lEz#YkWex2{D=zV9Y1wFTpccXlf?B)pX=!(>n$}sR$KJ{F^0%p!+A~Kt zt7)N(mPKi+mHfYofW^9(JT^vVX1CRWWeWw2%*?8%p;60#6%#opIj|ek)7u7oV|rTY zs5YI33FL*Veo5D2+5pSOl;x5eQ&TmKz<5Exjj5@U z(v8?BR0UXiqDs^LVybqg{l(MhHhZBX~)wKYvQ%T;bPq3IL=r}*7Z5kg#qkVhQH36=tj8r>s;)~P>d9FFw< zwKaH(#a;m5@{izmyA7W{onBnTZG}Hz?e-7;;q`v1acdob7D9-F5R$7z<5UH(0RUYP zO}3njxLm`%Jm2d8!T>P8oWUMK;L*9AkBUVr4IYCeh3b zhJhoINEkp{rOs{9;kbT)=U=x0E}{569%QrVXlkl>JWJy?zqWovwg{}me7=6pZs#j> zz(GQYjpMi#-N2DZq#b~+r9RGX=R?Kfc%vZv3;^;xuWLN3$L$17|K`6m9oIP`>Ioq( zj?><-LTv(TXzR?R)0x`$SXl8Ezkg90&n~AE&Gq$LhK}ROC&jo$%5m;*-nvf>`n7S1nqEah?B33jmu7I&1ReYr`P-23dikM z(m)7#p!D8qu#nMUL@jZOS{bA1w~N4v6mNe%F;S8~^MZiSCnn@Lxd^O`(e&GKidwNK zSfkWKQw!KKx#o6H#+}ZnvH+;8G^&4>BkpuYuesfm7Kh`ZvL;Ok*=u$1f7j`ZD}xd? zmxJAI$9yJ(am9XU)^7jcFFxPjtB`CtIgU$}0}fZ=3o+ty4Ikq9Fb#A{nUyjF%GzxI z`lH`}u3G7(61ZkZ0Iqty=hket4d%LLvrS(0de7CWA2kDxQ`E|3ulKa%#3Uzm+3P)R zp_9@L{HWT{BQDqJBCt{fRz_T|TELbt*;MmzGk|CC!;Niz&HUs1NiaU8eHq0si7! zRe&`fKpg-N02cu13~ap)FaXE`SOt)07{=20{(toEl|>e?>V5zK002ovPDHLkV1gD0 B|I7dY literal 0 HcmV?d00001 diff --git a/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/default_markerview.png b/platform/android/MapboxGLAndroidSDK/src/main/res/drawable-xxxhdpi/default_markerview.png new file mode 100644 index 0000000000000000000000000000000000000000..fe1c486518d5c73b5bfacf5a1f9e3a6b21386bdc GIT binary patch literal 4071 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 Date: Thu, 16 Jun 2016 10:58:17 +0200 Subject: [PATCH 08/43] [android] #5342 - initial marker animation --- .../mapboxsdk/annotations/MarkerView.java | 85 ++++++++++- .../annotations/MarkerViewManager.java | 135 +++++++++++++++--- .../com/mapbox/mapboxsdk/maps/MapView.java | 6 +- .../annotation/AnimatedMarkerActivity.java | 31 ++-- .../res/layout/activity_animated_marker.xml | 7 +- 5 files changed, 218 insertions(+), 46 deletions(-) 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 49d7a061d..580c3796d 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 @@ -1,12 +1,16 @@ package com.mapbox.mapboxsdk.annotations; +import android.animation.AnimatorSet; import android.graphics.Bitmap; +import android.graphics.PointF; import android.support.annotation.FloatRange; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.View; +import android.view.animation.AnimationUtils; import com.mapbox.mapboxsdk.constants.MapboxConstants; +import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapboxMap; /** @@ -26,8 +30,8 @@ public class MarkerView extends Marker { private float anchorU; private float anchorV; - private float offsetX; - private float offsetY; + private float offsetX = -1; + private float offsetY = -1; private float infoWindowAnchorU; private float infoWindowAnchorV; @@ -43,6 +47,15 @@ public class MarkerView extends Marker { private boolean selected; + private LatLng targetPosition; + private boolean shouldAnimate; + private boolean isAnimationRunning; + private AnimatorSet set; + + private long startTime; + private long duration; + private long remainingTime; + /** * Publicly hidden default constructor */ @@ -279,7 +292,7 @@ public class MarkerView extends Marker { * * @param alpha the alpha value to animate to */ - public void setAlpha(@FloatRange(from=0.0, to=255.0)float alpha) { + public void setAlpha(@FloatRange(from = 0.0, to = 255.0) float alpha) { this.alpha = alpha; if (markerViewManager != null) { markerViewManager.animateAlpha(this, alpha); @@ -339,6 +352,72 @@ public class MarkerView extends Marker { markerViewManager = mapboxMap.getMarkerViewManager(); } + @Override + public void setPosition(LatLng position) { + setPosition(position, 0); + } + + public void setPosition(LatLng position, long duration) { + if (duration <= 0) { + // update position instantly + super.setPosition(position); + if (markerViewManager != null) { + markerViewManager.update(); + } + } else { + // animate using Android SDK animations + this.targetPosition = position; + if (markerViewManager != null) { + markerViewManager.animatePosition(this, duration); + } + } + } + + boolean shouldAnimate() { + return shouldAnimate; + } + + void setShouldAnimate(boolean animating) { + shouldAnimate = animating; + } + + boolean isAnimating() { + return isAnimationRunning; + } + + void setAnimating(boolean animationRunning) { + isAnimationRunning = animationRunning; + } + + LatLng getTargetPosition() { + return targetPosition; + } + + void setAnimation(AnimatorSet set) { + this.set = set; + } + + AnimatorSet getAnimation() { + return set; + } + + long getRemainingTime() { + long time = duration - (AnimationUtils.currentAnimationTimeMillis() - startTime); + return time > 0 ? time : 0; + } + + void setDuration(long duration) { + this.duration = duration; + } + + void setStartTime(long startTime) { + this.startTime = startTime; + } + + PointF getScreenLocation(@NonNull View convertView) { + return new PointF(convertView.getX() + offsetX, convertView.getY() + offsetY); + } + /** * Get the String representation of a MarkerView. * 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 f1794b808..b438e28d9 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 @@ -1,14 +1,19 @@ package com.mapbox.mapboxsdk.annotations; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.PointF; +import android.os.CountDownTimer; import android.os.SystemClock; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import android.support.v4.util.Pools; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.animation.AnimationUtils; import android.widget.ImageView; import com.mapbox.mapboxsdk.R; @@ -38,6 +43,7 @@ public class MarkerViewManager { private long viewMarkerBoundsUpdateTime; private MapboxMap.OnMarkerViewClickListener onMarkerViewClickListener; private ImageMarkerViewAdapter defaultMarkerViewAdapter; + private CountDownTimer timer; /** * Creates an instance of MarkerViewManager. @@ -111,24 +117,60 @@ public class MarkerViewManager { *

*/ public void update() { - View convertView; - for (MarkerView marker : markerViewMap.keySet()) { - convertView = markerViewMap.get(marker); + for (final MarkerView marker : markerViewMap.keySet()) { + final View convertView = markerViewMap.get(marker); if (convertView != null) { - PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); - int x = (int) (marker.getAnchorU() * convertView.getMeasuredWidth()); - int y = (int) (marker.getAnchorV() * convertView.getMeasuredHeight()); + if (marker.isAnimating() || !marker.shouldAnimate()) { + if (marker.isAnimating()) { + // cancel ongoing animations + marker.setAnimating(false); + AnimatorSet set = marker.getAnimation(); + List animations = set.getChildAnimations(); + float x = (Float) ((ObjectAnimator) animations.get(0)).getAnimatedValue(); + float y = (Float) ((ObjectAnimator) animations.get(1)).getAnimatedValue(); + PointF pointF = new PointF(x + marker.getOffsetX(), y + marker.getOffsetY()); + marker.setPosition(mapboxMap.getProjection().fromScreenLocation(pointF)); + set.cancel(); + } - marker.setOffsetX(x); - marker.setOffsetY(y); + // update position on map + PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); + if (marker.getOffsetX() == -1) { + int x = (int) (marker.getAnchorU() * convertView.getMeasuredWidth()); + int y = (int) (marker.getAnchorV() * convertView.getMeasuredHeight()); + marker.setOffsetX(x); + marker.setOffsetY(y); + } - convertView.setX(point.x - x); - convertView.setY(point.y - y); + convertView.setX(point.x - marker.getOffsetX()); + convertView.setY(point.y - marker.getOffsetY()); - if (marker.isVisible() && convertView.getVisibility() == View.GONE) { - convertView.animate().cancel(); - convertView.setAlpha(0); - AnimatorUtils.alpha(convertView, 1); + // animate visibility + if (marker.isVisible() && convertView.getVisibility() == View.GONE) { + convertView.animate().cancel(); + convertView.setAlpha(0); + AnimatorUtils.alpha(convertView, 1); + } + } else { + if (timer == null) { + timer = new CountDownTimer(50, 560) { + @Override + public void onTick(long millisUntilFinished) { + + } + + @Override + public void onFinish() { + animate(marker, convertView); + } + }; + } else { + timer.cancel(); + PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); + convertView.setX(point.x - marker.getOffsetX()); + convertView.setY(point.y - marker.getOffsetY()); + } + timer.start(); } } } @@ -200,9 +242,10 @@ public class MarkerViewManager { *

* 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 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 adapter the adapter used to adapt the marker to the convertView */ public void select(@NonNull MarkerView marker, View convertView, MapboxMap.MarkerViewAdapter adapter) { if (convertView != null) { @@ -240,17 +283,23 @@ public class MarkerViewManager { * @param marker the MarkerView to remove */ public void removeMarkerView(MarkerView marker) { + boolean isAnimating = marker.isAnimating(); 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)) { - adapter.releaseView(viewHolder); + if (!isAnimating) { + if (adapter.prepareViewForReuse(marker, viewHolder)) { + adapter.releaseView(viewHolder); + } } } } } - markerViewMap.remove(marker); + + if (!isAnimating) { + markerViewMap.remove(marker); + } } /** @@ -324,7 +373,7 @@ public class MarkerViewManager { Iterator iterator = markerViewMap.keySet().iterator(); while (iterator.hasNext()) { MarkerView m = iterator.next(); - if (!markers.contains(m)) { + if (!m.shouldAnimate() && !markers.contains(m)) { // remove marker convertView = markerViewMap.get(m); for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { @@ -396,6 +445,50 @@ public class MarkerViewManager { } } + public void animatePosition(@NonNull MarkerView marker, long duration) { + marker.setDuration(duration); + marker.setStartTime(AnimationUtils.currentAnimationTimeMillis()); + marker.setShouldAnimate(true); + animate(marker, markerViewMap.get(marker)); + } + + private void animate(final MarkerView marker, @Nullable View convertView) { + if (convertView != null) { + marker.setAnimating(true); + PointF screenLocation = mapboxMap.getProjection().toScreenLocation(marker.getTargetPosition()); + PointF currentLocation = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); + convertView.setX(currentLocation.x - marker.getOffsetX()); + convertView.setY(currentLocation.y - marker.getOffsetY()); + ObjectAnimator animatorX = ObjectAnimator.ofFloat(convertView, "x", screenLocation.x - marker.getOffsetX()); + ObjectAnimator animatorY = ObjectAnimator.ofFloat(convertView, "y", screenLocation.y - marker.getOffsetY()); + AnimatorSet set = new AnimatorSet(); + set.playTogether(animatorX, animatorY); + marker.setAnimation(set); + set.setDuration(marker.getRemainingTime()); + set.addListener(new AnimatorListenerAdapter() { + + private boolean canceled; + + @Override + public void onAnimationCancel(Animator animation) { + super.onAnimationCancel(animation); + canceled = true; + } + + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + if (!canceled) { + marker.setShouldAnimate(false); + marker.setPosition(marker.getTargetPosition()); + } + } + }); + marker.setAnimation(set); + set.start(); + } + } + /** * Default MarkerViewAdapter used for base class of MarkerView to adapt a MarkerView to an ImageView */ 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 ae71ee384..8fe9568ea 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 @@ -1398,8 +1398,12 @@ public class MapView extends FrameLayout { mCompassView.update(getDirection()); mMyLocationView.update(); - mMapboxMap.getMarkerViewManager().update(); + try { + mMapboxMap.getMarkerViewManager().update(); + }catch (NullPointerException e){ + + } for (InfoWindow infoWindow : mMapboxMap.getInfoWindows()) { infoWindow.update(); } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java index 1e15c9ea3..bbd7428ea 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java @@ -1,18 +1,17 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation; import android.animation.TypeEvaluator; -import android.animation.ValueAnimator; import android.os.Bundle; +import android.os.Handler; import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.Menu; import android.view.MenuItem; -import android.view.animation.AccelerateDecelerateInterpolator; -import com.mapbox.mapboxsdk.annotations.Marker; -import com.mapbox.mapboxsdk.annotations.MarkerOptions; +import com.mapbox.mapboxsdk.annotations.MarkerView; +import com.mapbox.mapboxsdk.annotations.MarkerViewOptions; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; @@ -42,24 +41,18 @@ public class AnimatedMarkerActivity extends AppCompatActivity { mMapView.getMapAsync(new OnMapReadyCallback() { @Override public void onMapReady(@NonNull final MapboxMap mapboxMap) { - LatLng brussels = new LatLng(50.900446, 4.485251); - LatLng washington = new LatLng(38.897108, -77.036716); - final Marker marker = mapboxMap.addMarker(new MarkerOptions().position(brussels)); - ValueAnimator markerAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), (Object[]) new LatLng[]{brussels, washington}); - markerAnimator.setDuration(5000); - markerAnimator.setRepeatCount(ValueAnimator.INFINITE); - markerAnimator.setRepeatMode(ValueAnimator.REVERSE); - markerAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); - markerAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + LatLng brussels = new LatLng(50.900446, 4.485251); + final MarkerView marker = mapboxMap.addMarker(new MarkerViewOptions().position(brussels)); + + // FIXME workaround because view is not actually added at this time + final LatLng utrecht = new LatLng(52.086224, 5.122309); + new Handler().postDelayed(new Runnable() { @Override - public void onAnimationUpdate(ValueAnimator animation) { - if (marker != null) { - marker.setPosition((LatLng) animation.getAnimatedValue()); - } + public void run() { + marker.setPosition(utrecht, 6500l /*animation duration*/); } - }); - markerAnimator.start(); + }, 1000); } }); } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml index 8c025d999..b9bfa701a 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_animated_marker.xml @@ -1,8 +1,8 @@ + app:zoom="6" /> From cc1e2610c777a5b572f20de30e489f43521eea9f Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Wed, 15 Jun 2016 17:55:24 -0400 Subject: [PATCH 09/43] [android] Create Wrappers for Cordova Fixes #4761 --- .../mapboxsdk/annotations/BaseMarkerOptions.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) 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 fc2022f9e..3adeb52ea 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 @@ -39,6 +39,22 @@ public abstract class BaseMarkerOptions Date: Thu, 16 Jun 2016 14:30:34 +0200 Subject: [PATCH 10/43] [android] Dynamic update of InfowWindow with InfoWindowAdapter example Fixes #5353 --- .../mapboxsdk/annotations/InfoWindow.java | 11 +- .../mapbox/mapboxsdk/annotations/Marker.java | 5 + .../src/main/AndroidManifest.xml | 8 + .../DynamicInfoWindowAdapterActivity.java | 169 ++++++++++++++++++ .../activity_infowindow_adapter_dynamic.xml | 24 +++ .../src/main/res/values/strings.xml | 2 + 6 files changed, 218 insertions(+), 1 deletion(-) create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/infowindow/DynamicInfoWindowAdapterActivity.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_infowindow_adapter_dynamic.xml 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 aaa5525b4..9af459e8a 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 @@ -259,11 +259,20 @@ public class InfoWindow { View view = mView.get(); if (mapboxMap != null && marker != null && view != null) { mCoordinates = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); - view.setX(mCoordinates.x + mViewWidthOffset - mMarkerWidthOffset); + + if (view instanceof InfoWindowView) { + view.setX(mCoordinates.x + mViewWidthOffset - mMarkerWidthOffset); + } else { + view.setX(mCoordinates.x - (view.getMeasuredWidth() / 2) - mMarkerWidthOffset); + } view.setY(mCoordinates.y + mMarkerHeightOffset); } } + public View getView() { + return mView != null ? mView.get() : null; + } + boolean isVisible() { return mIsVisible; } 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 2d4ec4257..d24f020a1 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 @@ -117,6 +117,11 @@ public class Marker extends Annotation { refreshInfoWindowContent(); } + @Nullable + public InfoWindow getInfoWindow() { + return infoWindow; + } + /** * Update only for default Marker's InfoWindow content for Title and Snippet */ diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index 7268b7d55..c3bd231d3 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -41,6 +41,14 @@ android:name="@string/category" android:value="@string/category_infowindow" /> + + + + + + + + + + diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml index b856e7579..2ec1b0d25 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/values/strings.xml @@ -22,6 +22,7 @@ Standard InfoWindow example Custom InfoWindow Adapter + Custom Dynamic InfoWindow Adapter Animation Types @@ -80,6 +81,7 @@ 2 maps in a view hierarchy Restart map view after temporarily leaving to another activity Use an Android SDK View as marker + Learn how to create a dynamic custom InfoWindow Concurrent Open InfoWindows Deselect Markers On Tap From a5476346bf8dd696c6b7108d61dcc4928f8304e7 Mon Sep 17 00:00:00 2001 From: Justas Medeisis Date: Mon, 13 Jun 2016 16:52:47 +0300 Subject: [PATCH 11/43] [android] Fix crash when MyBearingTracking mode is not NONE. Fixes #5331 --- .../java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java index a1515b39c..12240aee8 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java @@ -260,7 +260,7 @@ public class MyLocationView extends View { camera.getMatrix(matrix); // - if (myBearingTrackingMode != MyBearingTracking.NONE) { + if (myBearingTrackingMode != MyBearingTracking.NONE && directionAnimator != null) { matrix.postRotate((Float) directionAnimator.getAnimatedValue()); } From 2893f39249650bac8c5c4c4edf6600018e811642 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Minh=20Nguy=E1=BB=85n?= Date: Mon, 13 Jun 2016 14:47:13 -0700 Subject: [PATCH 12/43] [android] Rename OS X SDK to macOS SDK in Android 4.1 release branch Fixes #5382 Also renamed as many references to OS X as possible to macOS in documentation. --- .gitignore | 1 + .ycm_extra_conf.py | 4 +- ARCHITECTURE.md | 87 ++++++++++++++++++ CHANGELOG.md | 2 +- CONTRIBUTING.md | 4 +- INSTALL.md | 4 +- Makefile | 74 ++++++++------- README.md | 8 +- bin/offline.sh | 2 +- configure | 4 + deps/ninja/{ninja-osx => ninja-macos} | Bin ...TRIBUTING_OSX.md => CONTRIBUTING_MACOS.md} | 2 +- platform/android/README.md | 2 +- platform/darwin/README.md | 6 +- platform/darwin/src/http_file_source.mm | 4 +- platform/ios/DEVELOPING.md | 10 +- platform/{osx => macos}/CHANGELOG.md | 3 +- platform/{osx => macos}/DEVELOPING.md | 24 ++--- platform/{osx => macos}/INSTALL.md | 14 +-- platform/{osx => macos}/README.md | 10 +- .../WorkspaceSettings.xcsettings | 0 platform/{osx => macos}/app/AppDelegate.h | 0 platform/{osx => macos}/app/AppDelegate.m | 0 .../AppIcon.appiconset/AppIcon128x128.png | Bin .../AppIcon.appiconset/AppIcon16x16.png | Bin .../AppIcon.appiconset/AppIcon256x256-1.png | Bin .../AppIcon.appiconset/AppIcon256x256.png | Bin .../AppIcon.appiconset/AppIcon32x32-1.png | Bin .../AppIcon.appiconset/AppIcon32x32.png | Bin .../AppIcon.appiconset/AppIcon512x512-1.png | Bin .../AppIcon.appiconset/AppIcon512x512.png | Bin .../AppIcon.appiconset/Contents.json | 0 .../AppIcon.appiconset/icon-1.png | Bin .../AppIcon.appiconset/icon.png | Bin .../app/Assets.xcassets/Contents.json | 0 .../app/Base.lproj/MainMenu.xib | 0 .../app/Base.lproj/MapDocument.xib | 0 platform/{osx => macos}/app/Credits.rtf | 0 .../{osx => macos}/app/DroppedPinAnnotation.h | 0 .../{osx => macos}/app/DroppedPinAnnotation.m | 0 platform/{osx => macos}/app/Info.plist | 0 .../app/LocationCoordinate2DTransformer.h | 0 .../app/LocationCoordinate2DTransformer.m | 0 platform/{osx => macos}/app/MapDocument.h | 0 platform/{osx => macos}/app/MapDocument.m | 0 .../app/OfflinePackNameValueTransformer.h | 0 .../app/OfflinePackNameValueTransformer.m | 0 .../app/TimeIntervalTransformer.h | 0 .../app/TimeIntervalTransformer.m | 0 platform/{osx => macos}/app/main.m | 0 platform/{osx => macos}/bitrise.yml | 8 +- platform/macos/docs/doc-README.md | 9 ++ platform/{osx => macos}/docs/pod-README.md | 12 +-- platform/{osx => macos}/jazzy.yml | 0 .../macos.xcodeproj}/project.pbxproj | 28 +++--- .../contents.xcworkspacedata | 2 +- .../xcshareddata/xcschemes/CI.xcscheme | 22 ++--- .../xcshareddata/xcschemes/dynamic.xcscheme | 12 +-- .../xcshareddata/xcschemes/macosapp.xcscheme} | 18 ++-- .../contents.xcworkspacedata | 4 +- .../xcdebugger/Breakpoints_v2.xcbkptlist | 0 .../xcschemes/mbgl-offline.xcscheme | 8 +- .../xcschemes/mbgl-render.xcscheme | 8 +- .../xcshareddata/xcschemes/test.xcscheme | 8 +- platform/{osx => macos}/platform.gyp | 4 +- platform/{osx => macos}/screenshot.png | Bin platform/{osx => macos}/scripts/configure.sh | 0 platform/{osx => macos}/scripts/document.sh | 16 ++-- .../scripts/macostest.xcscheme} | 6 +- platform/{osx => macos}/scripts/package.sh | 12 +-- .../sdk/Base.lproj/Localizable.strings | 0 .../sdk/Base.lproj/MGLAnnotationCallout.xib | 0 platform/{osx => macos}/sdk/Info.plist | 0 .../{osx => macos}/sdk/default_marker.pdf | Bin platform/{osx => macos}/sdk/mapbox.pdf | Bin .../{osx => macos}/src/MGLAnnotationImage.h | 0 .../{osx => macos}/src/MGLAnnotationImage.m | 0 .../src/MGLAnnotationImage_Private.h | 0 .../{osx => macos}/src/MGLAttributionButton.h | 0 .../{osx => macos}/src/MGLAttributionButton.m | 0 platform/{osx => macos}/src/MGLCompassCell.h | 0 platform/{osx => macos}/src/MGLCompassCell.m | 0 .../src/MGLMapView+IBAdditions.h | 0 .../src/MGLMapView+IBAdditions.m | 0 platform/{osx => macos}/src/MGLMapView.h | 0 platform/{osx => macos}/src/MGLMapView.mm | 6 +- .../{osx => macos}/src/MGLMapViewDelegate.h | 0 .../{osx => macos}/src/MGLMapView_Private.h | 0 platform/{osx => macos}/src/MGLOpenGLLayer.h | 0 platform/{osx => macos}/src/MGLOpenGLLayer.mm | 0 platform/{osx => macos}/src/Mapbox.h | 0 platform/{osx => macos}/test/Info.plist | 0 platform/node/README.md | 4 +- platform/node/bitrise.yml | 4 +- platform/osx/docs/doc-README.md | 9 -- platform/qt/README.md | 6 +- platform/qt/bitrise-qt4.yml | 4 +- platform/qt/bitrise-qt5.yml | 4 +- scripts/collect-coverage.sh | 2 +- 99 files changed, 293 insertions(+), 188 deletions(-) create mode 100644 ARCHITECTURE.md rename deps/ninja/{ninja-osx => ninja-macos} (100%) rename platform/android/{CONTRIBUTING_OSX.md => CONTRIBUTING_MACOS.md} (98%) rename platform/{osx => macos}/CHANGELOG.md (91%) rename platform/{osx => macos}/DEVELOPING.md (70%) rename platform/{osx => macos}/INSTALL.md (72%) rename platform/{osx => macos}/README.md (55%) rename platform/{osx => macos}/WorkspaceSettings.xcsettings (100%) rename platform/{osx => macos}/app/AppDelegate.h (100%) rename platform/{osx => macos}/app/AppDelegate.m (100%) rename platform/{osx => macos}/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.png (100%) rename platform/{osx => macos}/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.png (100%) rename platform/{osx => macos}/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256-1.png (100%) rename platform/{osx => macos}/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.png (100%) rename platform/{osx => macos}/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32-1.png (100%) rename platform/{osx => macos}/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.png (100%) rename platform/{osx => macos}/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512-1.png (100%) rename platform/{osx => macos}/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.png (100%) rename platform/{osx => macos}/app/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename platform/{osx => macos}/app/Assets.xcassets/AppIcon.appiconset/icon-1.png (100%) rename platform/{osx => macos}/app/Assets.xcassets/AppIcon.appiconset/icon.png (100%) rename platform/{osx => macos}/app/Assets.xcassets/Contents.json (100%) rename platform/{osx => macos}/app/Base.lproj/MainMenu.xib (100%) rename platform/{osx => macos}/app/Base.lproj/MapDocument.xib (100%) rename platform/{osx => macos}/app/Credits.rtf (100%) rename platform/{osx => macos}/app/DroppedPinAnnotation.h (100%) rename platform/{osx => macos}/app/DroppedPinAnnotation.m (100%) rename platform/{osx => macos}/app/Info.plist (100%) rename platform/{osx => macos}/app/LocationCoordinate2DTransformer.h (100%) rename platform/{osx => macos}/app/LocationCoordinate2DTransformer.m (100%) rename platform/{osx => macos}/app/MapDocument.h (100%) rename platform/{osx => macos}/app/MapDocument.m (100%) rename platform/{osx => macos}/app/OfflinePackNameValueTransformer.h (100%) rename platform/{osx => macos}/app/OfflinePackNameValueTransformer.m (100%) rename platform/{osx => macos}/app/TimeIntervalTransformer.h (100%) rename platform/{osx => macos}/app/TimeIntervalTransformer.m (100%) rename platform/{osx => macos}/app/main.m (100%) rename platform/{osx => macos}/bitrise.yml (93%) create mode 100644 platform/macos/docs/doc-README.md rename platform/{osx => macos}/docs/pod-README.md (59%) rename platform/{osx => macos}/jazzy.yml (100%) rename platform/{osx/osx.xcodeproj => macos/macos.xcodeproj}/project.pbxproj (98%) rename platform/{osx/osx.xcodeproj => macos/macos.xcodeproj}/project.xcworkspace/contents.xcworkspacedata (87%) rename platform/{osx/osx.xcodeproj => macos/macos.xcodeproj}/xcshareddata/xcschemes/CI.xcscheme (86%) rename platform/{osx/osx.xcodeproj => macos/macos.xcodeproj}/xcshareddata/xcschemes/dynamic.xcscheme (90%) rename platform/{osx/osx.xcodeproj/xcshareddata/xcschemes/osxapp.xcscheme => macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme} (87%) rename platform/{osx/osx.xcworkspace => macos/macos.xcworkspace}/contents.xcworkspacedata (52%) rename platform/{osx/osx.xcworkspace => macos/macos.xcworkspace}/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist (100%) rename platform/{osx/osx.xcworkspace => macos/macos.xcworkspace}/xcshareddata/xcschemes/mbgl-offline.xcscheme (88%) rename platform/{osx/osx.xcworkspace => macos/macos.xcworkspace}/xcshareddata/xcschemes/mbgl-render.xcscheme (88%) rename platform/{osx/osx.xcworkspace => macos/macos.xcworkspace}/xcshareddata/xcschemes/test.xcscheme (88%) rename platform/{osx => macos}/platform.gyp (96%) rename platform/{osx => macos}/screenshot.png (100%) rename platform/{osx => macos}/scripts/configure.sh (100%) rename platform/{osx => macos}/scripts/document.sh (67%) rename platform/{osx/scripts/osxtest.xcscheme => macos/scripts/macostest.xcscheme} (89%) rename platform/{osx => macos}/scripts/package.sh (82%) rename platform/{osx => macos}/sdk/Base.lproj/Localizable.strings (100%) rename platform/{osx => macos}/sdk/Base.lproj/MGLAnnotationCallout.xib (100%) rename platform/{osx => macos}/sdk/Info.plist (100%) rename platform/{osx => macos}/sdk/default_marker.pdf (100%) rename platform/{osx => macos}/sdk/mapbox.pdf (100%) rename platform/{osx => macos}/src/MGLAnnotationImage.h (100%) rename platform/{osx => macos}/src/MGLAnnotationImage.m (100%) rename platform/{osx => macos}/src/MGLAnnotationImage_Private.h (100%) rename platform/{osx => macos}/src/MGLAttributionButton.h (100%) rename platform/{osx => macos}/src/MGLAttributionButton.m (100%) rename platform/{osx => macos}/src/MGLCompassCell.h (100%) rename platform/{osx => macos}/src/MGLCompassCell.m (100%) rename platform/{osx => macos}/src/MGLMapView+IBAdditions.h (100%) rename platform/{osx => macos}/src/MGLMapView+IBAdditions.m (100%) rename platform/{osx => macos}/src/MGLMapView.h (100%) rename platform/{osx => macos}/src/MGLMapView.mm (99%) rename platform/{osx => macos}/src/MGLMapViewDelegate.h (100%) rename platform/{osx => macos}/src/MGLMapView_Private.h (100%) rename platform/{osx => macos}/src/MGLOpenGLLayer.h (100%) rename platform/{osx => macos}/src/MGLOpenGLLayer.mm (100%) rename platform/{osx => macos}/src/Mapbox.h (100%) rename platform/{osx => macos}/test/Info.plist (100%) delete mode 100644 platform/osx/docs/doc-README.md diff --git a/.gitignore b/.gitignore index d887dd3f9..16fd24510 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,4 @@ xcuserdata /platform/ios/benchmark/assets/glyphs/DIN* /platform/ios/benchmark/assets/tiles/mapbox.mapbox-terrain-v2,mapbox.mapbox-streets-v6 **/token +/platform/macos/macos.xcworkspace/xcshareddata/macos.xcscmblueprint diff --git a/.ycm_extra_conf.py b/.ycm_extra_conf.py index 632686f3d..d2008c9dd 100644 --- a/.ycm_extra_conf.py +++ b/.ycm_extra_conf.py @@ -36,8 +36,8 @@ import subprocess import ycm_core compilation_database_folders = [ - 'build/linux-x86_64/Release', - 'build/osx/Release', + 'build/linux-x86_64/Debug', + 'build/macos/Debug', ] subprocess.call(['make compdb'], shell=True) diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 000000000..590ea9772 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,87 @@ +This document aims to outline at a high level the various parts that make up mapbox-gl-native and how they work together. + +# Repository structure + +mapbox-gl-native uses a monolithic that houses both core C++ code and code that wraps the C++ core with SDKs for Android, iOS, macOS, Node.js, and Qt. A "monorepo" allows us to: + + * Make changes to the core API and SDKs simultaneously, ensuring no platform falls behind. + * Ensure that core changes do not inadvertently break SDK tests. + * Centralize discussions about features and defects that affect multiple platforms. + +In the repository, core C++ code is contained in the `include` and `src` directories. The former includes headers that are considered to make up the "public" core C++ API, while the latter includes `.cpp` implementation files and headers that are private to the implementation. Within both directories, files are nested under an `mbgl` directory, which has various subdirectories based on areas of functionality. Both public and private headers therefore can (and should) always be included with the form `#include `. + +Code and build scripts belonging to platform SDKs are contained in the `platform` directory, which has subdirectories for each platform. The `platform/darwin` and `platform/default` directories contain code shared by multiple platform SDKs. + +# Build system + +The mapbox-gl-native build system uses a variety of tools. + +## Make + +GNU Make and a master `Makefile` serves as the coordinating tool for all other build system tools. Most of your interaction with the build system will be via `make` commands. We aim to have a consistent pattern for make targets across platforms: for a given platform, e.g. `ios`, `make ios` builds a reasonable set of end products (though perhaps not all permutations of build options, which can be prohibitively expensive), and `make test-ios` runs a complete test suite for the platform. + +## Git submodules + +Git submodules are used to pull in several dependencies: mason (see below) and several iOS dependencies (though we have plans to phase these out). Initializing these submodules is handled automatically by the necessary `make` targets. + +## npm + +npm is a package manager for Node.js. mapbox-gl-native uses it to pull in several development dependencies that happen to be packaged as node modules -- mainly for testing needs. + +## Mason + +[Mason](https://github.com/mapbox/mason) is Mapbox's own cross platform C/C++ package manager. mapbox-gl-native uses mason packages as a source of precompiled binaries for third-party dependencies such as Boost, RapidJSON, and SQLite, and Mapbox's own C++ modules such as [earcut.hpp](https://github.com/mapbox/earcut.hpp) and [geojson-vt-cpp](https://github.com/mapbox/geojson-vt-cpp). It is also used to obtain a toolchain for Android platform cross-compiliation. + +We track mason dependencies for a given platform in the file `platform//scripts/configure.sh`. The `configure` script at the root handles sourcing this file during the build, running the appropriate mason commands, and writing configuration settings for the subsequent build to a `config.gypi` in the build output directory. + +## gyp + +[gyp](https://gyp.gsrc.io/) is a build system originally created for Chromium and since adopted by Node.js. In mapbox-gl-native it's used to build the core C++ static library, the Node.js platform module, and the shared JNI module for Android. + +## Platform-specific subsystems + +Outside of the core C++ static library, platform SDKs typically rely on platform-native build tooling to complete the job. + +* For iOS and macOS this means Xcode and the xcodebuild command line tool. +* For Android, Gradle and Android Studio. +* For Qt, `qmake`. + +See the relevant platform-specific `README.md` / `INSTALL.md` for details. + +# Major functional components + +## Map +## Style + +The "Style" component of mapbox-gl-native contains an implementation of the [Mapbox Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), defining what data to draw, the order to draw it in, and how to style the data when drawing it. + +In addition to supporting styles loaded from a URL, mapbox-gl-native includes a runtime styling API, which allows users to dynamically modify the current style: add and remove layers, modify layer properties, and so on. As appropriate for a C++ API, the runtime styling API API is _strongly typed_: there are subclasses for each layer type, with correctly-typed accessors for each style property. This results in a large API surface area. Fortunately, this is automated, by generating the API – and the regular portion of the implementation – from the style specification. + +The layers API makes a distinction between public API and internal implementation using [the `Impl` idiom](https://github.com/mapbox/mapbox-gl-native/issues/3254) seen elsewhere in the codebase. Here, it takes the form of two parallel class hierarchies: + +* `Layer` and its subclasses form the public API. +* `Layer::Impl` and its subclasses form the internal API. + +As well as forming the boundary between public and internal, these two class hierarchies form the boundary between generated code and handwritten code. Except for `CustomLayer` and `CustomLayer::Impl`: + +* `Layer` subclasses are entirely generated. (`Layer` itself is handwritten.) +* `Layer::Impl` and its subclasses are entirely handwritten. + +## FileSource +## Layout +## Rendering +## Annotations + +# Threading + +At runtime, mapbox-gl-native uses the following threads: + +* The "main thread" (or other thread on which a `Map` object is created) handles direct `Map` API requests, owns the active `Style` and its associated objects, and renders the map. Since this thread is usually dispatching events triggered by user input, it's important that these duties not require significant computation or perform blocking I/O that would cause UI jank or hangs. +* Many of the tasks that require significant computation are associated with layout and styling of map features: parsing vector tiles, computing text layout, and generating data buffers to be consumed by OpenGL. This work happens on "worker threads" that are spawned by the main thread, four per `Style` object. The `Style` and its associated objects handle dispatching tasks to the workers, typically on a tile-by-tile basis. +* A "FileSource" thread handles network requests for styles, tiles, and other resources, and I/O on the SQLite database used for offline maps and caching. Requests originate from the main thread, are dispatched by a FileSource internally to its thread, and results are returned to the main thread via an asynchronous callback function. (This is implemented with platform-specific hooks into the native message pump for the requesting thread.) + +To minimize data races and invalid memory access, we aim for zero shared memory state between any two threads. Cross-thread communication occurs via one thread requesting the "invocation" of a task on another thread. The parameters for this task should be passed as value objects, so that they are copied, or as ownership-transferring values such as `std::unique_ptr`. (We're [not entirely there yet](https://github.com/mapbox/mapbox-gl-native/issues/667), but that's the goal.) The result (if any) is likewise passed as a value or ownership-transferring parameter to the callback function. + +Invoking a task on another thread itself creates an ownership obligation: the responsibility for the work happening on the other thread. This ownership is represented by the invocation method returning `std::unique_ptr`. Destroying this object indicates that the result of the task is no longer required: the callback is guaranteed not to be called, and the work on the other thread may be aborted (if doing so is convenient). + +All this is implemented by [Thread](https://github.com/mapbox/mapbox-gl-native/blob/master/src/mbgl/util/thread.hpp) and [RunLoop](https://github.com/mapbox/mapbox-gl-native/blob/master/include/mbgl/util/run_loop.hpp). diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ad2d51ad..5034146ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,5 +4,5 @@ Each Mapbox GL Native SDK has a separate changelog that highlights changes relev * [Mapbox Android SDK](platform/android/CHANGELOG.md) * [Mapbox iOS SDK](platform/ios/CHANGELOG.md) -* [Mapbox OS X SDK](platform/osx/CHANGELOG.md) +* [Mapbox macOS SDK](platform/macos/CHANGELOG.md) * [node-mapbox-gl-native](platform/node/CHANGELOG.md) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0df51bd17..3bb618689 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -11,10 +11,10 @@ If you want to contribute code: 1. Pull requests are gladly accepted. If there are any changes that developers using one of the GL SDKs should be aware of, please update the **master** section of the relevant changelog(s): * [Mapbox Android SDK](platform/android/CHANGELOG.md) * [Mapbox iOS SDK](platform/ios/CHANGELOG.md) - * [Mapbox OS X SDK](platform/osx/CHANGELOG.md) + * [Mapbox macOS SDK](platform/macos/CHANGELOG.md) * [node-mapbox-gl-native](platform/node/CHANGELOG.md) -1. Prefix your commit messages with the platform(s) your changes affect: `[core]`, `[android]`, `[ios]`, `[osx]`, `[node]`, or `[qt]`. +1. Prefix your commit messages with the platform(s) your changes affect: `[core]`, `[android]`, `[ios]`, `[macos]`, `[node]`, or `[qt]`. # Code of conduct Everyone is invited to participate in Mapbox’s open source projects and public discussions: we want to create a welcoming and friendly environment. Harassment of participants or other unethical and unprofessional behavior will not be tolerated in our spaces. The [Contributor Covenant](http://contributor-covenant.org) applies to all projects under the Mapbox organization and we ask that you please read [the full text](http://contributor-covenant.org/version/1/2/0/). diff --git a/INSTALL.md b/INSTALL.md index d0f063840..d002e8df7 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -37,7 +37,7 @@ dependencies: - [`libcurl`](http://curl.haxx.se/libcurl/) (depends on OpenSSL) -### Additional Dependencies for OS X +### Additional Dependencies for macOS - Apple Command Line Tools (available at [Apple Developer](https://developer.apple.com/downloads)) - [Homebrew](http://brew.sh) @@ -50,7 +50,7 @@ See the relevant SDK documentation for next steps: * [Mapbox Android SDK](platform/android/) * [Mapbox iOS SDK](platform/ios/) -* [Mapbox OS X SDK](platform/osx/) +* [Mapbox macOS SDK](platform/macos/) * [Mapbox Qt SDK](platform/qt/) * [Mapbox GL Native on Linux](platform/linux/) * [node-mapbox-gl-native](platform/node/) diff --git a/Makefile b/Makefile index 26e9b58ec..9abce1a37 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ export BUILDTYPE ?= Debug ifeq ($(shell uname -s), Darwin) - HOST_PLATFORM = osx + HOST_PLATFORM = macos export JOBS ?= $(shell sysctl -n hw.ncpu) else ifeq ($(shell uname -s), Linux) HOST_PLATFORM = linux @@ -36,54 +36,54 @@ CONFIG_DEPENDENCIES = .mason configure # files are added or removed. GYP_DEPENDENCIES = mbgl.gypi test/test.gypi bin/*.gypi $(shell find src include -type d) node_modules -#### OS X targets ############################################################## +#### macOS targets ############################################################## -OSX_OUTPUT_PATH = build/osx -OSX_PROJ_PATH = $(OSX_OUTPUT_PATH)/platform/osx/platform.xcodeproj -OSX_WORK_PATH = platform/osx/osx.xcworkspace -OSX_USER_DATA_PATH = $(OSX_WORK_PATH)/xcuserdata/$(USER).xcuserdatad +MACOS_OUTPUT_PATH = build/macos +MACOS_PROJ_PATH = $(MACOS_OUTPUT_PATH)/platform/macos/platform.xcodeproj +MACOS_WORK_PATH = platform/macos/macos.xcworkspace +MACOS_USER_DATA_PATH = $(MACOS_WORK_PATH)/xcuserdata/$(USER).xcuserdatad -$(OSX_OUTPUT_PATH)/config.gypi: platform/osx/scripts/configure.sh $(CONFIG_DEPENDENCIES) - ./configure $< $@ osx +$(MACOS_OUTPUT_PATH)/config.gypi: platform/macos/scripts/configure.sh $(CONFIG_DEPENDENCIES) + ./configure $< $@ macos -$(OSX_OUTPUT_PATH)/mbgl.xcconfig: $(OSX_OUTPUT_PATH)/config.gypi +$(MACOS_OUTPUT_PATH)/mbgl.xcconfig: $(MACOS_OUTPUT_PATH)/config.gypi ./scripts/export-xcconfig.py $< $@ -$(OSX_PROJ_PATH): platform/osx/platform.gyp $(OSX_OUTPUT_PATH)/config.gypi $(OSX_OUTPUT_PATH)/mbgl.xcconfig $(GYP_DEPENDENCIES) - $(GYP) -f xcode --generator-output=$(OSX_OUTPUT_PATH) $< +$(MACOS_PROJ_PATH): platform/macos/platform.gyp $(MACOS_OUTPUT_PATH)/config.gypi $(MACOS_OUTPUT_PATH)/mbgl.xcconfig $(GYP_DEPENDENCIES) + $(GYP) -f xcode --generator-output=$(MACOS_OUTPUT_PATH) $< -osx: $(OSX_PROJ_PATH) +macos: $(MACOS_PROJ_PATH) set -o pipefail && xcodebuild \ - -derivedDataPath $(OSX_OUTPUT_PATH) \ + -derivedDataPath $(MACOS_OUTPUT_PATH) \ -configuration $(BUILDTYPE) \ - -workspace $(OSX_WORK_PATH) -scheme CI build $(XCPRETTY) + -workspace $(MACOS_WORK_PATH) -scheme CI build $(XCPRETTY) -xproj: $(OSX_PROJ_PATH) $(OSX_WORK_PATH) - mkdir -p "$(OSX_USER_DATA_PATH)" - cp platform/osx/WorkspaceSettings.xcsettings "$(OSX_USER_DATA_PATH)/WorkspaceSettings.xcsettings" - open $(OSX_WORK_PATH) +xproj: $(MACOS_PROJ_PATH) $(MACOS_WORK_PATH) + mkdir -p "$(MACOS_USER_DATA_PATH)" + cp platform/macos/WorkspaceSettings.xcsettings "$(MACOS_USER_DATA_PATH)/WorkspaceSettings.xcsettings" + open $(MACOS_WORK_PATH) -test-osx: osx node_modules - ulimit -c unlimited && ($(OSX_OUTPUT_PATH)/Build/Products/$(BUILDTYPE)/test & pid=$$! && wait $$pid \ +test-macos: macos node_modules + ulimit -c unlimited && ($(MACOS_OUTPUT_PATH)/Build/Products/$(BUILDTYPE)/test & pid=$$! && wait $$pid \ || (lldb -c /cores/core.$$pid --batch --one-line 'thread backtrace all' --one-line 'quit' && exit 1)) set -o pipefail && xcodebuild \ - -derivedDataPath $(OSX_OUTPUT_PATH) \ + -derivedDataPath $(MACOS_OUTPUT_PATH) \ -configuration $(BUILDTYPE) \ - -workspace $(OSX_WORK_PATH) -scheme CI test $(XCPRETTY) + -workspace $(MACOS_WORK_PATH) -scheme CI test $(XCPRETTY) -xpackage: $(OSX_PROJ_PATH) - SYMBOLS=$(SYMBOLS) ./platform/osx/scripts/package.sh +xpackage: $(MACOS_PROJ_PATH) + SYMBOLS=$(SYMBOLS) ./platform/macos/scripts/package.sh xdocument: - OUTPUT=$(OUTPUT) ./platform/osx/scripts/document.sh + OUTPUT=$(OUTPUT) ./platform/macos/scripts/document.sh genstrings: - genstrings -u -o platform/osx/sdk/Base.lproj platform/darwin/src/*.{m,mm} - genstrings -u -o platform/osx/sdk/Base.lproj platform/osx/src/*.{m,mm} + genstrings -u -o platform/macos/sdk/Base.lproj platform/darwin/src/*.{m,mm} + genstrings -u -o platform/macos/sdk/Base.lproj platform/macos/src/*.{m,mm} genstrings -u -o platform/ios/resources/Base.lproj platform/ios/src/*.{m,mm} - -find platform/ios/resources platform/osx/sdk -path '*/Base.lproj/*.strings' -exec \ + -find platform/ios/resources platform/macos/sdk -path '*/Base.lproj/*.strings' -exec \ textutil -convert txt -extension strings -inputencoding UTF-16 -encoding UTF-8 {} \; - mv platform/osx/sdk/Base.lproj/Foundation.strings platform/darwin/resources/Base.lproj/ + mv platform/macos/sdk/Base.lproj/Foundation.strings platform/darwin/resources/Base.lproj/ #### iOS targets ############################################################## @@ -288,10 +288,22 @@ compdb: platform/linux/platform.gyp $(LINUX_OUTPUT_PATH)/config.gypi deps/ninja/ninja-linux -C $(LINUX_OUTPUT_PATH)/$(BUILDTYPE) \ -t compdb cc cc_s cxx objc objcxx > $(LINUX_OUTPUT_PATH)/$(BUILDTYPE)/compile_commands.json -tidy: compdb - deps/ninja/ninja-linux -C $(LINUX_OUTPUT_PATH)/$(BUILDTYPE) version shaders +compdb-macos: platform/macos/platform.gyp $(MACOS_OUTPUT_PATH)/config.gypi + $(GYP) -f ninja -I $(MACOS_OUTPUT_PATH)/config.gypi \ + --generator-output=$(MACOS_OUTPUT_PATH) $< + deps/ninja/ninja-macos -C $(MACOS_OUTPUT_PATH)/$(BUILDTYPE) \ + -t compdb cc cc_s cxx objc objcxx > $(MACOS_OUTPUT_PATH)/$(BUILDTYPE)/compile_commands.json + +tidy: compdb tidy-$(HOST_PLATFORM) + +tidy-linux: + deps/ninja/ninja-linux -C $(LINUX_OUTPUT_PATH)/$(BUILDTYPE) headers scripts/clang-tidy.sh $(LINUX_OUTPUT_PATH)/$(BUILDTYPE) +tidy-macos: + deps/ninja/ninja-macos -C $(MACOS_OUTPUT_PATH)/$(BUILDTYPE) headers + scripts/clang-tidy.sh $(MACOS_OUTPUT_PATH)/$(BUILDTYPE) + #### Miscellaneous targets ##################################################### clean: diff --git a/README.md b/README.md index 27802976e..3808f31de 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,16 @@ A library for embedding interactive, customizable vector maps into native applic ## The Mapbox GL ecosystem -This repository hosts the cross-platform Mapbox GL Native library, plus convenient SDKs for several platforms. The cross-platform library comes with a [GLFW](https://github.com/glfw/glfw)-based demo application for Ubuntu Linux and OS X. The SDKs target the usual languages on their respective platforms: +This repository hosts the cross-platform Mapbox GL Native library, plus convenient SDKs for several platforms. The cross-platform library comes with a [GLFW](https://github.com/glfw/glfw)-based demo application for Ubuntu Linux and macOS. The SDKs target the usual languages on their respective platforms: SDK | Languages | Build status ----|-----------|------------- [Mapbox GL Native](INSTALL.md) | C++14 | [![Travis](https://travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds) [![Coverage Status](https://coveralls.io/repos/github/mapbox/mapbox-gl-native/badge.svg?branch=master)](https://coveralls.io/github/mapbox/mapbox-gl-native?branch=master) [Mapbox Android SDK](platform/android/) | Java | [![Bitrise](https://www.bitrise.io/app/79cdcbdc42de4303.svg?token=_InPF8bII6W7J6kFr-L8QQ&branch=master)](https://www.bitrise.io/app/79cdcbdc42de4303) [Mapbox iOS SDK](platform/ios/) | Objective-C or Swift | [![Bitrise](https://www.bitrise.io/app/7514e4cf3da2cc57.svg?token=OwqZE5rSBR9MVWNr_lf4sA&branch=master)](https://www.bitrise.io/app/7514e4cf3da2cc57) -[Mapbox OS X SDK](platform/osx/) | Objective-C or Swift | [![Bitrise](https://www.bitrise.io/app/155ef7da24b38dcd.svg?token=4KSOw_gd6WxTnvGE2rMttg&branch=master)](https://www.bitrise.io/app/155ef7da24b38dcd) -[node-mapbox-gl-native](platform/node/) | Node.js | [![Linux](https://travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds) / [![OS X](https://www.bitrise.io/app/55e3a9bf71202106.svg?token=5qf5ZUcKVN3LDnHhW7rO0w)](https://www.bitrise.io/app/55e3a9bf71202106) -[Mapbox Qt SDK](platform/qt) | C++03 | [![Travis](https://travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds) +[Mapbox macOS SDK](platform/macos/) | Objective-C or Swift | [![Bitrise](https://www.bitrise.io/app/155ef7da24b38dcd.svg?token=4KSOw_gd6WxTnvGE2rMttg&branch=master)](https://www.bitrise.io/app/155ef7da24b38dcd) +[node-mapbox-gl-native](platform/node/) | Node.js | [![Linux](https://travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds) [![macOS](https://www.bitrise.io/app/55e3a9bf71202106.svg?token=5qf5ZUcKVN3LDnHhW7rO0w)](https://www.bitrise.io/app/55e3a9bf71202106) +[Mapbox Qt SDK](platform/qt) | C++03 | [![Travis](https://travis-ci.org/mapbox/mapbox-gl-native.svg?branch=master)](https://travis-ci.org/mapbox/mapbox-gl-native/builds) [![Bitrise](https://www.bitrise.io/app/96cfbc97e0245c22.svg?token=GxsqIOGPXhn0F23sSVSsYA&branch=master)](https://www.bitrise.io/app/96cfbc97e0245c22) Additional Mapbox GL Native–based libraries are developed outside of this repository: diff --git a/bin/offline.sh b/bin/offline.sh index f85cb1194..99ce2185e 100755 --- a/bin/offline.sh +++ b/bin/offline.sh @@ -3,7 +3,7 @@ set -e set -o pipefail -OFFLINE=./build/osx/Release/mbgl-offline +OFFLINE=./build/macos/Release/mbgl-offline # Barcelona $OFFLINE --north 41.4664 --west 2.0407 --south 41.2724 --east 2.2680 --output barcelona.db diff --git a/configure b/configure index 1d58a8244..26052aa4f 100755 --- a/configure +++ b/configure @@ -7,6 +7,10 @@ OUTPUT_FILE=$2 export MASON_PLATFORM=$3 export MASON_PLATFORM_VERSION=${4:-} +if [ "${MASON_PLATFORM}" = "macos" ]; then + export MASON_PLATFORM=osx +fi + if [ -z ${INPUT_FILE} ]; then abort 'You need to specify an input path for the configure.sh file' fi diff --git a/deps/ninja/ninja-osx b/deps/ninja/ninja-macos similarity index 100% rename from deps/ninja/ninja-osx rename to deps/ninja/ninja-macos diff --git a/platform/android/CONTRIBUTING_OSX.md b/platform/android/CONTRIBUTING_MACOS.md similarity index 98% rename from platform/android/CONTRIBUTING_OSX.md rename to platform/android/CONTRIBUTING_MACOS.md index 3154ac108..447e989d6 100644 --- a/platform/android/CONTRIBUTING_OSX.md +++ b/platform/android/CONTRIBUTING_MACOS.md @@ -1,4 +1,4 @@ -# Contributing to the Android SDK on OS X +# Contributing to the Android SDK on macOS Install Oracle JDK 7+ and Android Studio: diff --git a/platform/android/README.md b/platform/android/README.md index 895cf8468..3f5837009 100644 --- a/platform/android/README.md +++ b/platform/android/README.md @@ -15,7 +15,7 @@ A library based on [Mapbox GL Native](../../README.md) for embedding interactive Building the SDK yourself requires [a number of dependencies and steps](../../INSTALL.md) that are unnecessary for developing production applications. * [Contributing on Linux](CONTRIBUTING_LINUX.md) -* [Contributing on OS X](CONTRIBUTING_OSX.md) +* [Contributing on macOS](CONTRIBUTING_MACOS.md) ### Setting up the Android emulator diff --git a/platform/darwin/README.md b/platform/darwin/README.md index 43e229028..349c9a00c 100644 --- a/platform/darwin/README.md +++ b/platform/darwin/README.md @@ -1,10 +1,10 @@ # Darwin The code in the Darwin platform targets Apple platforms but is not specific -to iOS or OS X. This code is not distributed as an SDK in itself, but is required +to iOS or macOS. This code is not distributed as an SDK in itself, but is required by the [Mapbox iOS SDK](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/ios) -and [Mapbox OS X SDK](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/osx). +and [Mapbox macOS SDK](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/macos). These files depend on the Foundation and Core Foundation frameworks but do not -depend on iOS- or OS X–specific frameworks, such as UIKit or AppKit. Any +depend on iOS- or macOS–specific frameworks, such as UIKit or AppKit. Any non-cross-platform code is guarded by TargetConditionals.h macros. diff --git a/platform/darwin/src/http_file_source.mm b/platform/darwin/src/http_file_source.mm index eb751258c..a678b6e5c 100644 --- a/platform/darwin/src/http_file_source.mm +++ b/platform/darwin/src/http_file_source.mm @@ -130,7 +130,7 @@ NSString *HTTPFileSource::Impl::getUserAgent() const { } } - // Avoid %s here because it inserts hidden bidirectional markers on OS X when the system + // Avoid %s here because it inserts hidden bidirectional markers on macOS when the system // language is set to a right-to-left language. [userAgentComponents addObject:[NSString stringWithFormat:@"MapboxGL/%@ (%@)", CFSTR(MBGL_VERSION_STRING), CFSTR(MBGL_VERSION_REV)]]; @@ -139,7 +139,7 @@ NSString *HTTPFileSource::Impl::getUserAgent() const { #if TARGET_OS_IPHONE systemName = @"iOS"; #elif TARGET_OS_MAC - systemName = @"OS X"; + systemName = @"macOS"; #elif TARGET_OS_WATCH systemName = @"watchOS"; #elif TARGET_OS_TV diff --git a/platform/ios/DEVELOPING.md b/platform/ios/DEVELOPING.md index d1be5d703..240c3796b 100644 --- a/platform/ios/DEVELOPING.md +++ b/platform/ios/DEVELOPING.md @@ -4,7 +4,7 @@ This document explains how to build the Mapbox iOS SDK from source. It is intend ## Requirements -The Mapbox iOS SDK and iosapp demo application build against the iOS 7.0 SDK. The SDK is intended to run on iOS 7.0 and above, while iosapp is intended to run on iOS 8.0 and above due to the use of a dynamic framework. Both require Xcode on a computer running OS X. +The Mapbox iOS SDK and iosapp demo application build against the iOS 7.0 SDK. The SDK is intended to run on iOS 7.0 and above, while iosapp is intended to run on iOS 8.0 and above due to the use of a dynamic framework. Both require Xcode on a computer running macOS. ## Building the SDK @@ -54,14 +54,14 @@ To add an Objective-C header or implementation file to the iOS SDK: 1. Add the file to the Headers or Compile Sources build phase, as appropriate, of both the “dynamic” and “static” targets. You can either use the Build Phases tab of the project editor or the Target Membership section of the File inspector. 1. _(Optional.)_ If it’s a public header, change its visibility from Project to Public and import it in [the iOS SDK’s umbrella header](./src/Mapbox.h). -1. _(Optional.)_ If the file would also be used by the OS X SDK, make sure it’s in [platform/darwin/src/](../darwin/src/), then consult [the companion OS X document](../osx/DEVELOPING.md#adding-a-source-code-file) for further instructions. +1. _(Optional.)_ If the file would also be used by the macOS SDK, make sure it’s in [platform/darwin/src/](../darwin/src/), then consult [the companion macOS document](../macos/DEVELOPING.md#adding-a-source-code-file) for further instructions. ### Adding a resource To add a resource (such as an image, SSL certificate, property list, or strings table) to the iOS SDK: 1. Add the header to the Copy Bundle Resources build phase of both the “dynamic” and “bundle” targets. You can either use the Build Phases tab of the project editor or the Target Membership section of the File inspector. -1. _(Optional.)_ If the resource would also be used by the OS X SDK, make sure it’s in [platform/darwin/resources/](../darwin/resources/), then consult [the companion OS X document](../osx/DEVELOPING.md#adding-a-resource) for further instructions. +1. _(Optional.)_ If the resource would also be used by the macOS SDK, make sure it’s in [platform/darwin/resources/](../darwin/resources/), then consult [the companion macOS document](../macos/DEVELOPING.md#adding-a-resource) for further instructions. ### Adding user-facing text @@ -70,11 +70,11 @@ To add or update text that the user may see in the iOS SDK: 1. Make sure the implementation file imports [NSBundle+MGLAdditions.h](../darwin/src/NSBundle+MGLAdditions.h). 1. Use the `NSLocalizedStringWithDefaultValue()` macro: * `key` is a unique identifier that won’t change if the user-facing text ever needs to change. - * `tbl` is `Foundation` in code shared between the iOS and OS X SDKs, or `nil` otherwise. + * `tbl` is `Foundation` in code shared between the iOS and macOS SDKs, or `nil` otherwise. * `bundle` is `nil`; the redefined macro looks for the SDK bundle at runtime and ignores this argument. * `val` is the English string. 1. _(Optional.)_ When dealing with a number followed by a pluralized word, do not split the string. Instead, use a format string and make `val` ambiguous, like `%d file(s)`. Then pluralize for English in the appropriate [.stringsdict file](https://developer.apple.com/library/ios/documentation/MacOSX/Conceptual/BPInternational/StringsdictFileFormat/StringsdictFileFormat.html). See [platform/darwin/resources/en.lproj/Foundation.stringsdict](../darwin/resources/en.lproj/Foundation.stringsdict) for an example. Localizers should do likewise for their languages. -1. Run `make genstrings` and commit any changes it makes to .strings files. The make rule also updates the OS X SDK’s strings tables. +1. Run `make genstrings` and commit any changes it makes to .strings files. The make rule also updates the macOS SDK’s strings tables. ## Testing diff --git a/platform/osx/CHANGELOG.md b/platform/macos/CHANGELOG.md similarity index 91% rename from platform/osx/CHANGELOG.md rename to platform/macos/CHANGELOG.md index df26619ba..ca32580cf 100644 --- a/platform/osx/CHANGELOG.md +++ b/platform/macos/CHANGELOG.md @@ -1,7 +1,8 @@ -# Changelog for Mapbox OS X SDK +# Changelog for Mapbox macOS SDK ## master +* Renamed the SDK to the Mapbox macOS SDK. * Fixed an issue in which Mapbox.framework was nested inside another folder named Mapbox.framework. ([#4998](https://github.com/mapbox/mapbox-gl-native/pull/4998)) * Fixed a crash passing a mixture of point and shape annotations into `-[MGLMapView addAnnotations:]`. ([#5097](https://github.com/mapbox/mapbox-gl-native/pull/5097)) * Added new options to `MGLMapDebugMaskOptions` that show wireframes and the stencil buffer instead of the color buffer. ([#4359](https://github.com/mapbox/mapbox-gl-native/pull/4359)) diff --git a/platform/osx/DEVELOPING.md b/platform/macos/DEVELOPING.md similarity index 70% rename from platform/osx/DEVELOPING.md rename to platform/macos/DEVELOPING.md index dcba9db1a..fc7b0330a 100644 --- a/platform/osx/DEVELOPING.md +++ b/platform/macos/DEVELOPING.md @@ -1,42 +1,42 @@ -# Contributing to the Mapbox OS X SDK +# Contributing to the Mapbox macOS SDK -This document explains how to build the Mapbox OS X SDK from source. It is intended for advanced developers who wish to contribute to Mapbox GL and the Mapbox iOS SDK. +This document explains how to build the Mapbox macOS SDK from source. It is intended for advanced developers who wish to contribute to Mapbox GL and the Mapbox iOS SDK. ## Requirements -The Mapbox OS X SDK and the osxapp demo application run on OS X 10.10.0 and above. +The Mapbox macOS SDK and the macosapp demo application run on macOS 10.10.0 and above. ## Building the SDK 1. [Install core dependencies](../../INSTALL.md). 1. Run `make xproj`. -1. Switch to the “dynamic” or “osxapp” scheme. The former builds just the Cocoa framework, while the latter also builds a Cocoa demo application based on it. +1. Switch to the “dynamic” or “macosapp” scheme. The former builds just the Cocoa framework, while the latter also builds a Cocoa demo application based on it. ## Contributing ### Adding a source code file -To add an Objective-C header or implementation file to the OS X SDK: +To add an Objective-C header or implementation file to the macOS SDK: 1. Add the file to the “dynamic” target’s Headers or Compile Sources build phase, as appropriate. You can either use the Build Phases tab of the project editor or the Target Membership section of the File inspector. -1. _(Optional.)_ If it’s a public header, change its visibility from Project to Public and import it in [the OS X SDK’s umbrella header](./src/Mapbox.h). +1. _(Optional.)_ If it’s a public header, change its visibility from Project to Public and import it in [the macOS SDK’s umbrella header](./src/Mapbox.h). 1. _(Optional.)_ If the file would also be used by the iOS SDK, make sure it’s in [platform/darwin/src/](../darwin/src/), then consult [the companion iOS document](../ios/DEVELOPING.md#adding-a-source-code-file) for further instructions. ### Adding a resource -To add a resource (such as an image, SSL certificate, property list, or strings table) to the OS X SDK: +To add a resource (such as an image, SSL certificate, property list, or strings table) to the macOS SDK: 1. Add the header to the Copy Bundle Resources build phase of the “dynamic” target. You can either use the Build Phases tab of the project editor or the Target Membership section of the File inspector. 1. _(Optional.)_ If the resource would also be used by the iOS SDK, make sure it’s in [platform/darwin/resources/](../darwin/resources/), then consult [the companion iOS document](../ios/DEVELOPING.md#adding-a-resource) for further instructions. ### Adding user-facing text -To add or update text that the user may see in the OS X SDK: +To add or update text that the user may see in the macOS SDK: 1. Make sure the implementation file imports [NSBundle+MGLAdditions.h](../darwin/src/NSBundle+MGLAdditions.h). 1. Use the `NSLocalizedStringWithDefaultValue()` macro: * `key` is a unique identifier that won’t change if the user-facing text ever needs to change. - * `tbl` is `Foundation` in code shared between the iOS and OS X SDKs, or `nil` otherwise. + * `tbl` is `Foundation` in code shared between the iOS and macOS SDKs, or `nil` otherwise. * `bundle` is `nil`; the redefined macro looks for the SDK bundle at runtime and ignores this argument. * `val` is the English string. 1. _(Optional.)_ When dealing with a number followed by a pluralized word, do not split the string. Instead, use a format string and make `val` ambiguous, like `%d file(s)`. Then pluralize for English in the appropriate [.stringsdict file](https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPInternational/StringsdictFileFormat/StringsdictFileFormat.html). See [platform/darwin/resources/en.lproj/Foundation.stringsdict](../darwin/resources/en.lproj/Foundation.stringsdict) for an example. Localizers should do likewise for their languages. @@ -46,8 +46,8 @@ To add or update text that the user may see in the OS X SDK: The demo applications use Mapbox vector tiles, which require a Mapbox account and API access token. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/). You will be prompted for this access token the first time you launch the demo application. -## Using osxapp +## Using macosapp -Through the OS X SDK, the demo application supports a variety of standard gestures and keyboard shortcuts. For more details, open Mapbox GL Help from the Help menu. +Through the macOS SDK, the demo application supports a variety of standard gestures and keyboard shortcuts. For more details, open Mapbox GL Help from the Help menu. -You can also [integrate the Mapbox OS X SDK into your own Cocoa application](INSTALL.md). +You can also [integrate the Mapbox macOS SDK into your own Cocoa application](INSTALL.md). diff --git a/platform/osx/INSTALL.md b/platform/macos/INSTALL.md similarity index 72% rename from platform/osx/INSTALL.md rename to platform/macos/INSTALL.md index 8a4323aa8..42896d380 100644 --- a/platform/osx/INSTALL.md +++ b/platform/macos/INSTALL.md @@ -1,23 +1,23 @@ -# Integrating the Mapbox OS X SDK into your application +# Integrating the Mapbox macOS SDK into your application -This document explains how to build the Mapbox OS X SDK and integrate it into your own Cocoa application. +This document explains how to build the Mapbox macOS SDK and integrate it into your own Cocoa application. ### Requirements -The Mapbox OS X SDK requires the OS X 10.10.0 SDK or above. +The Mapbox macOS SDK requires the macOS 10.10.0 SDK or above. ### Building the SDK -Grab a [prebuilt release](https://github.com/mapbox/mapbox-gl-native/releases/) – look for the releases that begin with “osx-” – or build the SDK from source: +Grab a [prebuilt release](https://github.com/mapbox/mapbox-gl-native/releases/) – look for the releases that begin with “macos-” – or build the SDK from source: 1. [Install core dependencies](../../INSTALL.md). -1. Run `make xpackage`, which produces a `Mapbox.framework` in the `build/osx/pkg/` folder. +1. Run `make xpackage`, which produces a `Mapbox.framework` in the `build/macos/pkg/` folder. ### Installation 1. Open the project editor, select your application target, then go to the General tab. Drag Mapbox.framework into the “Embedded Binaries” section. (Don’t drag it into the “Linked Frameworks and Libraries” section; Xcode will add it there automatically.) In the sheet that appears, make sure “Copy items if needed” is checked, then click Finish. -1. Mapbox vector tiles require a Mapbox account and API access token. In the project editor, select the application target, then go to the Info tab. Under the “Custom OS X Application Target Properties” section, set `MGLMapboxAccessToken` to your access token. You can obtain an access token from the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/). +1. Mapbox vector tiles require a Mapbox account and API access token. In the project editor, select the application target, then go to the Info tab. Under the “Custom macOS Application Target Properties” section, set `MGLMapboxAccessToken` to your access token. You can obtain an access token from the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/). ## Usage @@ -47,4 +47,4 @@ class ViewController: NSViewController { } ``` -Run `make xdocument` to generate complete API documentation. The [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)’s [API documentation](https://www.mapbox.com/ios-sdk/api/) and [online examples](https://www.mapbox.com/ios-sdk/examples/) apply to the Mapbox OS X SDK with few differences, mostly around unimplemented features like user location tracking. +Run `make xdocument` to generate complete API documentation. The [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)’s [API documentation](https://www.mapbox.com/ios-sdk/api/) and [online examples](https://www.mapbox.com/ios-sdk/examples/) apply to the Mapbox macOS SDK with few differences, mostly around unimplemented features like user location tracking. diff --git a/platform/osx/README.md b/platform/macos/README.md similarity index 55% rename from platform/osx/README.md rename to platform/macos/README.md index 75c8c3453..211b238d5 100644 --- a/platform/osx/README.md +++ b/platform/macos/README.md @@ -1,12 +1,12 @@ -# Mapbox OS X SDK +# Mapbox macOS SDK [![Bitrise](https://www.bitrise.io/app/155ef7da24b38dcd.svg?token=4KSOw_gd6WxTnvGE2rMttg&branch=master)](https://www.bitrise.io/app/155ef7da24b38dcd) -A library based on [Mapbox GL Native](../../README.md) for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on OS X 10.10.0 and above using Objective-C, Swift, or Interface Builder. +A library based on [Mapbox GL Native](../../README.md) for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on macOS 10.10.0 and above using Objective-C, Swift, or Interface Builder. -This SDK is analogous to the Mapbox iOS SDK, and much of the iOS SDK documentation applies here. Mapbox does not officially support the OS X SDK to the same extent as the iOS SDK; however, bug reports and pull requests are certainly welcome. +This SDK is analogous to the Mapbox iOS SDK, and much of the iOS SDK documentation applies here. Mapbox does not officially support the macOS SDK to the same extent as the iOS SDK; however, bug reports and pull requests are certainly welcome. -* [Integrating the Mapbox OS X SDK into your application](INSTALL.md) -* [Contributing to the Mapbox OS X SDK](DEVELOPING.md) +* [Integrating the Mapbox macOS SDK into your application](INSTALL.md) +* [Contributing to the Mapbox macOS SDK](DEVELOPING.md) diff --git a/platform/osx/WorkspaceSettings.xcsettings b/platform/macos/WorkspaceSettings.xcsettings similarity index 100% rename from platform/osx/WorkspaceSettings.xcsettings rename to platform/macos/WorkspaceSettings.xcsettings diff --git a/platform/osx/app/AppDelegate.h b/platform/macos/app/AppDelegate.h similarity index 100% rename from platform/osx/app/AppDelegate.h rename to platform/macos/app/AppDelegate.h diff --git a/platform/osx/app/AppDelegate.m b/platform/macos/app/AppDelegate.m similarity index 100% rename from platform/osx/app/AppDelegate.m rename to platform/macos/app/AppDelegate.m diff --git a/platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.png similarity index 100% rename from platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.png rename to platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon128x128.png diff --git a/platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.png similarity index 100% rename from platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.png rename to platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon16x16.png diff --git a/platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256-1.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256-1.png similarity index 100% rename from platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256-1.png rename to platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256-1.png diff --git a/platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.png similarity index 100% rename from platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.png rename to platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon256x256.png diff --git a/platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32-1.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32-1.png similarity index 100% rename from platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32-1.png rename to platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32-1.png diff --git a/platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.png similarity index 100% rename from platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.png rename to platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon32x32.png diff --git a/platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512-1.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512-1.png similarity index 100% rename from platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512-1.png rename to platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512-1.png diff --git a/platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.png similarity index 100% rename from platform/osx/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.png rename to platform/macos/app/Assets.xcassets/AppIcon.appiconset/AppIcon512x512.png diff --git a/platform/osx/app/Assets.xcassets/AppIcon.appiconset/Contents.json b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from platform/osx/app/Assets.xcassets/AppIcon.appiconset/Contents.json rename to platform/macos/app/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/platform/osx/app/Assets.xcassets/AppIcon.appiconset/icon-1.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon-1.png similarity index 100% rename from platform/osx/app/Assets.xcassets/AppIcon.appiconset/icon-1.png rename to platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon-1.png diff --git a/platform/osx/app/Assets.xcassets/AppIcon.appiconset/icon.png b/platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon.png similarity index 100% rename from platform/osx/app/Assets.xcassets/AppIcon.appiconset/icon.png rename to platform/macos/app/Assets.xcassets/AppIcon.appiconset/icon.png diff --git a/platform/osx/app/Assets.xcassets/Contents.json b/platform/macos/app/Assets.xcassets/Contents.json similarity index 100% rename from platform/osx/app/Assets.xcassets/Contents.json rename to platform/macos/app/Assets.xcassets/Contents.json diff --git a/platform/osx/app/Base.lproj/MainMenu.xib b/platform/macos/app/Base.lproj/MainMenu.xib similarity index 100% rename from platform/osx/app/Base.lproj/MainMenu.xib rename to platform/macos/app/Base.lproj/MainMenu.xib diff --git a/platform/osx/app/Base.lproj/MapDocument.xib b/platform/macos/app/Base.lproj/MapDocument.xib similarity index 100% rename from platform/osx/app/Base.lproj/MapDocument.xib rename to platform/macos/app/Base.lproj/MapDocument.xib diff --git a/platform/osx/app/Credits.rtf b/platform/macos/app/Credits.rtf similarity index 100% rename from platform/osx/app/Credits.rtf rename to platform/macos/app/Credits.rtf diff --git a/platform/osx/app/DroppedPinAnnotation.h b/platform/macos/app/DroppedPinAnnotation.h similarity index 100% rename from platform/osx/app/DroppedPinAnnotation.h rename to platform/macos/app/DroppedPinAnnotation.h diff --git a/platform/osx/app/DroppedPinAnnotation.m b/platform/macos/app/DroppedPinAnnotation.m similarity index 100% rename from platform/osx/app/DroppedPinAnnotation.m rename to platform/macos/app/DroppedPinAnnotation.m diff --git a/platform/osx/app/Info.plist b/platform/macos/app/Info.plist similarity index 100% rename from platform/osx/app/Info.plist rename to platform/macos/app/Info.plist diff --git a/platform/osx/app/LocationCoordinate2DTransformer.h b/platform/macos/app/LocationCoordinate2DTransformer.h similarity index 100% rename from platform/osx/app/LocationCoordinate2DTransformer.h rename to platform/macos/app/LocationCoordinate2DTransformer.h diff --git a/platform/osx/app/LocationCoordinate2DTransformer.m b/platform/macos/app/LocationCoordinate2DTransformer.m similarity index 100% rename from platform/osx/app/LocationCoordinate2DTransformer.m rename to platform/macos/app/LocationCoordinate2DTransformer.m diff --git a/platform/osx/app/MapDocument.h b/platform/macos/app/MapDocument.h similarity index 100% rename from platform/osx/app/MapDocument.h rename to platform/macos/app/MapDocument.h diff --git a/platform/osx/app/MapDocument.m b/platform/macos/app/MapDocument.m similarity index 100% rename from platform/osx/app/MapDocument.m rename to platform/macos/app/MapDocument.m diff --git a/platform/osx/app/OfflinePackNameValueTransformer.h b/platform/macos/app/OfflinePackNameValueTransformer.h similarity index 100% rename from platform/osx/app/OfflinePackNameValueTransformer.h rename to platform/macos/app/OfflinePackNameValueTransformer.h diff --git a/platform/osx/app/OfflinePackNameValueTransformer.m b/platform/macos/app/OfflinePackNameValueTransformer.m similarity index 100% rename from platform/osx/app/OfflinePackNameValueTransformer.m rename to platform/macos/app/OfflinePackNameValueTransformer.m diff --git a/platform/osx/app/TimeIntervalTransformer.h b/platform/macos/app/TimeIntervalTransformer.h similarity index 100% rename from platform/osx/app/TimeIntervalTransformer.h rename to platform/macos/app/TimeIntervalTransformer.h diff --git a/platform/osx/app/TimeIntervalTransformer.m b/platform/macos/app/TimeIntervalTransformer.m similarity index 100% rename from platform/osx/app/TimeIntervalTransformer.m rename to platform/macos/app/TimeIntervalTransformer.m diff --git a/platform/osx/app/main.m b/platform/macos/app/main.m similarity index 100% rename from platform/osx/app/main.m rename to platform/macos/app/main.m diff --git a/platform/osx/bitrise.yml b/platform/macos/bitrise.yml similarity index 93% rename from platform/osx/bitrise.yml rename to platform/macos/bitrise.yml index fdf9ebb65..ce622ef0f 100644 --- a/platform/osx/bitrise.yml +++ b/platform/macos/bitrise.yml @@ -31,8 +31,8 @@ workflows: set -eu -o pipefail gem install xcpretty --no-rdoc --no-ri export BUILDTYPE=Debug - make osx - make test-osx + make macos + make test-macos - is_debug: 'yes' - slack: title: Post to Slack @@ -40,8 +40,8 @@ workflows: inputs: - webhook_url: "$SLACK_HOOK_URL" - channel: "#gl-bots" - - from_username: 'Bitrise OS X' - - from_username_on_error: 'Bitrise OS X' + - from_username: 'Bitrise macOS' + - from_username_on_error: 'Bitrise macOS' - message: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}> for by ${GIT_CLONE_COMMIT_COMMITER_NAME} diff --git a/platform/macos/docs/doc-README.md b/platform/macos/docs/doc-README.md new file mode 100644 index 000000000..b037da19d --- /dev/null +++ b/platform/macos/docs/doc-README.md @@ -0,0 +1,9 @@ +# [Mapbox macOS SDK](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/macos/) + +The Mapbox macOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on macOS 10.10.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox GL Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL. + + + +For setup information, consult the README.md that comes with this documentation. The [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)’s [API documentation](https://www.mapbox.com/ios-sdk/api/) and [online examples](https://www.mapbox.com/ios-sdk/examples/) apply to the Mapbox macOS SDK with few differences, mostly around unimplemented features like user location tracking. A [full changelog](https://github.com/mapbox/mapbox-gl-native/blob/master/platform/macos/CHANGELOG.md) is also available. + +Mapbox does not officially support the macOS SDK to the same extent as the iOS SDK; however, [bug reports and pull requests](https://github.com/mapbox/mapbox-gl-native/issues/) are certainly welcome. diff --git a/platform/osx/docs/pod-README.md b/platform/macos/docs/pod-README.md similarity index 59% rename from platform/osx/docs/pod-README.md rename to platform/macos/docs/pod-README.md index 28c783cf5..70d98ecdb 100644 --- a/platform/osx/docs/pod-README.md +++ b/platform/macos/docs/pod-README.md @@ -1,14 +1,14 @@ -# [Mapbox OS X SDK](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/osx/) +# [Mapbox macOS SDK](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/macos/) -The Mapbox OS X SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on OS X 10.10.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox GL Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL. +The Mapbox macOS SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on macOS 10.10.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox GL Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL. - + ## Installation 1. Open the project editor, select your application target, then go to the General tab. Drag Mapbox.framework from the `dynamic` folder into the “Embedded Binaries” section. (Don’t drag it into the “Linked Frameworks and Libraries” section; Xcode will add it there automatically.) In the sheet that appears, make sure “Copy items if needed” is checked, then click Finish. -1. Mapbox vector tiles require a Mapbox account and API access token. In the project editor, select the application target, then go to the Info tab. Under the “Custom iOS Target Properties” section, set `MGLMapboxAccessToken` to your access token. You can obtain an access token from the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/). +1. Mapbox vector tiles require a Mapbox account and API access token. In the project editor, select the application target, then go to the Info tab. Under the “Custom macOS Target Properties” section, set `MGLMapboxAccessToken` to your access token. You can obtain an access token from the [Mapbox account page](https://www.mapbox.com/studio/account/tokens/). ## Usage @@ -38,6 +38,6 @@ class ViewController: NSViewController { } ``` -Full API documentation is included in this package, within the `documentation` folder. The [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)’s [API documentation](https://www.mapbox.com/ios-sdk/api/) and [online examples](https://www.mapbox.com/ios-sdk/examples/) apply to the Mapbox OS X SDK with few differences, mostly around unimplemented features like user location tracking. +Full API documentation is included in this package, within the `documentation` folder. The [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)’s [API documentation](https://www.mapbox.com/ios-sdk/api/) and [online examples](https://www.mapbox.com/ios-sdk/examples/) apply to the Mapbox macOS SDK with few differences, mostly around unimplemented features like user location tracking. -Mapbox does not officially support the OS X SDK to the same extent as the iOS SDK; however, [bug reports and pull requests](https://github.com/mapbox/mapbox-gl-native/issues/) are certainly welcome. +Mapbox does not officially support the macOS SDK to the same extent as the iOS SDK; however, [bug reports and pull requests](https://github.com/mapbox/mapbox-gl-native/issues/) are certainly welcome. diff --git a/platform/osx/jazzy.yml b/platform/macos/jazzy.yml similarity index 100% rename from platform/osx/jazzy.yml rename to platform/macos/jazzy.yml diff --git a/platform/osx/osx.xcodeproj/project.pbxproj b/platform/macos/macos.xcodeproj/project.pbxproj similarity index 98% rename from platform/osx/osx.xcodeproj/project.pbxproj rename to platform/macos/macos.xcodeproj/project.pbxproj index 270b2e33d..be82bcc47 100644 --- a/platform/osx/osx.xcodeproj/project.pbxproj +++ b/platform/macos/macos.xcodeproj/project.pbxproj @@ -40,7 +40,7 @@ DAE6C33D1CC30DB200DB3429 /* Mapbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3281CC30DB200DB3429 /* Mapbox.framework */; }; DAE6C33E1CC30DB200DB3429 /* Mapbox.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3281CC30DB200DB3429 /* Mapbox.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; DAE6C3471CC31D1200DB3429 /* libmbgl-core.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */; }; - DAE6C3481CC31D1200DB3429 /* libmbgl-platform-osx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3461CC31D1200DB3429 /* libmbgl-platform-osx.a */; }; + DAE6C3481CC31D1200DB3429 /* libmbgl-platform-macos.a in Frameworks */ = {isa = PBXBuildFile; fileRef = DAE6C3461CC31D1200DB3429 /* libmbgl-platform-macos.a */; }; DAE6C35A1CC31E0400DB3429 /* MGLAccountManager.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C34A1CC31E0400DB3429 /* MGLAccountManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAE6C35B1CC31E0400DB3429 /* MGLAnnotation.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C34B1CC31E0400DB3429 /* MGLAnnotation.h */; settings = {ATTRIBUTES = (Public, ); }; }; DAE6C35C1CC31E0400DB3429 /* MGLGeometry.h in Headers */ = {isa = PBXBuildFile; fileRef = DAE6C34C1CC31E0400DB3429 /* MGLGeometry.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -181,7 +181,7 @@ DAE6C3311CC30DB200DB3429 /* test.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = test.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DAE6C33A1CC30DB200DB3429 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libmbgl-core.a"; sourceTree = BUILT_PRODUCTS_DIR; }; - DAE6C3461CC31D1200DB3429 /* libmbgl-platform-osx.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libmbgl-platform-osx.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + DAE6C3461CC31D1200DB3429 /* libmbgl-platform-macos.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = "libmbgl-platform-macos.a"; sourceTree = BUILT_PRODUCTS_DIR; }; DAE6C34A1CC31E0400DB3429 /* MGLAccountManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAccountManager.h; sourceTree = ""; }; DAE6C34B1CC31E0400DB3429 /* MGLAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLAnnotation.h; sourceTree = ""; }; DAE6C34C1CC31E0400DB3429 /* MGLGeometry.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLGeometry.h; sourceTree = ""; }; @@ -241,7 +241,7 @@ DAE6C3BB1CC31F2E00DB3429 /* default_marker.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = default_marker.pdf; sourceTree = ""; }; DAE6C3BC1CC31F2E00DB3429 /* mapbox.pdf */ = {isa = PBXFileReference; lastKnownFileType = image.pdf; path = mapbox.pdf; sourceTree = ""; }; DAE6C3C11CC31F4500DB3429 /* Mapbox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Mapbox.h; path = src/Mapbox.h; sourceTree = SOURCE_ROOT; }; - DAE6C3C51CC31F9100DB3429 /* mbgl.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = mbgl.xcconfig; path = ../../build/osx/mbgl.xcconfig; sourceTree = ""; }; + DAE6C3C51CC31F9100DB3429 /* mbgl.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = mbgl.xcconfig; path = ../../build/macos/mbgl.xcconfig; sourceTree = ""; }; DAE6C3C61CC3499100DB3429 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; DAE6C3C81CC34BD800DB3429 /* MGLGeometryTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLGeometryTests.mm; path = ../../darwin/test/MGLGeometryTests.mm; sourceTree = ""; }; DAE6C3C91CC34BD800DB3429 /* MGLOfflinePackTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflinePackTests.m; path = ../../darwin/test/MGLOfflinePackTests.m; sourceTree = ""; }; @@ -265,7 +265,7 @@ files = ( 52BECB0A1CC5A26F009CD791 /* SystemConfiguration.framework in Frameworks */, DAE6C3471CC31D1200DB3429 /* libmbgl-core.a in Frameworks */, - DAE6C3481CC31D1200DB3429 /* libmbgl-platform-osx.a in Frameworks */, + DAE6C3481CC31D1200DB3429 /* libmbgl-platform-macos.a in Frameworks */, DAE6C3C71CC3499100DB3429 /* libsqlite3.tbd in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -364,7 +364,7 @@ children = ( 52BECB091CC5A26F009CD791 /* SystemConfiguration.framework */, DAE6C3451CC31D1200DB3429 /* libmbgl-core.a */, - DAE6C3461CC31D1200DB3429 /* libmbgl-platform-osx.a */, + DAE6C3461CC31D1200DB3429 /* libmbgl-platform-macos.a */, DAE6C3C61CC3499100DB3429 /* libsqlite3.tbd */, ); name = Frameworks; @@ -545,7 +545,7 @@ /* Begin PBXLegacyTarget section */ DAAA17961CE13BAE00731EFE /* docs */ = { isa = PBXLegacyTarget; - buildArgumentsString = "xdocument OUTPUT=build/osx/pkg/documentation"; + buildArgumentsString = "xdocument OUTPUT=build/macos/pkg/documentation"; buildConfigurationList = DAAA17991CE13BAE00731EFE /* Build configuration list for PBXLegacyTarget "docs" */; buildPhases = ( ); @@ -560,9 +560,9 @@ /* End PBXLegacyTarget section */ /* Begin PBXNativeTarget section */ - DA839E911CC2E3400062CAFB /* osxapp */ = { + DA839E911CC2E3400062CAFB /* macosapp */ = { isa = PBXNativeTarget; - buildConfigurationList = DA839EA91CC2E3400062CAFB /* Build configuration list for PBXNativeTarget "osxapp" */; + buildConfigurationList = DA839EA91CC2E3400062CAFB /* Build configuration list for PBXNativeTarget "macosapp" */; buildPhases = ( DA839E8E1CC2E3400062CAFB /* Sources */, DA839E8F1CC2E3400062CAFB /* Frameworks */, @@ -574,8 +574,8 @@ dependencies = ( DAE6C33C1CC30DB200DB3429 /* PBXTargetDependency */, ); - name = osxapp; - productName = osxapp; + name = macosapp; + productName = macosapp; productReference = DA839E921CC2E3400062CAFB /* Mapbox GL.app */; productType = "com.apple.product-type.application"; }; @@ -639,7 +639,7 @@ }; }; }; - buildConfigurationList = DA839E8D1CC2E3400062CAFB /* Build configuration list for PBXProject "osx" */; + buildConfigurationList = DA839E8D1CC2E3400062CAFB /* Build configuration list for PBXProject "macos" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; @@ -652,7 +652,7 @@ projectDirPath = ""; projectRoot = ""; targets = ( - DA839E911CC2E3400062CAFB /* osxapp */, + DA839E911CC2E3400062CAFB /* macosapp */, DAE6C3271CC30DB200DB3429 /* dynamic */, DAE6C3301CC30DB200DB3429 /* test */, DAAA17961CE13BAE00731EFE /* docs */, @@ -1069,7 +1069,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - DA839E8D1CC2E3400062CAFB /* Build configuration list for PBXProject "osx" */ = { + DA839E8D1CC2E3400062CAFB /* Build configuration list for PBXProject "macos" */ = { isa = XCConfigurationList; buildConfigurations = ( DA839EA71CC2E3400062CAFB /* Debug */, @@ -1078,7 +1078,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - DA839EA91CC2E3400062CAFB /* Build configuration list for PBXNativeTarget "osxapp" */ = { + DA839EA91CC2E3400062CAFB /* Build configuration list for PBXNativeTarget "macosapp" */ = { isa = XCConfigurationList; buildConfigurations = ( DA839EAA1CC2E3400062CAFB /* Debug */, diff --git a/platform/osx/osx.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/platform/macos/macos.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 87% rename from platform/osx/osx.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to platform/macos/macos.xcodeproj/project.xcworkspace/contents.xcworkspacedata index 6451d59ca..f2c779de4 100644 --- a/platform/osx/osx.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ b/platform/macos/macos.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -2,6 +2,6 @@ + location = "self:/Users/mxn/hub/mapbox-gl-native/platform/macos/macos.xcodeproj"> diff --git a/platform/osx/osx.xcodeproj/xcshareddata/xcschemes/CI.xcscheme b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme similarity index 86% rename from platform/osx/osx.xcodeproj/xcshareddata/xcschemes/CI.xcscheme rename to platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme index 2c9e4a3c7..476532377 100644 --- a/platform/osx/osx.xcodeproj/xcshareddata/xcschemes/CI.xcscheme +++ b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/CI.xcscheme @@ -17,7 +17,7 @@ BlueprintIdentifier = "4E8A9455A3A23B7FD2A8FC52" BuildableName = "All" BlueprintName = "All" - ReferencedContainer = "container:../../build/osx/platform/osx/platform.xcodeproj"> + ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj"> + BlueprintName = "macosapp" + ReferencedContainer = "container:macos.xcodeproj"> + ReferencedContainer = "container:macos.xcodeproj"> @@ -63,7 +63,7 @@ BlueprintIdentifier = "DAE6C3301CC30DB200DB3429" BuildableName = "test.xctest" BlueprintName = "test" - ReferencedContainer = "container:osx.xcodeproj"> + ReferencedContainer = "container:macos.xcodeproj"> @@ -72,8 +72,8 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "DA839E911CC2E3400062CAFB" BuildableName = "Mapbox GL.app" - BlueprintName = "osxapp" - ReferencedContainer = "container:osx.xcodeproj"> + BlueprintName = "macosapp" + ReferencedContainer = "container:macos.xcodeproj"> @@ -94,8 +94,8 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "DA839E911CC2E3400062CAFB" BuildableName = "Mapbox GL.app" - BlueprintName = "osxapp" - ReferencedContainer = "container:osx.xcodeproj"> + BlueprintName = "macosapp" + ReferencedContainer = "container:macos.xcodeproj"> @@ -113,8 +113,8 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "DA839E911CC2E3400062CAFB" BuildableName = "Mapbox GL.app" - BlueprintName = "osxapp" - ReferencedContainer = "container:osx.xcodeproj"> + BlueprintName = "macosapp" + ReferencedContainer = "container:macos.xcodeproj"> diff --git a/platform/osx/osx.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme similarity index 90% rename from platform/osx/osx.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme rename to platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme index b3659411e..1d1c9de8c 100644 --- a/platform/osx/osx.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme +++ b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/dynamic.xcscheme @@ -17,7 +17,7 @@ BlueprintIdentifier = "DAE6C3271CC30DB200DB3429" BuildableName = "Mapbox.framework" BlueprintName = "dynamic" - ReferencedContainer = "container:osx.xcodeproj"> + ReferencedContainer = "container:macos.xcodeproj"> + ReferencedContainer = "container:macos.xcodeproj"> @@ -49,7 +49,7 @@ BlueprintIdentifier = "DAE6C3301CC30DB200DB3429" BuildableName = "test.xctest" BlueprintName = "test" - ReferencedContainer = "container:osx.xcodeproj"> + ReferencedContainer = "container:macos.xcodeproj"> @@ -59,7 +59,7 @@ BlueprintIdentifier = "DAE6C3271CC30DB200DB3429" BuildableName = "Mapbox.framework" BlueprintName = "dynamic" - ReferencedContainer = "container:osx.xcodeproj"> + ReferencedContainer = "container:macos.xcodeproj"> @@ -81,7 +81,7 @@ BlueprintIdentifier = "DAE6C3271CC30DB200DB3429" BuildableName = "Mapbox.framework" BlueprintName = "dynamic" - ReferencedContainer = "container:osx.xcodeproj"> + ReferencedContainer = "container:macos.xcodeproj"> @@ -99,7 +99,7 @@ BlueprintIdentifier = "DAE6C3271CC30DB200DB3429" BuildableName = "Mapbox.framework" BlueprintName = "dynamic" - ReferencedContainer = "container:osx.xcodeproj"> + ReferencedContainer = "container:macos.xcodeproj"> diff --git a/platform/osx/osx.xcodeproj/xcshareddata/xcschemes/osxapp.xcscheme b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme similarity index 87% rename from platform/osx/osx.xcodeproj/xcshareddata/xcschemes/osxapp.xcscheme rename to platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme index 528ce0e75..3e3baa832 100644 --- a/platform/osx/osx.xcodeproj/xcshareddata/xcschemes/osxapp.xcscheme +++ b/platform/macos/macos.xcodeproj/xcshareddata/xcschemes/macosapp.xcscheme @@ -16,8 +16,8 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "DA839E911CC2E3400062CAFB" BuildableName = "Mapbox GL.app" - BlueprintName = "osxapp" - ReferencedContainer = "container:osx.xcodeproj"> + BlueprintName = "macosapp" + ReferencedContainer = "container:macos.xcodeproj"> @@ -35,7 +35,7 @@ BlueprintIdentifier = "DAE6C3301CC30DB200DB3429" BuildableName = "test.xctest" BlueprintName = "test" - ReferencedContainer = "container:osx.xcodeproj"> + ReferencedContainer = "container:macos.xcodeproj"> @@ -44,8 +44,8 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "DA839E911CC2E3400062CAFB" BuildableName = "Mapbox GL.app" - BlueprintName = "osxapp" - ReferencedContainer = "container:osx.xcodeproj"> + BlueprintName = "macosapp" + ReferencedContainer = "container:macos.xcodeproj"> @@ -67,8 +67,8 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "DA839E911CC2E3400062CAFB" BuildableName = "Mapbox GL.app" - BlueprintName = "osxapp" - ReferencedContainer = "container:osx.xcodeproj"> + BlueprintName = "macosapp" + ReferencedContainer = "container:macos.xcodeproj"> @@ -86,8 +86,8 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "DA839E911CC2E3400062CAFB" BuildableName = "Mapbox GL.app" - BlueprintName = "osxapp" - ReferencedContainer = "container:osx.xcodeproj"> + BlueprintName = "macosapp" + ReferencedContainer = "container:macos.xcodeproj"> diff --git a/platform/osx/osx.xcworkspace/contents.xcworkspacedata b/platform/macos/macos.xcworkspace/contents.xcworkspacedata similarity index 52% rename from platform/osx/osx.xcworkspace/contents.xcworkspacedata rename to platform/macos/macos.xcworkspace/contents.xcworkspacedata index 3d745d179..67a33490e 100644 --- a/platform/osx/osx.xcworkspace/contents.xcworkspacedata +++ b/platform/macos/macos.xcworkspace/contents.xcworkspacedata @@ -2,9 +2,9 @@ + location = "container:macos.xcodeproj"> + location = "group:../../build/macos/platform/macos/platform.xcodeproj"> diff --git a/platform/osx/osx.xcworkspace/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist b/platform/macos/macos.xcworkspace/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist similarity index 100% rename from platform/osx/osx.xcworkspace/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist rename to platform/macos/macos.xcworkspace/xcshareddata/xcdebugger/Breakpoints_v2.xcbkptlist diff --git a/platform/osx/osx.xcworkspace/xcshareddata/xcschemes/mbgl-offline.xcscheme b/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/mbgl-offline.xcscheme similarity index 88% rename from platform/osx/osx.xcworkspace/xcshareddata/xcschemes/mbgl-offline.xcscheme rename to platform/macos/macos.xcworkspace/xcshareddata/xcschemes/mbgl-offline.xcscheme index c88fefb74..90ba9db15 100644 --- a/platform/osx/osx.xcworkspace/xcshareddata/xcschemes/mbgl-offline.xcscheme +++ b/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/mbgl-offline.xcscheme @@ -17,7 +17,7 @@ BlueprintIdentifier = "960D5BDFBD73C605ACCF58C2" BuildableName = "mbgl-offline" BlueprintName = "mbgl-offline" - ReferencedContainer = "container:../../build/osx/platform/osx/platform.xcodeproj"> + ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj"> @@ -35,7 +35,7 @@ BlueprintIdentifier = "960D5BDFBD73C605ACCF58C2" BuildableName = "mbgl-offline" BlueprintName = "mbgl-offline" - ReferencedContainer = "container:../../build/osx/platform/osx/platform.xcodeproj"> + ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj"> @@ -59,7 +59,7 @@ BlueprintIdentifier = "960D5BDFBD73C605ACCF58C2" BuildableName = "mbgl-offline" BlueprintName = "mbgl-offline" - ReferencedContainer = "container:../../build/osx/platform/osx/platform.xcodeproj"> + ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj"> @@ -78,7 +78,7 @@ BlueprintIdentifier = "960D5BDFBD73C605ACCF58C2" BuildableName = "mbgl-offline" BlueprintName = "mbgl-offline" - ReferencedContainer = "container:../../build/osx/platform/osx/platform.xcodeproj"> + ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj"> diff --git a/platform/osx/osx.xcworkspace/xcshareddata/xcschemes/mbgl-render.xcscheme b/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/mbgl-render.xcscheme similarity index 88% rename from platform/osx/osx.xcworkspace/xcshareddata/xcschemes/mbgl-render.xcscheme rename to platform/macos/macos.xcworkspace/xcshareddata/xcschemes/mbgl-render.xcscheme index 522998bd3..c17686199 100644 --- a/platform/osx/osx.xcworkspace/xcshareddata/xcschemes/mbgl-render.xcscheme +++ b/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/mbgl-render.xcscheme @@ -17,7 +17,7 @@ BlueprintIdentifier = "D27AE71B9B193AD277AD4CFE" BuildableName = "mbgl-render" BlueprintName = "mbgl-render" - ReferencedContainer = "container:../../build/osx/platform/osx/platform.xcodeproj"> + ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj"> @@ -35,7 +35,7 @@ BlueprintIdentifier = "D27AE71B9B193AD277AD4CFE" BuildableName = "mbgl-render" BlueprintName = "mbgl-render" - ReferencedContainer = "container:../../build/osx/platform/osx/platform.xcodeproj"> + ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj"> @@ -59,7 +59,7 @@ BlueprintIdentifier = "D27AE71B9B193AD277AD4CFE" BuildableName = "mbgl-render" BlueprintName = "mbgl-render" - ReferencedContainer = "container:../../build/osx/platform/osx/platform.xcodeproj"> + ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj"> @@ -78,7 +78,7 @@ BlueprintIdentifier = "D27AE71B9B193AD277AD4CFE" BuildableName = "mbgl-render" BlueprintName = "mbgl-render" - ReferencedContainer = "container:../../build/osx/platform/osx/platform.xcodeproj"> + ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj"> diff --git a/platform/osx/osx.xcworkspace/xcshareddata/xcschemes/test.xcscheme b/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/test.xcscheme similarity index 88% rename from platform/osx/osx.xcworkspace/xcshareddata/xcschemes/test.xcscheme rename to platform/macos/macos.xcworkspace/xcshareddata/xcschemes/test.xcscheme index f995e7496..20394eb25 100644 --- a/platform/osx/osx.xcworkspace/xcshareddata/xcschemes/test.xcscheme +++ b/platform/macos/macos.xcworkspace/xcshareddata/xcschemes/test.xcscheme @@ -17,7 +17,7 @@ BlueprintIdentifier = "DC37A7F85AC5E5958672B4F8" BuildableName = "test" BlueprintName = "test" - ReferencedContainer = "container:../../build/osx/platform/osx/platform.xcodeproj"> + ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj"> @@ -35,7 +35,7 @@ BlueprintIdentifier = "DC37A7F85AC5E5958672B4F8" BuildableName = "test" BlueprintName = "test" - ReferencedContainer = "container:../../build/osx/platform/osx/platform.xcodeproj"> + ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj"> @@ -59,7 +59,7 @@ BlueprintIdentifier = "DC37A7F85AC5E5958672B4F8" BuildableName = "test" BlueprintName = "test" - ReferencedContainer = "container:../../build/osx/platform/osx/platform.xcodeproj"> + ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj"> @@ -78,7 +78,7 @@ BlueprintIdentifier = "DC37A7F85AC5E5958672B4F8" BuildableName = "test" BlueprintName = "test" - ReferencedContainer = "container:../../build/osx/platform/osx/platform.xcodeproj"> + ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj"> diff --git a/platform/osx/platform.gyp b/platform/macos/platform.gyp similarity index 96% rename from platform/osx/platform.gyp rename to platform/macos/platform.gyp index c3f94935d..f748708b2 100644 --- a/platform/osx/platform.gyp +++ b/platform/macos/platform.gyp @@ -5,7 +5,7 @@ 'coverage': 0, }, 'includes': [ - '../../build/osx/config.gypi', + '../../build/macos/config.gypi', '../../mbgl.gypi', '../../test/test.gypi', '../../bin/glfw.gypi', @@ -28,7 +28,7 @@ }, { 'target_name': 'platform-lib', - 'product_name': 'mbgl-platform-osx', + 'product_name': 'mbgl-platform-macos', 'type': 'static_library', 'standalone_static_library': 1, 'hard_dependency': 1, diff --git a/platform/osx/screenshot.png b/platform/macos/screenshot.png similarity index 100% rename from platform/osx/screenshot.png rename to platform/macos/screenshot.png diff --git a/platform/osx/scripts/configure.sh b/platform/macos/scripts/configure.sh similarity index 100% rename from platform/osx/scripts/configure.sh rename to platform/macos/scripts/configure.sh diff --git a/platform/osx/scripts/document.sh b/platform/macos/scripts/document.sh similarity index 67% rename from platform/osx/scripts/document.sh rename to platform/macos/scripts/document.sh index 5559d858c..e62a1e166 100755 --- a/platform/osx/scripts/document.sh +++ b/platform/macos/scripts/document.sh @@ -8,32 +8,32 @@ if [ -z `which jazzy` ]; then echo "Installing jazzy…" gem install jazzy if [ -z `which jazzy` ]; then - echo "Unable to install jazzy. See https://github.com/mapbox/mapbox-gl-native/blob/master/platform/osx/INSTALL.md" + echo "Unable to install jazzy. See https://github.com/mapbox/mapbox-gl-native/blob/master/platform/macos/INSTALL.md" exit 1 fi fi OUTPUT=${OUTPUT:-documentation} -BRANCH=$( git describe --tags --match=osx-v*.*.* --abbrev=0 ) -SHORT_VERSION=$( echo ${BRANCH} | sed 's/^osx-v//' ) -RELEASE_VERSION=$( echo ${SHORT_VERSION} | sed -e 's/^osx-v//' -e 's/-.*//' ) +BRANCH=$( git describe --tags --match=macos-v*.*.* --abbrev=0 ) +SHORT_VERSION=$( echo ${BRANCH} | sed 's/^macos-v//' ) +RELEASE_VERSION=$( echo ${SHORT_VERSION} | sed -e 's/^macos-v//' -e 's/-.*//' ) SWIFT_VERSION=$(xcrun swift -version | head -n 1 | sed -e 's/^Apple Swift version //' -e 's/ .*$//') rm -rf /tmp/mbgl mkdir -p /tmp/mbgl/ README=/tmp/mbgl/README.md -cp platform/osx/docs/doc-README.md "${README}" +cp platform/macos/docs/doc-README.md "${README}" # http://stackoverflow.com/a/4858011/4585461 echo "## Changes in version ${RELEASE_VERSION}" >> "${README}" -sed -n -e '/^## /{' -e ':a' -e 'n' -e '/^##/q' -e 'p' -e 'ba' -e '}' platform/osx/CHANGELOG.md >> "${README}" +sed -n -e '/^## /{' -e ':a' -e 'n' -e '/^##/q' -e 'p' -e 'ba' -e '}' platform/macos/CHANGELOG.md >> "${README}" rm -rf ${OUTPUT} mkdir -p ${OUTPUT} jazzy \ - --config platform/osx/jazzy.yml \ + --config platform/macos/jazzy.yml \ --sdk macosx \ --swift-version $SWIFT_VERSION \ --github-file-prefix https://github.com/mapbox/mapbox-gl-native/tree/${BRANCH} \ @@ -42,4 +42,4 @@ jazzy \ --output ${OUTPUT} # https://github.com/realm/jazzy/issues/411 find ${OUTPUT} -name *.html -exec \ - perl -pi -e 's/Mapbox\s+(Docs|Reference)/Mapbox OS X SDK $1/' {} \; + perl -pi -e 's/Mapbox\s+(Docs|Reference)/Mapbox macOS SDK $1/' {} \; diff --git a/platform/osx/scripts/osxtest.xcscheme b/platform/macos/scripts/macostest.xcscheme similarity index 89% rename from platform/osx/scripts/osxtest.xcscheme rename to platform/macos/scripts/macostest.xcscheme index 506070361..ba6f6a6f4 100644 --- a/platform/osx/scripts/osxtest.xcscheme +++ b/platform/macos/scripts/macostest.xcscheme @@ -17,9 +17,9 @@ + BuildableName = "macostest.xctest" + BlueprintName = "macostest" + ReferencedContainer = "container:../../build/macos/platform/macos/platform.xcodeproj"> diff --git a/platform/osx/scripts/package.sh b/platform/macos/scripts/package.sh similarity index 82% rename from platform/osx/scripts/package.sh rename to platform/macos/scripts/package.sh index 130443083..a6952e8ab 100755 --- a/platform/osx/scripts/package.sh +++ b/platform/macos/scripts/package.sh @@ -5,8 +5,8 @@ set -o pipefail set -u NAME=Mapbox -OUTPUT=build/osx/pkg -DERIVED_DATA=build/osx +OUTPUT=build/macos/pkg +DERIVED_DATA=build/macos PRODUCTS=${DERIVED_DATA}/Build/Products BUILDTYPE=${BUILDTYPE:-Release} @@ -20,7 +20,7 @@ rm -rf ${OUTPUT} HASH=`git log | head -1 | awk '{ print $2 }' | cut -c 1-10` && true PROJ_VERSION=$(git rev-list --count HEAD) -SEM_VERSION=$( git describe --tags --match=osx-v*.*.* --abbrev=0 | sed 's/^osx-v//' ) +SEM_VERSION=$( git describe --tags --match=macos-v*.*.* --abbrev=0 | sed 's/^macos-v//' ) SHORT_VERSION=${SEM_VERSION%-*} step "Building targets (build ${PROJ_VERSION}, version ${SEM_VERSION})…" @@ -31,7 +31,7 @@ xcodebuild \ CURRENT_SEMANTIC_VERSION=${SEM_VERSION} \ CURRENT_COMMIT_HASH=${HASH} \ -derivedDataPath ${DERIVED_DATA} \ - -workspace ./platform/osx/osx.xcworkspace \ + -workspace ./platform/macos/macos.xcworkspace \ -scheme dynamic \ -configuration ${BUILDTYPE} \ -jobs ${JOBS} | xcpretty @@ -50,8 +50,8 @@ fi step "Copying library resources…" cp -pv LICENSE.md "${OUTPUT}" -cp -pv platform/osx/docs/pod-README.md "${OUTPUT}/README.md" -sed -n -e '/^## /,$p' platform/osx/CHANGELOG.md > "${OUTPUT}/CHANGELOG.md" +cp -pv platform/macos/docs/pod-README.md "${OUTPUT}/README.md" +sed -n -e '/^## /,$p' platform/macos/CHANGELOG.md > "${OUTPUT}/CHANGELOG.md" step "Generating API documentation…" make xdocument OUTPUT="${OUTPUT}/documentation" diff --git a/platform/osx/sdk/Base.lproj/Localizable.strings b/platform/macos/sdk/Base.lproj/Localizable.strings similarity index 100% rename from platform/osx/sdk/Base.lproj/Localizable.strings rename to platform/macos/sdk/Base.lproj/Localizable.strings diff --git a/platform/osx/sdk/Base.lproj/MGLAnnotationCallout.xib b/platform/macos/sdk/Base.lproj/MGLAnnotationCallout.xib similarity index 100% rename from platform/osx/sdk/Base.lproj/MGLAnnotationCallout.xib rename to platform/macos/sdk/Base.lproj/MGLAnnotationCallout.xib diff --git a/platform/osx/sdk/Info.plist b/platform/macos/sdk/Info.plist similarity index 100% rename from platform/osx/sdk/Info.plist rename to platform/macos/sdk/Info.plist diff --git a/platform/osx/sdk/default_marker.pdf b/platform/macos/sdk/default_marker.pdf similarity index 100% rename from platform/osx/sdk/default_marker.pdf rename to platform/macos/sdk/default_marker.pdf diff --git a/platform/osx/sdk/mapbox.pdf b/platform/macos/sdk/mapbox.pdf similarity index 100% rename from platform/osx/sdk/mapbox.pdf rename to platform/macos/sdk/mapbox.pdf diff --git a/platform/osx/src/MGLAnnotationImage.h b/platform/macos/src/MGLAnnotationImage.h similarity index 100% rename from platform/osx/src/MGLAnnotationImage.h rename to platform/macos/src/MGLAnnotationImage.h diff --git a/platform/osx/src/MGLAnnotationImage.m b/platform/macos/src/MGLAnnotationImage.m similarity index 100% rename from platform/osx/src/MGLAnnotationImage.m rename to platform/macos/src/MGLAnnotationImage.m diff --git a/platform/osx/src/MGLAnnotationImage_Private.h b/platform/macos/src/MGLAnnotationImage_Private.h similarity index 100% rename from platform/osx/src/MGLAnnotationImage_Private.h rename to platform/macos/src/MGLAnnotationImage_Private.h diff --git a/platform/osx/src/MGLAttributionButton.h b/platform/macos/src/MGLAttributionButton.h similarity index 100% rename from platform/osx/src/MGLAttributionButton.h rename to platform/macos/src/MGLAttributionButton.h diff --git a/platform/osx/src/MGLAttributionButton.m b/platform/macos/src/MGLAttributionButton.m similarity index 100% rename from platform/osx/src/MGLAttributionButton.m rename to platform/macos/src/MGLAttributionButton.m diff --git a/platform/osx/src/MGLCompassCell.h b/platform/macos/src/MGLCompassCell.h similarity index 100% rename from platform/osx/src/MGLCompassCell.h rename to platform/macos/src/MGLCompassCell.h diff --git a/platform/osx/src/MGLCompassCell.m b/platform/macos/src/MGLCompassCell.m similarity index 100% rename from platform/osx/src/MGLCompassCell.m rename to platform/macos/src/MGLCompassCell.m diff --git a/platform/osx/src/MGLMapView+IBAdditions.h b/platform/macos/src/MGLMapView+IBAdditions.h similarity index 100% rename from platform/osx/src/MGLMapView+IBAdditions.h rename to platform/macos/src/MGLMapView+IBAdditions.h diff --git a/platform/osx/src/MGLMapView+IBAdditions.m b/platform/macos/src/MGLMapView+IBAdditions.m similarity index 100% rename from platform/osx/src/MGLMapView+IBAdditions.m rename to platform/macos/src/MGLMapView+IBAdditions.m diff --git a/platform/osx/src/MGLMapView.h b/platform/macos/src/MGLMapView.h similarity index 100% rename from platform/osx/src/MGLMapView.h rename to platform/macos/src/MGLMapView.h diff --git a/platform/osx/src/MGLMapView.mm b/platform/macos/src/MGLMapView.mm similarity index 99% rename from platform/osx/src/MGLMapView.mm rename to platform/macos/src/MGLMapView.mm index 5b85ff7ec..fe75b833e 100644 --- a/platform/osx/src/MGLMapView.mm +++ b/platform/macos/src/MGLMapView.mm @@ -507,17 +507,17 @@ public: #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundeclared-selector" if ([self.delegate respondsToSelector:@selector(mapView:regionWillChangeAnimated:)]) { - NSLog(@"-mapView:regionWillChangeAnimated: is not supported by the OS X SDK, but %@ implements it anyways. " + NSLog(@"-mapView:regionWillChangeAnimated: is not supported by the macOS SDK, but %@ implements it anyways. " @"Please implement -[%@ mapView:cameraWillChangeAnimated:] instead.", NSStringFromClass([delegate class]), NSStringFromClass([delegate class])); } if ([self.delegate respondsToSelector:@selector(mapViewRegionIsChanging:)]) { - NSLog(@"-mapViewRegionIsChanging: is not supported by the OS X SDK, but %@ implements it anyways. " + NSLog(@"-mapViewRegionIsChanging: is not supported by the macOS SDK, but %@ implements it anyways. " @"Please implement -[%@ mapViewCameraIsChanging:] instead.", NSStringFromClass([delegate class]), NSStringFromClass([delegate class])); } if ([self.delegate respondsToSelector:@selector(mapView:regionDidChangeAnimated:)]) { - NSLog(@"-mapView:regionDidChangeAnimated: is not supported by the OS X SDK, but %@ implements it anyways. " + NSLog(@"-mapView:regionDidChangeAnimated: is not supported by the macOS SDK, but %@ implements it anyways. " @"Please implement -[%@ mapView:cameraDidChangeAnimated:] instead.", NSStringFromClass([delegate class]), NSStringFromClass([delegate class])); } diff --git a/platform/osx/src/MGLMapViewDelegate.h b/platform/macos/src/MGLMapViewDelegate.h similarity index 100% rename from platform/osx/src/MGLMapViewDelegate.h rename to platform/macos/src/MGLMapViewDelegate.h diff --git a/platform/osx/src/MGLMapView_Private.h b/platform/macos/src/MGLMapView_Private.h similarity index 100% rename from platform/osx/src/MGLMapView_Private.h rename to platform/macos/src/MGLMapView_Private.h diff --git a/platform/osx/src/MGLOpenGLLayer.h b/platform/macos/src/MGLOpenGLLayer.h similarity index 100% rename from platform/osx/src/MGLOpenGLLayer.h rename to platform/macos/src/MGLOpenGLLayer.h diff --git a/platform/osx/src/MGLOpenGLLayer.mm b/platform/macos/src/MGLOpenGLLayer.mm similarity index 100% rename from platform/osx/src/MGLOpenGLLayer.mm rename to platform/macos/src/MGLOpenGLLayer.mm diff --git a/platform/osx/src/Mapbox.h b/platform/macos/src/Mapbox.h similarity index 100% rename from platform/osx/src/Mapbox.h rename to platform/macos/src/Mapbox.h diff --git a/platform/osx/test/Info.plist b/platform/macos/test/Info.plist similarity index 100% rename from platform/osx/test/Info.plist rename to platform/macos/test/Info.plist diff --git a/platform/node/README.md b/platform/node/README.md index 1a18c61d0..4928ba386 100644 --- a/platform/node/README.md +++ b/platform/node/README.md @@ -8,8 +8,8 @@ Requires a modern C++ runtime that supports C++14. By default, installs binaries. On these platforms no additional dependencies are needed. -- 64 bit OS X or 64 bit Linux -- Node.js v4+ +- 64 bit macOS or 64 bit Linux +- Node.js v4.x _(note: v5+ is known to have issues)_ Just run: diff --git a/platform/node/bitrise.yml b/platform/node/bitrise.yml index dde34c6c6..b43b85d69 100644 --- a/platform/node/bitrise.yml +++ b/platform/node/bitrise.yml @@ -43,8 +43,8 @@ workflows: inputs: - webhook_url: "$SLACK_HOOK_URL" - channel: "#gl-bots" - - from_username: 'Bitrise Node OS X' - - from_username_on_error: 'Bitrise Node OS X' + - from_username: 'Bitrise Node macOS' + - from_username_on_error: 'Bitrise Node macOS' - message: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}> for by ${GIT_CLONE_COMMIT_COMMITER_NAME} diff --git a/platform/osx/docs/doc-README.md b/platform/osx/docs/doc-README.md deleted file mode 100644 index 1e9619766..000000000 --- a/platform/osx/docs/doc-README.md +++ /dev/null @@ -1,9 +0,0 @@ -# [Mapbox OS X SDK](https://github.com/mapbox/mapbox-gl-native/tree/master/platform/osx/) - -The Mapbox OS X SDK is an open-source framework for embedding interactive map views with scalable, customizable vector maps into Cocoa applications on OS X 10.10.0 and above using Objective-C, Swift, or Interface Builder. It takes stylesheets that conform to the [Mapbox GL Style Specification](https://www.mapbox.com/mapbox-gl-style-spec/), applies them to vector tiles that conform to the [Mapbox Vector Tile Specification](https://www.mapbox.com/developers/vector-tiles/), and renders them using OpenGL. - - - -For setup information, consult the README.md that comes with this documentation. The [Mapbox iOS SDK](https://www.mapbox.com/ios-sdk/)’s [API documentation](https://www.mapbox.com/ios-sdk/api/) and [online examples](https://www.mapbox.com/ios-sdk/examples/) apply to the Mapbox OS X SDK with few differences, mostly around unimplemented features like user location tracking. A [full changelog](https://github.com/mapbox/mapbox-gl-native/blob/master/platform/osx/CHANGELOG.md) is also available. - -Mapbox does not officially support the OS X SDK to the same extent as the iOS SDK; however, [bug reports and pull requests](https://github.com/mapbox/mapbox-gl-native/issues/) are certainly welcome. diff --git a/platform/qt/README.md b/platform/qt/README.md index 56f9301b3..97662f5ff 100644 --- a/platform/qt/README.md +++ b/platform/qt/README.md @@ -18,7 +18,7 @@ example](https://c2.staticflickr.com/8/7689/26247088394_01541b34de_o.png) ### Developing [Qt supports many platforms](https://www.qt.io/qt-framework/#section-4) - so far -we have been testing our code on Linux and OS X desktops, as well as embedded +we have been testing our code on Linux and macOS desktops, as well as embedded devices such as Raspberry Pi 3. If you need to maintain backwards compatibility with prior releases of @@ -46,9 +46,9 @@ you also need: qml-module-qtquick2 qml-module-qtpositioning qml-module-qtgraphicaleffects \ qml-module-qtquick-layouts qml-module-qtquick-controls -#### OS X +#### macOS -For OS X desktop, you can install Qt 5 via [Homebrew](http://brew.sh): +For macOS desktop, you can install Qt 5 via [Homebrew](http://brew.sh): brew install qt5 diff --git a/platform/qt/bitrise-qt4.yml b/platform/qt/bitrise-qt4.yml index 83c222a9d..24e0f4493 100644 --- a/platform/qt/bitrise-qt4.yml +++ b/platform/qt/bitrise-qt4.yml @@ -42,8 +42,8 @@ workflows: inputs: - webhook_url: "$SLACK_HOOK_URL" - channel: "#gl-bots" - - from_username: 'Bitrise Qt4 OS X' - - from_username_on_error: 'Bitrise Qt4 OS X' + - from_username: 'Bitrise Qt4 macOS' + - from_username_on_error: 'Bitrise Qt4 macOS' - message: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}> for by ${GIT_CLONE_COMMIT_COMMITER_NAME} diff --git a/platform/qt/bitrise-qt5.yml b/platform/qt/bitrise-qt5.yml index 1e767b316..18fa44dd2 100644 --- a/platform/qt/bitrise-qt5.yml +++ b/platform/qt/bitrise-qt5.yml @@ -43,8 +43,8 @@ workflows: inputs: - webhook_url: "$SLACK_HOOK_URL" - channel: "#gl-bots" - - from_username: 'Bitrise Qt5 OS X' - - from_username_on_error: 'Bitrise Qt5 OS X' + - from_username: 'Bitrise Qt5 macOS' + - from_username_on_error: 'Bitrise Qt5 macOS' - message: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}> for by ${GIT_CLONE_COMMIT_COMMITER_NAME} diff --git a/scripts/collect-coverage.sh b/scripts/collect-coverage.sh index 35a9b8cd5..efc93769f 100755 --- a/scripts/collect-coverage.sh +++ b/scripts/collect-coverage.sh @@ -15,7 +15,7 @@ function usage() { if [ `uname -s` = 'Linux' ]; then echo "On Debian-based distros, you can install them via 'apt-get install lcov'" elif [ `uname -s` = 'Darwin' ]; then - echo "On OS X, you can install them via 'brew install lcov'" + echo "On macOS, you can install them via 'brew install lcov'" fi exit 1 } From f470208f6e784cfbc2581775b24a3b70b6f08f99 Mon Sep 17 00:00:00 2001 From: Justas Medeisis Date: Mon, 13 Jun 2016 22:10:29 +0300 Subject: [PATCH 13/43] [android] #5335 - Always record latest accelerometer and magnetometer sensor values regardless of MyLocationView update throttling. --- .../mapboxsdk/maps/widgets/MyLocationView.java | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java index 12240aee8..2751fe86c 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java @@ -526,24 +526,19 @@ public class MyLocationView extends View { return; } - long currentTime = SystemClock.elapsedRealtime(); - if (currentTime < mCompassUpdateNextTimestamp) { - return; - } - int type = event.sensor.getType(); - float[] data; if (type == Sensor.TYPE_ACCELEROMETER) { - data = mGData; + System.arraycopy(event.values, 0, mGData, 0, 3); } else if (type == Sensor.TYPE_MAGNETIC_FIELD) { - data = mMData; + System.arraycopy(event.values, 0, mMData, 0, 3); } else { // we should not be here. return; } - for (int i = 0; i < 3; i++) { - data[i] = event.values[i]; + long currentTime = SystemClock.elapsedRealtime(); + if (currentTime < mCompassUpdateNextTimestamp) { + return; } SensorManager.getRotationMatrix(mR, mI, mGData, mMData); From ce2ccf9c3fa27ee7b6693b4cb73562701c80771e Mon Sep 17 00:00:00 2001 From: Justas Medeisis Date: Mon, 13 Jun 2016 22:16:04 +0300 Subject: [PATCH 14/43] [android] #5335 - Invalidate MyLocationView during bearing indicator animation. --- .../mapbox/mapboxsdk/maps/widgets/MyLocationView.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java index 2751fe86c..49141d338 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/widgets/MyLocationView.java @@ -67,6 +67,14 @@ public class MyLocationView extends View { private ValueAnimator accuracyAnimator; private ValueAnimator directionAnimator; + private ValueAnimator.AnimatorUpdateListener invalidateSelfOnUpdateListener = + new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + invalidate(); + } + }; + private Drawable foregroundDrawable; private Drawable foregroundBearingDrawable; private Drawable backgroundDrawable; @@ -444,6 +452,7 @@ public class MyLocationView extends View { directionAnimator = ValueAnimator.ofFloat(oldDir, newDir); directionAnimator.setDuration(375); + directionAnimator.addUpdateListener(invalidateSelfOnUpdateListener); directionAnimator.start(); } From 2f8fd61ac7378d362fa8c0f579691b0ed637d637 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 17 Jun 2016 13:08:32 +0200 Subject: [PATCH 15/43] [android #4700 - remove deprecation MyLocationListener --- .../src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index 72eabf579..f11d46dba 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -39,7 +39,6 @@ import com.mapbox.mapboxsdk.constants.MyLocationTracking; import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.layers.CustomLayer; -import com.mapbox.mapboxsdk.location.LocationListener; import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings; import java.lang.reflect.ParameterizedType; @@ -1539,10 +1538,8 @@ public class MapboxMap { * * @param listener The callback that's invoked when the user clicks on a marker. * To unset the callback, use null. - * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.location.LocationServices#addLocationListener(LocationListener)})} */ @UiThread - @Deprecated public void setOnMyLocationChangeListener(@Nullable MapboxMap.OnMyLocationChangeListener listener) { mMapView.setOnMyLocationChangeListener(listener); } @@ -1951,7 +1948,6 @@ public class MapboxMap { * Interface definition for a callback to be invoked when the the My Location view changes location. * * @see MapboxMap#setOnMyLocationChangeListener(OnMyLocationChangeListener) - * @deprecated As of release 4.1.0, replaced by {@link com.mapbox.mapboxsdk.location.LocationListener} */ @Deprecated public interface OnMyLocationChangeListener { From 27da49c5fb72dd4e3f2c7237c3e4f73fe56c73a2 Mon Sep 17 00:00:00 2001 From: Antonio Zugaldia Date: Thu, 9 Jun 2016 15:15:44 -0400 Subject: [PATCH 16/43] first approach to a marker continuosly chasing another --- .../mapboxsdk/annotations/MarkerView.java | 12 ++ .../annotation/AnimatedMarkerActivity.java | 127 ++++++++++++++++-- .../drawable/ic_directions_car_black_24dp.xml | 9 ++ .../drawable/ic_directions_run_black_24dp.xml | 9 ++ 4 files changed, 144 insertions(+), 13 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black_24dp.xml create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml 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 580c3796d..ba7d58b83 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 @@ -12,6 +12,7 @@ import android.view.animation.AnimationUtils; import com.mapbox.mapboxsdk.constants.MapboxConstants; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.utils.AnimatorUtils; /** * MarkerView is an annotation that shows an View at a geographical location. @@ -55,6 +56,7 @@ public class MarkerView extends Marker { private long startTime; private long duration; private long remainingTime; + private AnimatorUtils.OnAnimationEndListener animationEndListener; /** * Publicly hidden default constructor @@ -358,6 +360,12 @@ public class MarkerView extends Marker { } public void setPosition(LatLng position, long duration) { + setPosition(position, duration, null); + } + + public void setPosition(LatLng position, long duration, AnimatorUtils.OnAnimationEndListener animationEndListener) { + this.animationEndListener = animationEndListener; + if (duration <= 0) { // update position instantly super.setPosition(position); @@ -414,6 +422,10 @@ public class MarkerView extends Marker { this.startTime = startTime; } + AnimatorUtils.OnAnimationEndListener getAnimationEndListener() { + return animationEndListener; + } + PointF getScreenLocation(@NonNull View convertView) { return new PointF(convertView.getX() + offsetX, convertView.getY() + offsetY); } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java index bbd7428ea..8a8a2a558 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java @@ -1,26 +1,42 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation; +import android.animation.Animator; import android.animation.TypeEvaluator; import android.os.Bundle; -import android.os.Handler; import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; +import android.util.Log; import android.view.Menu; import android.view.MenuItem; +import android.view.animation.LinearInterpolator; -import com.mapbox.mapboxsdk.annotations.MarkerView; +import com.mapbox.mapboxsdk.annotations.Icon; +import com.mapbox.mapboxsdk.annotations.IconFactory; +import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.MarkerViewOptions; +import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.geometry.LatLngBounds; import com.mapbox.mapboxsdk.maps.MapView; import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.testapp.R; +import java.util.Random; + public class AnimatedMarkerActivity extends AppCompatActivity { + private final static String LOG_TAG = "AnimatedMarkerActivity"; + private MapView mMapView; + private MapboxMap mMapboxMap; + + private LatLng dupontCircle = new LatLng(38.90962, -77.04341); + + private Marker passengerMarker = null; + private Marker carMarker = null; @Override protected void onCreate(Bundle savedInstanceState) { @@ -39,24 +55,109 @@ public class AnimatedMarkerActivity extends AppCompatActivity { mMapView = (MapView) findViewById(R.id.mapView); mMapView.onCreate(savedInstanceState); mMapView.getMapAsync(new OnMapReadyCallback() { + @Override public void onMapReady(@NonNull final MapboxMap mapboxMap) { + mMapboxMap = mapboxMap; + setupMap(); - LatLng brussels = new LatLng(50.900446, 4.485251); - final MarkerView marker = mapboxMap.addMarker(new MarkerViewOptions().position(brussels)); - - // FIXME workaround because view is not actually added at this time - final LatLng utrecht = new LatLng(52.086224, 5.122309); - new Handler().postDelayed(new Runnable() { - @Override - public void run() { - marker.setPosition(utrecht, 6500l /*animation duration*/); - } - }, 1000); + addPassenger(); + addCar(); + animateMarker(carMarker, carMarker.getPosition(), passengerMarker.getPosition()); } }); } + private void setupMap() { + CameraPosition cameraPosition = new CameraPosition.Builder() + .target(dupontCircle) + .zoom(15) + .build(); + mMapboxMap.setCameraPosition(cameraPosition); + } + + private void addPassenger() { + LatLng randomLatLng = getLatLngInBounds(); + + if (passengerMarker == null) { + Icon icon = IconFactory.getInstance(AnimatedMarkerActivity.this) + .fromResource(R.drawable.ic_directions_run_black_24dp); + passengerMarker = mMapboxMap.addMarker(new MarkerViewOptions() + .position(randomLatLng) + .icon(icon)); + } else { + passengerMarker.setPosition(randomLatLng); + } + } + + private void addCar() { + LatLng randomLatLng = getLatLngInBounds(); + + if (carMarker == null) { + Icon icon = IconFactory.getInstance(AnimatedMarkerActivity.this) + .fromResource(R.drawable.ic_directions_car_black_24dp); + carMarker = mMapboxMap.addMarker(new MarkerViewOptions() + .position(randomLatLng) + .icon(icon)); + } else { + carMarker.setPosition(randomLatLng); + } + + // Make sure the car marker is selected so that it's always brought to the front (#5285) + mMapboxMap.selectMarker(carMarker); + } + + private LatLng getLatLngInBounds() { + LatLngBounds bounds = mMapboxMap.getProjection().getVisibleRegion().latLngBounds; + Random generator = new Random(); + double randomLat = bounds.getLatSouth() + generator.nextDouble() * (bounds.getLatNorth() - bounds.getLatSouth()); + double randomLon = bounds.getLonWest() + generator.nextDouble() * (bounds.getLonEast() - bounds.getLonWest()); + return new LatLng(randomLat, randomLon); + } + + private void animateMarker(final Marker marker, LatLng from, LatLng to) { + ValueAnimator markerAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), (Object[]) new LatLng[]{from, to}); + markerAnimator.setDuration(5000); + markerAnimator.setInterpolator(new LinearInterpolator()); + + markerAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + if (marker != null) { + marker.setPosition((LatLng) animation.getAnimatedValue()); + } + } + }); + + markerAnimator.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + // Nothing + } + + @Override + public void onAnimationEnd(Animator animation) { + Log.d(LOG_TAG, "Animation ended."); + + addPassenger(); + animateMarker(carMarker, carMarker.getPosition(), passengerMarker.getPosition()); + } + + @Override + public void onAnimationCancel(Animator animation) { + // Nothing + } + + @Override + public void onAnimationRepeat(Animator animation) { + // Nothing + } + }); + + // Start + markerAnimator.start(); + } + @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_zoom, menu); diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black_24dp.xml new file mode 100644 index 000000000..6d6337c3a --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_car_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml new file mode 100644 index 000000000..d18f6a17c --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml @@ -0,0 +1,9 @@ + + + From fa0e3df981a6b6cbe9ae64564f3985a6fe34f5c7 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Fri, 10 Jun 2016 13:31:57 +0200 Subject: [PATCH 17/43] [android] #5299 - Simplify animation code a bit. Make duration dependent on distance. Use non-linear interpolator. --- .../annotation/AnimatedMarkerActivity.java | 43 ++++++------------- 1 file changed, 14 insertions(+), 29 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java index 8a8a2a558..284218872 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java @@ -1,6 +1,8 @@ package com.mapbox.mapboxsdk.testapp.activity.annotation; import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.ObjectAnimator; import android.animation.TypeEvaluator; import android.os.Bundle; import android.support.annotation.NonNull; @@ -10,7 +12,7 @@ import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.Menu; import android.view.MenuItem; -import android.view.animation.LinearInterpolator; +import android.view.animation.AccelerateDecelerateInterpolator; import com.mapbox.mapboxsdk.annotations.Icon; import com.mapbox.mapboxsdk.annotations.IconFactory; @@ -116,24 +118,13 @@ public class AnimatedMarkerActivity extends AppCompatActivity { } private void animateMarker(final Marker marker, LatLng from, LatLng to) { - ValueAnimator markerAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), (Object[]) new LatLng[]{from, to}); - markerAnimator.setDuration(5000); - markerAnimator.setInterpolator(new LinearInterpolator()); - markerAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { - @Override - public void onAnimationUpdate(ValueAnimator animation) { - if (marker != null) { - marker.setPosition((LatLng) animation.getAnimatedValue()); - } - } - }); + final ValueAnimator markerAnimator = ObjectAnimator.ofObject(marker, "position", new LatLngEvaluator(), from, to); + markerAnimator.setDuration((long) (10 * from.distanceTo(to))); + markerAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); - markerAnimator.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - // Nothing - } + //Add listener to restart animation on end + markerAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -143,15 +134,6 @@ public class AnimatedMarkerActivity extends AppCompatActivity { animateMarker(carMarker, carMarker.getPosition(), passengerMarker.getPosition()); } - @Override - public void onAnimationCancel(Animator animation) { - // Nothing - } - - @Override - public void onAnimationRepeat(Animator animation) { - // Nothing - } }); // Start @@ -205,14 +187,17 @@ public class AnimatedMarkerActivity extends AppCompatActivity { mMapView.onLowMemory(); } - private class LatLngEvaluator implements TypeEvaluator { + /** + * Evaluator for LatLng pairs + */ + private static class LatLngEvaluator implements TypeEvaluator { private LatLng mLatLng = new LatLng(); @Override public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) { - mLatLng.setLatitude(startValue.getLatitude() + (endValue.getLatitude() - startValue.getLatitude()) * fraction); - mLatLng.setLongitude(startValue.getLongitude() + (endValue.getLongitude() - startValue.getLongitude()) * fraction); + mLatLng.setLatitude(startValue.getLatitude() + ((endValue.getLatitude() - startValue.getLatitude()) * fraction)); + mLatLng.setLongitude(startValue.getLongitude() + ((endValue.getLongitude() - startValue.getLongitude()) * fraction)); return mLatLng; } } From 8e9b158e7347c00465d99f30f1220dff6c375178 Mon Sep 17 00:00:00 2001 From: Ivo van Dongen Date: Fri, 10 Jun 2016 18:38:22 +0200 Subject: [PATCH 18/43] [android] #5299 - Added more cars to the animation example to see what impact it has --- .../annotation/AnimatedMarkerActivity.java | 100 ++++++++++++------ 1 file changed, 68 insertions(+), 32 deletions(-) diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java index 284218872..76e662d6a 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java @@ -9,7 +9,6 @@ import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; -import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.animation.AccelerateDecelerateInterpolator; @@ -17,6 +16,7 @@ import android.view.animation.AccelerateDecelerateInterpolator; import com.mapbox.mapboxsdk.annotations.Icon; import com.mapbox.mapboxsdk.annotations.IconFactory; import com.mapbox.mapboxsdk.annotations.Marker; +import com.mapbox.mapboxsdk.annotations.MarkerOptions; import com.mapbox.mapboxsdk.annotations.MarkerViewOptions; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.geometry.LatLng; @@ -64,8 +64,13 @@ public class AnimatedMarkerActivity extends AppCompatActivity { setupMap(); addPassenger(); - addCar(); - animateMarker(carMarker, carMarker.getPosition(), passengerMarker.getPosition()); + addMainCar(); + animateMoveToPassenger(carMarker); + + for (int i = 0; i < 10; i++) { + addRandomCar(); + } + } }); } @@ -92,15 +97,11 @@ public class AnimatedMarkerActivity extends AppCompatActivity { } } - private void addCar() { + private void addMainCar() { LatLng randomLatLng = getLatLngInBounds(); if (carMarker == null) { - Icon icon = IconFactory.getInstance(AnimatedMarkerActivity.this) - .fromResource(R.drawable.ic_directions_car_black_24dp); - carMarker = mMapboxMap.addMarker(new MarkerViewOptions() - .position(randomLatLng) - .icon(icon)); + carMarker = createCarMarker(randomLatLng); } else { carMarker.setPosition(randomLatLng); } @@ -109,6 +110,64 @@ public class AnimatedMarkerActivity extends AppCompatActivity { mMapboxMap.selectMarker(carMarker); } + private void animateMoveToPassenger(final Marker car) { + + ValueAnimator animator = animateMoveMarker(car, passengerMarker.getPosition()); + animator.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + addPassenger(); + animateMoveToPassenger(car); + } + }); + } + + protected void addRandomCar() { + Marker car = createCarMarker(getLatLngInBounds()); + randomlyMoveMarker(car); + } + + private void randomlyMoveMarker(final Marker marker) { + ValueAnimator animator = animateMoveMarker(marker, getLatLngInBounds()); + + //Add listener to restart animation on end + animator.addListener(new AnimatorListenerAdapter() { + + @Override + public void onAnimationEnd(Animator animation) { + randomlyMoveMarker(marker); + } + + }); + } + + private ValueAnimator animateMoveMarker(final Marker marker, LatLng to) { + final ValueAnimator markerAnimator = ObjectAnimator.ofObject(marker, "position", new LatLngEvaluator(), marker.getPosition(), to); + markerAnimator.setDuration((long) (10 * marker.getPosition().distanceTo(to))); + markerAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); + + // Start + markerAnimator.start(); + + return markerAnimator; + } + + private Marker createCarMarker(LatLng start) { + Icon icon = IconFactory.getInstance(AnimatedMarkerActivity.this) + .fromResource(R.drawable.ic_directions_car_black_24dp); + + //View Markers + return mMapboxMap.addMarker(new MarkerViewOptions() + .position(start) + .icon(icon)); + + //GL Markers +// return mMapboxMap.addMarker(new MarkerOptions() +// .position(start) +// .icon(icon)); + + } + private LatLng getLatLngInBounds() { LatLngBounds bounds = mMapboxMap.getProjection().getVisibleRegion().latLngBounds; Random generator = new Random(); @@ -117,29 +176,6 @@ public class AnimatedMarkerActivity extends AppCompatActivity { return new LatLng(randomLat, randomLon); } - private void animateMarker(final Marker marker, LatLng from, LatLng to) { - - final ValueAnimator markerAnimator = ObjectAnimator.ofObject(marker, "position", new LatLngEvaluator(), from, to); - markerAnimator.setDuration((long) (10 * from.distanceTo(to))); - markerAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); - - //Add listener to restart animation on end - markerAnimator.addListener(new AnimatorListenerAdapter() { - - @Override - public void onAnimationEnd(Animator animation) { - Log.d(LOG_TAG, "Animation ended."); - - addPassenger(); - animateMarker(carMarker, carMarker.getPosition(), passengerMarker.getPosition()); - } - - }); - - // Start - markerAnimator.start(); - } - @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.menu_zoom, menu); From 8c83af7b977d1091e3e3c35a47bce451488ba080 Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 17 Jun 2016 16:05:45 +0200 Subject: [PATCH 19/43] [android] #5299 - remove MarkerView x,y animation --- .../mapboxsdk/annotations/MarkerView.java | 86 ------------ .../annotations/MarkerViewManager.java | 128 +++--------------- .../com/mapbox/mapboxsdk/maps/MapboxMap.java | 2 +- .../annotation/AnimatedMarkerActivity.java | 4 +- 4 files changed, 20 insertions(+), 200 deletions(-) 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 ba7d58b83..cee634c43 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 @@ -48,16 +48,6 @@ public class MarkerView extends Marker { private boolean selected; - private LatLng targetPosition; - private boolean shouldAnimate; - private boolean isAnimationRunning; - private AnimatorSet set; - - private long startTime; - private long duration; - private long remainingTime; - private AnimatorUtils.OnAnimationEndListener animationEndListener; - /** * Publicly hidden default constructor */ @@ -354,82 +344,6 @@ public class MarkerView extends Marker { markerViewManager = mapboxMap.getMarkerViewManager(); } - @Override - public void setPosition(LatLng position) { - setPosition(position, 0); - } - - public void setPosition(LatLng position, long duration) { - setPosition(position, duration, null); - } - - public void setPosition(LatLng position, long duration, AnimatorUtils.OnAnimationEndListener animationEndListener) { - this.animationEndListener = animationEndListener; - - if (duration <= 0) { - // update position instantly - super.setPosition(position); - if (markerViewManager != null) { - markerViewManager.update(); - } - } else { - // animate using Android SDK animations - this.targetPosition = position; - if (markerViewManager != null) { - markerViewManager.animatePosition(this, duration); - } - } - } - - boolean shouldAnimate() { - return shouldAnimate; - } - - void setShouldAnimate(boolean animating) { - shouldAnimate = animating; - } - - boolean isAnimating() { - return isAnimationRunning; - } - - void setAnimating(boolean animationRunning) { - isAnimationRunning = animationRunning; - } - - LatLng getTargetPosition() { - return targetPosition; - } - - void setAnimation(AnimatorSet set) { - this.set = set; - } - - AnimatorSet getAnimation() { - return set; - } - - long getRemainingTime() { - long time = duration - (AnimationUtils.currentAnimationTimeMillis() - startTime); - return time > 0 ? time : 0; - } - - void setDuration(long duration) { - this.duration = duration; - } - - void setStartTime(long startTime) { - this.startTime = startTime; - } - - AnimatorUtils.OnAnimationEndListener getAnimationEndListener() { - return animationEndListener; - } - - PointF getScreenLocation(@NonNull View convertView) { - return new PointF(convertView.getX() + offsetX, convertView.getY() + offsetY); - } - /** * Get the String representation of a MarkerView. * 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 b438e28d9..f99516bb0 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 @@ -1,19 +1,13 @@ package com.mapbox.mapboxsdk.annotations; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.content.Context; import android.graphics.PointF; -import android.os.CountDownTimer; import android.os.SystemClock; import android.support.annotation.NonNull; import android.support.annotation.Nullable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.animation.AnimationUtils; import android.widget.ImageView; import com.mapbox.mapboxsdk.R; @@ -43,7 +37,6 @@ public class MarkerViewManager { private long viewMarkerBoundsUpdateTime; private MapboxMap.OnMarkerViewClickListener onMarkerViewClickListener; private ImageMarkerViewAdapter defaultMarkerViewAdapter; - private CountDownTimer timer; /** * Creates an instance of MarkerViewManager. @@ -120,57 +113,22 @@ public class MarkerViewManager { for (final MarkerView marker : markerViewMap.keySet()) { final View convertView = markerViewMap.get(marker); if (convertView != null) { - if (marker.isAnimating() || !marker.shouldAnimate()) { - if (marker.isAnimating()) { - // cancel ongoing animations - marker.setAnimating(false); - AnimatorSet set = marker.getAnimation(); - List animations = set.getChildAnimations(); - float x = (Float) ((ObjectAnimator) animations.get(0)).getAnimatedValue(); - float y = (Float) ((ObjectAnimator) animations.get(1)).getAnimatedValue(); - PointF pointF = new PointF(x + marker.getOffsetX(), y + marker.getOffsetY()); - marker.setPosition(mapboxMap.getProjection().fromScreenLocation(pointF)); - set.cancel(); - } + PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); + if (marker.getOffsetX() == -1) { + int x = (int) (marker.getAnchorU() * convertView.getMeasuredWidth()); + int y = (int) (marker.getAnchorV() * convertView.getMeasuredHeight()); + marker.setOffsetX(x); + marker.setOffsetY(y); + } - // update position on map - PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); - if (marker.getOffsetX() == -1) { - int x = (int) (marker.getAnchorU() * convertView.getMeasuredWidth()); - int y = (int) (marker.getAnchorV() * convertView.getMeasuredHeight()); - marker.setOffsetX(x); - marker.setOffsetY(y); - } + convertView.setX(point.x - marker.getOffsetX()); + convertView.setY(point.y - marker.getOffsetY()); - convertView.setX(point.x - marker.getOffsetX()); - convertView.setY(point.y - marker.getOffsetY()); - - // animate visibility - if (marker.isVisible() && convertView.getVisibility() == View.GONE) { - convertView.animate().cancel(); - convertView.setAlpha(0); - AnimatorUtils.alpha(convertView, 1); - } - } else { - if (timer == null) { - timer = new CountDownTimer(50, 560) { - @Override - public void onTick(long millisUntilFinished) { - - } - - @Override - public void onFinish() { - animate(marker, convertView); - } - }; - } else { - timer.cancel(); - PointF point = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); - convertView.setX(point.x - marker.getOffsetX()); - convertView.setY(point.y - marker.getOffsetY()); - } - timer.start(); + // animate visibility + if (marker.isVisible() && convertView.getVisibility() == View.GONE) { + convertView.animate().cancel(); + convertView.setAlpha(0); + AnimatorUtils.alpha(convertView, 1); } } } @@ -283,23 +241,17 @@ public class MarkerViewManager { * @param marker the MarkerView to remove */ public void removeMarkerView(MarkerView marker) { - boolean isAnimating = marker.isAnimating(); final View viewHolder = markerViewMap.get(marker); if (viewHolder != null && marker != null) { for (final MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { if (adapter.getMarkerClass().equals(marker.getClass())) { - if (!isAnimating) { - if (adapter.prepareViewForReuse(marker, viewHolder)) { - adapter.releaseView(viewHolder); - } + if (adapter.prepareViewForReuse(marker, viewHolder)) { + adapter.releaseView(viewHolder); } } } } - - if (!isAnimating) { - markerViewMap.remove(marker); - } + markerViewMap.remove(marker); } /** @@ -373,7 +325,7 @@ public class MarkerViewManager { Iterator iterator = markerViewMap.keySet().iterator(); while (iterator.hasNext()) { MarkerView m = iterator.next(); - if (!m.shouldAnimate() && !markers.contains(m)) { + if (!markers.contains(m)) { // remove marker convertView = markerViewMap.get(m); for (MapboxMap.MarkerViewAdapter adapter : markerViewAdapters) { @@ -445,50 +397,6 @@ public class MarkerViewManager { } } - public void animatePosition(@NonNull MarkerView marker, long duration) { - marker.setDuration(duration); - marker.setStartTime(AnimationUtils.currentAnimationTimeMillis()); - marker.setShouldAnimate(true); - animate(marker, markerViewMap.get(marker)); - } - - private void animate(final MarkerView marker, @Nullable View convertView) { - if (convertView != null) { - marker.setAnimating(true); - PointF screenLocation = mapboxMap.getProjection().toScreenLocation(marker.getTargetPosition()); - PointF currentLocation = mapboxMap.getProjection().toScreenLocation(marker.getPosition()); - convertView.setX(currentLocation.x - marker.getOffsetX()); - convertView.setY(currentLocation.y - marker.getOffsetY()); - ObjectAnimator animatorX = ObjectAnimator.ofFloat(convertView, "x", screenLocation.x - marker.getOffsetX()); - ObjectAnimator animatorY = ObjectAnimator.ofFloat(convertView, "y", screenLocation.y - marker.getOffsetY()); - AnimatorSet set = new AnimatorSet(); - set.playTogether(animatorX, animatorY); - marker.setAnimation(set); - set.setDuration(marker.getRemainingTime()); - set.addListener(new AnimatorListenerAdapter() { - - private boolean canceled; - - @Override - public void onAnimationCancel(Animator animation) { - super.onAnimationCancel(animation); - canceled = true; - } - - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - if (!canceled) { - marker.setShouldAnimate(false); - marker.setPosition(marker.getTargetPosition()); - } - } - }); - marker.setAnimation(set); - set.start(); - } - } - /** * Default MarkerViewAdapter used for base class of MarkerView to adapt a MarkerView to an ImageView */ diff --git a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java index f11d46dba..c26b07952 100644 --- a/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java +++ b/platform/android/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxsdk/maps/MapboxMap.java @@ -52,7 +52,7 @@ import java.util.concurrent.TimeUnit; * you must obtain one from the getMapAsync() method on a MapFragment or MapView that you have * added to your application. *

- * Note: Similar to a View object, a GoogleMap should only be read and modified from the main thread. + * Note: Similar to a View object, a MapboxMap should only be read and modified from the main thread. *

*/ public class MapboxMap { diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java index 76e662d6a..118f4d166 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java @@ -4,6 +4,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.TypeEvaluator; +import android.animation.ValueAnimator; import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; @@ -16,7 +17,6 @@ import android.view.animation.AccelerateDecelerateInterpolator; import com.mapbox.mapboxsdk.annotations.Icon; import com.mapbox.mapboxsdk.annotations.IconFactory; import com.mapbox.mapboxsdk.annotations.Marker; -import com.mapbox.mapboxsdk.annotations.MarkerOptions; import com.mapbox.mapboxsdk.annotations.MarkerViewOptions; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.geometry.LatLng; @@ -30,8 +30,6 @@ import java.util.Random; public class AnimatedMarkerActivity extends AppCompatActivity { - private final static String LOG_TAG = "AnimatedMarkerActivity"; - private MapView mMapView; private MapboxMap mMapboxMap; From ebbe90983f1360126254b8d055beae14f59a35ea Mon Sep 17 00:00:00 2001 From: Tobrun Date: Fri, 17 Jun 2016 17:00:57 +0200 Subject: [PATCH 20/43] [android] #5299 - add rotation to cars, add cars images --- .../annotation/AnimatedMarkerActivity.java | 48 ++++++++++++------ .../main/res/drawable-xxxhdpi/ic_car_top.png | Bin 0 -> 19879 bytes .../main/res/drawable-xxxhdpi/ic_taxi_top.png | Bin 0 -> 11275 bytes .../drawable/ic_directions_run_black_24dp.xml | 4 +- 4 files changed, 34 insertions(+), 18 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_car_top.png create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_taxi_top.png diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java index 118f4d166..ea3a4cc42 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/annotation/AnimatedMarkerActivity.java @@ -6,6 +6,7 @@ import android.animation.ObjectAnimator; import android.animation.TypeEvaluator; import android.animation.ValueAnimator; import android.os.Bundle; +import android.support.annotation.DrawableRes; import android.support.annotation.NonNull; import android.support.v7.app.ActionBar; import android.support.v7.app.AppCompatActivity; @@ -17,6 +18,7 @@ import android.view.animation.AccelerateDecelerateInterpolator; import com.mapbox.mapboxsdk.annotations.Icon; import com.mapbox.mapboxsdk.annotations.IconFactory; import com.mapbox.mapboxsdk.annotations.Marker; +import com.mapbox.mapboxsdk.annotations.MarkerView; import com.mapbox.mapboxsdk.annotations.MarkerViewOptions; import com.mapbox.mapboxsdk.camera.CameraPosition; import com.mapbox.mapboxsdk.geometry.LatLng; @@ -32,11 +34,12 @@ public class AnimatedMarkerActivity extends AppCompatActivity { private MapView mMapView; private MapboxMap mMapboxMap; + private Random random = new Random(); private LatLng dupontCircle = new LatLng(38.90962, -77.04341); private Marker passengerMarker = null; - private Marker carMarker = null; + private MarkerView carMarker = null; @Override protected void onCreate(Bundle savedInstanceState) { @@ -60,15 +63,14 @@ public class AnimatedMarkerActivity extends AppCompatActivity { public void onMapReady(@NonNull final MapboxMap mapboxMap) { mMapboxMap = mapboxMap; setupMap(); - - addPassenger(); - addMainCar(); - animateMoveToPassenger(carMarker); - + for (int i = 0; i < 10; i++) { addRandomCar(); } + addPassenger(); + addMainCar(); + animateMoveToPassenger(carMarker); } }); } @@ -99,7 +101,7 @@ public class AnimatedMarkerActivity extends AppCompatActivity { LatLng randomLatLng = getLatLngInBounds(); if (carMarker == null) { - carMarker = createCarMarker(randomLatLng); + carMarker = createCarMarker(randomLatLng, R.drawable.ic_taxi_top); } else { carMarker.setPosition(randomLatLng); } @@ -108,8 +110,7 @@ public class AnimatedMarkerActivity extends AppCompatActivity { mMapboxMap.selectMarker(carMarker); } - private void animateMoveToPassenger(final Marker car) { - + private void animateMoveToPassenger(final MarkerView car) { ValueAnimator animator = animateMoveMarker(car, passengerMarker.getPosition()); animator.addListener(new AnimatorListenerAdapter() { @Override @@ -121,25 +122,25 @@ public class AnimatedMarkerActivity extends AppCompatActivity { } protected void addRandomCar() { - Marker car = createCarMarker(getLatLngInBounds()); + MarkerView car = createCarMarker(getLatLngInBounds(), R.drawable.ic_car_top); randomlyMoveMarker(car); } - private void randomlyMoveMarker(final Marker marker) { + private void randomlyMoveMarker(final MarkerView marker) { ValueAnimator animator = animateMoveMarker(marker, getLatLngInBounds()); //Add listener to restart animation on end animator.addListener(new AnimatorListenerAdapter() { - @Override public void onAnimationEnd(Animator animation) { randomlyMoveMarker(marker); } - }); } - private ValueAnimator animateMoveMarker(final Marker marker, LatLng to) { + private ValueAnimator animateMoveMarker(final MarkerView marker, LatLng to) { + marker.setRotation((float) getBearing(marker.getPosition(), to)); + final ValueAnimator markerAnimator = ObjectAnimator.ofObject(marker, "position", new LatLngEvaluator(), marker.getPosition(), to); markerAnimator.setDuration((long) (10 * marker.getPosition().distanceTo(to))); markerAnimator.setInterpolator(new AccelerateDecelerateInterpolator()); @@ -150,9 +151,9 @@ public class AnimatedMarkerActivity extends AppCompatActivity { return markerAnimator; } - private Marker createCarMarker(LatLng start) { + private MarkerView createCarMarker(LatLng start, @DrawableRes int carResource) { Icon icon = IconFactory.getInstance(AnimatedMarkerActivity.this) - .fromResource(R.drawable.ic_directions_car_black_24dp); + .fromResource(carResource); //View Markers return mMapboxMap.addMarker(new MarkerViewOptions() @@ -235,4 +236,19 @@ public class AnimatedMarkerActivity extends AppCompatActivity { return mLatLng; } } + + private double getBearing(LatLng from, LatLng to) { + double degrees2radians = Math.PI / 180; + double radians2degrees = 180 / Math.PI; + + double lon1 = degrees2radians * from.getLongitude(); + double lon2 = degrees2radians * to.getLongitude(); + double lat1 = degrees2radians * from.getLatitude(); + double lat2 = degrees2radians * to.getLatitude(); + double a = Math.sin(lon2 - lon1) * Math.cos(lat2); + double b = Math.cos(lat1) * Math.sin(lat2) - + Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon2 - lon1); + + return radians2degrees * Math.atan2(a, b); + } } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_car_top.png b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable-xxxhdpi/ic_car_top.png new file mode 100644 index 0000000000000000000000000000000000000000..ca7590137ba968dc0903ce4c75beb93b56d10787 GIT binary patch literal 19879 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 literal 0 HcmV?d00001 diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml index d18f6a17c..dfa43f020 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_directions_run_black_24dp.xml @@ -1,6 +1,6 @@ Date: Fri, 17 Jun 2016 08:28:19 -0700 Subject: [PATCH 21/43] [core] Bring optimized animated annotations to Android release branch Part of #5385 --- include/mbgl/map/update.hpp | 3 ++- src/mbgl/annotation/annotation_manager.cpp | 29 +++++++++++++++++----- src/mbgl/annotation/annotation_manager.hpp | 6 +++-- src/mbgl/map/map.cpp | 17 +++++++------ src/mbgl/style/style.cpp | 6 ++--- src/mbgl/style/style.hpp | 2 +- src/mbgl/tile/tile_worker.cpp | 17 +------------ src/mbgl/tile/tile_worker.hpp | 2 -- src/mbgl/tile/vector_tile_data.cpp | 28 ++++++++++++++++++--- src/mbgl/tile/vector_tile_data.hpp | 5 ++++ test/api/annotations.cpp | 2 +- 11 files changed, 75 insertions(+), 42 deletions(-) diff --git a/include/mbgl/map/update.hpp b/include/mbgl/map/update.hpp index 3915545bb..1c1270ac7 100644 --- a/include/mbgl/map/update.hpp +++ b/include/mbgl/map/update.hpp @@ -13,7 +13,8 @@ enum class Update : uint8_t { RecalculateStyle = 1 << 3, RenderStill = 1 << 4, Repaint = 1 << 5, - Annotations = 1 << 6, + AnnotationStyle = 1 << 6, + AnnotationData = 1 << 7, }; inline Update operator| (const Update& lhs, const Update& rhs) { diff --git a/src/mbgl/annotation/annotation_manager.cpp b/src/mbgl/annotation/annotation_manager.cpp index 1febc757a..5cd261696 100644 --- a/src/mbgl/annotation/annotation_manager.cpp +++ b/src/mbgl/annotation/annotation_manager.cpp @@ -49,14 +49,29 @@ AnnotationManager::addShapeAnnotations(const std::vector& shape return annotationIDs; } -void AnnotationManager::updatePointAnnotation(const AnnotationID& id, const PointAnnotation& point, const uint8_t) { +Update AnnotationManager::updatePointAnnotation(const AnnotationID& id, const PointAnnotation& point, const uint8_t) { auto foundAnnotation = pointAnnotations.find(id); - if (foundAnnotation != pointAnnotations.end()) { - auto updatedAnnotation = std::make_shared(id, point); - pointTree.remove(foundAnnotation->second); - pointTree.insert(updatedAnnotation); - foundAnnotation->second = updatedAnnotation; + if (foundAnnotation == pointAnnotations.end()) { + return Update::Nothing; } + + Update result = Update::Nothing; + const PointAnnotation& existing = foundAnnotation->second->point; + + if (existing.position != point.position) { + result |= Update::AnnotationData; + } + + if (existing.icon != point.icon) { + result |= Update::AnnotationData | Update::AnnotationStyle; + } + + auto updatedAnnotation = std::make_shared(id, point); + pointTree.remove(foundAnnotation->second); + pointTree.insert(updatedAnnotation); + foundAnnotation->second = updatedAnnotation; + + return result; } void AnnotationManager::removeAnnotations(const AnnotationIDs& ids) { @@ -135,7 +150,9 @@ void AnnotationManager::updateStyle(Style& style) { } obsoleteShapeAnnotationLayers.clear(); +} +void AnnotationManager::updateData() { for (auto& monitor : monitors) { monitor->update(getTile(monitor->tileID.canonical)); } diff --git a/src/mbgl/annotation/annotation_manager.hpp b/src/mbgl/annotation/annotation_manager.hpp index aaa60278c..560a16689 100644 --- a/src/mbgl/annotation/annotation_manager.hpp +++ b/src/mbgl/annotation/annotation_manager.hpp @@ -5,7 +5,7 @@ #include #include #include -#include +#include #include #include @@ -14,6 +14,7 @@ namespace mbgl { +class LatLngBounds; class PointAnnotation; class ShapeAnnotation; class AnnotationTile; @@ -27,7 +28,7 @@ public: AnnotationIDs addPointAnnotations(const std::vector&, const uint8_t maxZoom); AnnotationIDs addShapeAnnotations(const std::vector&, const uint8_t maxZoom); - void updatePointAnnotation(const AnnotationID&, const PointAnnotation&, const uint8_t maxZoom); + Update updatePointAnnotation(const AnnotationID&, const PointAnnotation&, const uint8_t maxZoom); void removeAnnotations(const AnnotationIDs&); AnnotationIDs getPointAnnotationsInBounds(const LatLngBounds&) const; @@ -38,6 +39,7 @@ public: SpriteAtlas& getSpriteAtlas() { return spriteAtlas; } void updateStyle(Style&); + void updateData(); void addTileMonitor(AnnotationTileMonitor&); void removeTileMonitor(AnnotationTileMonitor&); diff --git a/src/mbgl/map/map.cpp b/src/mbgl/map/map.cpp index 841b4607c..99262beb2 100644 --- a/src/mbgl/map/map.cpp +++ b/src/mbgl/map/map.cpp @@ -211,11 +211,15 @@ void Map::Impl::update() { // - Hint style sources to notify when all its tiles are loaded; timePoint = Clock::now(); - if (style->loaded && updateFlags & Update::Annotations) { + if (style->loaded && updateFlags & Update::AnnotationStyle) { annotationManager->updateStyle(*style); updateFlags |= Update::Classes; } + if (updateFlags & Update::AnnotationData) { + annotationManager->updateData(); + } + if (updateFlags & Update::Classes) { style->cascade(timePoint, mode); } @@ -344,7 +348,7 @@ void Map::Impl::loadStyleJSON(const std::string& json, const std::string& base) // force style cascade, causing all pending transitions to complete. style->cascade(Clock::now(), mode); - updateFlags |= Update::Classes | Update::RecalculateStyle | Update::Annotations; + updateFlags |= Update::Classes | Update::RecalculateStyle | Update::AnnotationStyle; asyncUpdate.send(); } @@ -700,7 +704,7 @@ AnnotationID Map::addPointAnnotation(const PointAnnotation& annotation) { AnnotationIDs Map::addPointAnnotations(const std::vector& annotations) { auto result = impl->annotationManager->addPointAnnotations(annotations, getMaxZoom()); - update(Update::Annotations); + update(Update::AnnotationStyle | Update::AnnotationData); return result; } @@ -710,13 +714,12 @@ AnnotationID Map::addShapeAnnotation(const ShapeAnnotation& annotation) { AnnotationIDs Map::addShapeAnnotations(const std::vector& annotations) { auto result = impl->annotationManager->addShapeAnnotations(annotations, getMaxZoom()); - update(Update::Annotations); + update(Update::AnnotationStyle | Update::AnnotationData); return result; } void Map::updatePointAnnotation(AnnotationID annotationId, const PointAnnotation& annotation) { - impl->annotationManager->updatePointAnnotation(annotationId, annotation, getMaxZoom()); - update(Update::Annotations); + update(impl->annotationManager->updatePointAnnotation(annotationId, annotation, getMaxZoom())); } void Map::removeAnnotation(AnnotationID annotation) { @@ -725,7 +728,7 @@ void Map::removeAnnotation(AnnotationID annotation) { void Map::removeAnnotations(const AnnotationIDs& annotations) { impl->annotationManager->removeAnnotations(annotations); - update(Update::Annotations); + update(Update::AnnotationStyle | Update::AnnotationData); } AnnotationIDs Map::getPointAnnotationsInBounds(const LatLngBounds& bounds) { diff --git a/src/mbgl/style/style.cpp b/src/mbgl/style/style.cpp index bc2a1d9a4..774e523b7 100644 --- a/src/mbgl/style/style.cpp +++ b/src/mbgl/style/style.cpp @@ -109,11 +109,11 @@ void Style::addSource(std::unique_ptr source) { sources.emplace_back(std::move(source)); } -std::vector> Style::getLayers() const { - std::vector> result; +std::vector Style::getLayers() const { + std::vector result; result.reserve(layers.size()); for (const auto& layer : layers) { - result.push_back(layer->clone()); + result.push_back(layer.get()); } return result; } diff --git a/src/mbgl/style/style.hpp b/src/mbgl/style/style.hpp index 5fdd6cdc8..1150c9daf 100644 --- a/src/mbgl/style/style.hpp +++ b/src/mbgl/style/style.hpp @@ -69,7 +69,7 @@ public: Source* getSource(const std::string& id) const; void addSource(std::unique_ptr); - std::vector> getLayers() const; + std::vector getLayers() const; StyleLayer* getLayer(const std::string& id) const; void addLayer(std::unique_ptr, optional beforeLayerID = {}); diff --git a/src/mbgl/tile/tile_worker.cpp b/src/mbgl/tile/tile_worker.cpp index 266e357ab..ae26ccd4a 100644 --- a/src/mbgl/tile/tile_worker.cpp +++ b/src/mbgl/tile/tile_worker.cpp @@ -3,8 +3,6 @@ #include #include #include -#include -#include #include #include #include @@ -13,19 +11,18 @@ #include #include #include + #include using namespace mbgl; TileWorker::TileWorker(const OverscaledTileID& id_, - std::string sourceID_, SpriteStore& spriteStore_, GlyphAtlas& glyphAtlas_, GlyphStore& glyphStore_, const util::Atomic& obsolete_, const MapMode mode_) : id(id_), - sourceID(std::move(sourceID_)), spriteStore(spriteStore_), glyphAtlas(glyphAtlas_), glyphStore(glyphStore_), @@ -134,18 +131,6 @@ void TileWorker::parseLayer(const StyleLayer* layer) { if (obsolete) return; - // Background and custom layers are special cases. - if (layer->is() || layer->is()) - return; - - // Skip this bucket if we are to not render this - if ((layer->source != sourceID) || - (id.overscaledZ < std::floor(layer->minZoom)) || - (id.overscaledZ >= std::ceil(layer->maxZoom)) || - (layer->visibility == VisibilityType::None)) { - return; - } - auto geometryLayer = geometryTile->getLayer(layer->sourceLayer); if (!geometryLayer) { // The layer specified in the bucket does not exist. Do nothing. diff --git a/src/mbgl/tile/tile_worker.hpp b/src/mbgl/tile/tile_worker.hpp index e19d803ac..5a8b336e3 100644 --- a/src/mbgl/tile/tile_worker.hpp +++ b/src/mbgl/tile/tile_worker.hpp @@ -43,7 +43,6 @@ using TileParseResult = variant< class TileWorker : public util::noncopyable { public: TileWorker(const OverscaledTileID&, - std::string sourceID, SpriteStore&, GlyphAtlas&, GlyphStore&, @@ -67,7 +66,6 @@ private: std::unique_ptr placeLayers(PlacementConfig); const OverscaledTileID id; - const std::string sourceID; SpriteStore& spriteStore; GlyphAtlas& glyphAtlas; diff --git a/src/mbgl/tile/vector_tile_data.cpp b/src/mbgl/tile/vector_tile_data.cpp index 428c605f2..e81e94ed5 100644 --- a/src/mbgl/tile/vector_tile_data.cpp +++ b/src/mbgl/tile/vector_tile_data.cpp @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include #include #include @@ -13,15 +15,15 @@ namespace mbgl { VectorTileData::VectorTileData(const OverscaledTileID& id_, std::unique_ptr monitor_, - std::string sourceID, + std::string sourceID_, Style& style_, const MapMode mode_, const std::function& callback) : TileData(id_), + sourceID(std::move(sourceID_)), style(style_), worker(style_.workers), tileWorker(id_, - sourceID, *style_.spriteStore, *style_.glyphAtlas, *style_.glyphStore, @@ -60,7 +62,7 @@ VectorTileData::VectorTileData(const OverscaledTileID& id_, // when tile data changed. Replacing the workdRequest will cancel a pending work // request in case there is one. workRequest.reset(); - workRequest = worker.parseGeometryTile(tileWorker, style.getLayers(), std::move(tile), targetConfig, [callback, this, config = targetConfig] (TileParseResult result) { + workRequest = worker.parseGeometryTile(tileWorker, cloneStyleLayers(), std::move(tile), targetConfig, [callback, this, config = targetConfig] (TileParseResult result) { workRequest.reset(); std::exception_ptr error; @@ -97,6 +99,26 @@ VectorTileData::~VectorTileData() { cancel(); } +std::vector> VectorTileData::cloneStyleLayers() const { + std::vector> result; + + for (const StyleLayer* layer : style.getLayers()) { + // Avoid cloning and including irrelevant layers. + if (layer->is() || + layer->is() || + layer->source != sourceID || + id.overscaledZ < std::floor(layer->minZoom) || + id.overscaledZ >= std::ceil(layer->maxZoom) || + layer->visibility == VisibilityType::None) { + continue; + } + + result.push_back(layer->clone()); + } + + return result; +} + bool VectorTileData::parsePending(std::function callback) { if (workRequest) { // There's already parsing or placement going on. diff --git a/src/mbgl/tile/vector_tile_data.hpp b/src/mbgl/tile/vector_tile_data.hpp index ec557e202..a6ed6213c 100644 --- a/src/mbgl/tile/vector_tile_data.hpp +++ b/src/mbgl/tile/vector_tile_data.hpp @@ -8,10 +8,12 @@ #include #include +#include namespace mbgl { class Style; +class StyleLayer; class AsyncRequest; class GeometryTileMonitor; class FeatureIndex; @@ -43,6 +45,9 @@ public: void cancel() override; private: + std::vector> cloneStyleLayers() const; + + const std::string sourceID; Style& style; Worker& worker; TileWorker tileWorker; diff --git a/test/api/annotations.cpp b/test/api/annotations.cpp index 8640ce9db..0764cd8a5 100644 --- a/test/api/annotations.cpp +++ b/test/api/annotations.cpp @@ -159,7 +159,7 @@ TEST(Annotations, UpdateIcon) { map.removeAnnotationIcon("flipped_marker"); map.addAnnotationIcon("flipped_marker", namedMarker("flipped_marker.png")); - map.update(Update::Annotations); + map.update(Update::AnnotationData | Update::AnnotationStyle); checkRendering(map, "update_icon"); } From 2591147e25d6ed74f091bed97f57fb4591e7bde6 Mon Sep 17 00:00:00 2001 From: Brad Leege Date: Wed, 8 Jun 2016 13:07:52 -0500 Subject: [PATCH 22/43] [android] Setting up LocationPickerActivity infrastructure Fixes #5282 --- .../MapboxGLAndroidSDKTestApp/build.gradle | 9 +- .../src/main/AndroidManifest.xml | 8 + .../directions/DirectionsActivity.java | 96 ++-- .../activity/geocoding/GeocoderActivity.java | 74 +-- .../navigation/LocationPickerActivity.java | 467 ++++++++++++++++++ .../model/annotations/PulseMarkerView.java | 11 + .../annotations/PulseMarkerViewOptions.java | 79 +++ .../src/main/res/anim/pulse.xml | 24 + .../src/main/res/drawable/ic_circle.xml | 12 + .../src/main/res/drawable/ic_clear_24dp.xml | 9 + .../res/layout/activity_location_picker.xml | 41 ++ .../src/main/res/layout/view_pulse_marker.xml | 21 + .../src/main/res/values/dimens.xml | 2 + .../src/main/res/values/strings.xml | 8 +- platform/android/build.gradle | 2 +- 15 files changed, 772 insertions(+), 91 deletions(-) create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/LocationPickerActivity.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerView.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerViewOptions.java create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/anim/pulse.xml create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_circle.xml create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_clear_24dp.xml create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_picker.xml create mode 100644 platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/view_pulse_marker.xml diff --git a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle index 5c6265c72..10ddcd90b 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/build.gradle +++ b/platform/android/MapboxGLAndroidSDKTestApp/build.gradle @@ -90,13 +90,8 @@ dependencies { debugCompile 'com.squareup.leakcanary:leakcanary-android:1.4-beta1' releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.4-beta1' - // Directions SDK - compile('com.mapbox.mapboxsdk:mapbox-android-directions:1.0.0@aar') { - transitive = true - } - - // Geocoder SDK - compile('com.mapbox.mapboxsdk:mapbox-android-geocoder:1.0.0@aar') { + // Mapbox Android Services + compile('com.mapbox.mapboxsdk:mapbox-android-services:1.1.0@aar') { transitive = true } diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml index c3bd231d3..593ba8403 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/AndroidManifest.xml @@ -270,6 +270,14 @@ android:value="@string/category_annotation" />
+ + + + () { - @Override - public void onResponse(Response response, Retrofit retrofit) { - // You can get generic HTTP info about the response - Log.d(LOG_TAG, "Response code: " + response.code()); + md.enqueueCall(new Callback() { - // Print some info about the route - DirectionsRoute currentRoute = response.body().getRoutes().get(0); - Log.d(LOG_TAG, "Distance: " + currentRoute.getDistance()); + @Override + public void onFailure(Call call, Throwable t) { + Log.e(LOG_TAG, "Error: " + t.getMessage()); + } - // Draw the route on the map - drawRoute(currentRoute); - } + @Override + public void onResponse(Call call, Response response) { + // You can get generic HTTP info about the response + Log.d(LOG_TAG, "Response code: " + response.code()); - @Override - public void onFailure(Throwable t) { - Log.e(LOG_TAG, "Error: " + t.getMessage()); - } - }); + // Print some info about the route + DirectionsRoute currentRoute = response.body().getRoutes().get(0); + Log.d(LOG_TAG, "Distance: " + currentRoute.getDistance()); + + // Draw the route on the map + drawRoute(currentRoute); + } + + }); + } catch (ServicesException e) { + Log.e(LOG_TAG, "Error displaying route: " + e.toString()); + e.printStackTrace(); + } } private void drawRoute(DirectionsRoute route) { - // Convert List into LatLng[] - List waypoints = route.getGeometry().getWaypoints(); - LatLng[] point = new LatLng[waypoints.size()]; - for (int i = 0; i < waypoints.size(); i++) { - point[i] = new LatLng( - waypoints.get(i).getLatitude(), - waypoints.get(i).getLongitude()); + + PolylineOptions builder = new PolylineOptions(); + builder.color(Color.parseColor("#3887be")); + builder.alpha(0.5f); + builder.width(5); + builder.width(5); + LineString lineString = route.asLineString(Constants.OSRM_PRECISION_V4); + for (Position coordinates : lineString.getCoordinates()) { + builder.add(new LatLng(coordinates.getLatitude(), coordinates.getLongitude())); } // Draw Points on MapView - mMapboxMap.addPolyline(new PolylineOptions() - .add(point) - .color(Color.parseColor("#3887be")) - .width(5)); + mMapboxMap.addPolyline(builder); } @Override diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/geocoding/GeocoderActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/geocoding/GeocoderActivity.java index 99d2f81aa..7c99e16b2 100644 --- a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/geocoding/GeocoderActivity.java +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/geocoding/GeocoderActivity.java @@ -14,11 +14,6 @@ import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.TextView; - -import com.mapbox.geocoder.GeocoderCriteria; -import com.mapbox.geocoder.MapboxGeocoder; -import com.mapbox.geocoder.service.models.GeocoderFeature; -import com.mapbox.geocoder.service.models.GeocoderResponse; import com.mapbox.mapboxsdk.annotations.MarkerOptions; import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.geometry.LatLng; @@ -27,12 +22,19 @@ import com.mapbox.mapboxsdk.maps.MapboxMap; import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; import com.mapbox.mapboxsdk.maps.Projection; import com.mapbox.mapboxsdk.testapp.R; +import com.mapbox.services.commons.ServicesException; +import com.mapbox.services.commons.models.Position; +import com.mapbox.services.geocoding.v5.GeocodingCriteria; +import com.mapbox.services.geocoding.v5.MapboxGeocoding; +import com.mapbox.services.geocoding.v5.models.GeocodingFeature; +import com.mapbox.services.geocoding.v5.models.GeocodingResponse; import java.util.List; -import retrofit.Callback; -import retrofit.Response; -import retrofit.Retrofit; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; public class GeocoderActivity extends AppCompatActivity { @@ -123,40 +125,38 @@ public class GeocoderActivity extends AppCompatActivity { */ private void geocode(final LatLng point) { - new AsyncTask() { - @Override - protected Void doInBackground(Void... params) { - MapboxGeocoder client = new MapboxGeocoder.Builder() - .setAccessToken(getString(R.string.mapbox_access_token)) - .setCoordinates(point.getLongitude(), point.getLatitude()) - .setType(GeocoderCriteria.TYPE_POI) - .build(); + try { + MapboxGeocoding client = new MapboxGeocoding.Builder() + .setAccessToken(getString(R.string.mapbox_access_token)) + .setCoordinates(Position.fromCoordinates(point.getLongitude(), point.getLatitude())) + .setType(GeocodingCriteria.TYPE_POI) + .build(); - client.enqueue(new Callback() + client.enqueueCall(new Callback() { + @Override + public void onResponse(Call call, Response response) { - { - @Override - public void onResponse(Response response, Retrofit retrofit) { - List results = response.body().getFeatures(); - if (results.size() > 0) { - String placeName = results.get(0).getPlaceName(); - setSuccess(placeName); - } else { - setMessage("No results."); - } - } + List results = response.body().getFeatures(); + if (results.size() > 0) { + String placeName = results.get(0).getPlaceName(); + setSuccess(placeName); + } else { + setMessage("No results."); + } - @Override - public void onFailure(Throwable t) { - setError(t.getMessage()); - } - } + } - ); - return null; - } - }.execute(); + @Override + public void onFailure(Call call, Throwable t) { + setError(t.getMessage()); + } + }); + } catch (ServicesException e) { + Log.e(LOG_TAG, "Error geocoding: " + e.toString()); + e.printStackTrace(); + setError(e.getMessage()); + } } /* diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/LocationPickerActivity.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/LocationPickerActivity.java new file mode 100644 index 000000000..7a6e42565 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity/navigation/LocationPickerActivity.java @@ -0,0 +1,467 @@ +package com.mapbox.mapboxsdk.testapp.activity.navigation; + +import android.Manifest; +import android.app.ProgressDialog; +import android.content.Context; +import android.content.pm.PackageManager; +import android.graphics.PointF; +import android.location.Location; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.ActivityCompat; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.widget.Button; +import android.widget.FrameLayout; +import android.widget.ImageButton; +import android.widget.ImageView; +import android.widget.Toast; + +import com.mapbox.mapboxsdk.annotations.Icon; +import com.mapbox.mapboxsdk.annotations.IconFactory; +import com.mapbox.mapboxsdk.annotations.Marker; +import com.mapbox.mapboxsdk.annotations.MarkerOptions; +import com.mapbox.mapboxsdk.annotations.MarkerView; +import com.mapbox.mapboxsdk.annotations.MarkerViewOptions; +import com.mapbox.mapboxsdk.camera.CameraPosition; +import com.mapbox.mapboxsdk.geometry.LatLng; +import com.mapbox.mapboxsdk.location.LocationListener; +import com.mapbox.mapboxsdk.location.LocationServices; +import com.mapbox.mapboxsdk.maps.MapView; +import com.mapbox.mapboxsdk.maps.MapboxMap; +import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; +import com.mapbox.mapboxsdk.testapp.R; +import com.mapbox.mapboxsdk.testapp.model.annotations.PulseMarkerView; +import com.mapbox.mapboxsdk.testapp.model.annotations.PulseMarkerViewOptions; +import com.mapbox.services.commons.ServicesException; +import com.mapbox.services.commons.models.Position; +import com.mapbox.services.geocoding.v5.GeocodingCriteria; +import com.mapbox.services.geocoding.v5.MapboxGeocoding; +import com.mapbox.services.geocoding.v5.models.GeocodingFeature; +import com.mapbox.services.geocoding.v5.models.GeocodingResponse; + +import java.util.List; + +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; + +/** + * Sample Activity to show a typical location picker use case + */ +public class LocationPickerActivity extends AppCompatActivity { + private static final String TAG = "LocationPickerActivity"; + private static final int REQUEST_PERMISSIONS = 101; + + private MapView mapView; + private MapboxMap mapboxMap; + + private ImageView dropPinView; + private Marker addressPin; + private ImageButton clearDisplayViewButton; + private MarkerView userMarker; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_location_picker); + + setupActionBar(); + + //Initialize map as normal + mapView = (MapView) findViewById(R.id.mapView); + mapView.onCreate(savedInstanceState); + + //Create ui elements + createDropPin(); + createSelectLocationButton(); + createClearSelectionButton(); + + mapView.getMapAsync(new OnMapReadyCallback() { + @Override + public void onMapReady(MapboxMap map) { + //Store for later + mapboxMap = map; + + //Add user marker + mapboxMap.getMarkerViewManager().addMarkerViewAdapter(new PulseMarkerViewAdapter(LocationPickerActivity.this)); + userMarker = createCustomUserMarker(new LatLng(0, 0)); + + //Fix the focal point to the center of the map + PointF focalPoint = new PointF((mapView.getX() + mapView.getWidth() / 2), (mapView.getY() + mapView.getHeight() / 2)); + mapboxMap.getUiSettings().setFocalPoint(focalPoint); + + //Track camera updates to animate the user location views + trackUserLocationView(userMarker); + } + }); + } + + @Override + public void onResume() { + super.onResume(); + mapView.onResume(); + + //Check permissions + if (arePermissionsGranted()) { + mapView.getMapAsync(new OnMapReadyCallback() { + + @Override + public void onMapReady(final MapboxMap mapboxMap) { + //Get the user's location + final LocationServices locationServices = LocationServices.getLocationServices(getApplicationContext()); + + Location location = locationServices.getLastLocation(); + if (location != null) { + zoomInOn(location); + userMarker.setPosition(new LatLng(location)); + } else { + final ProgressDialog loadingDialog = ProgressDialog.show(LocationPickerActivity.this, "Loading", "Getting user location", false); + locationServices.addLocationListener(new LocationListener() { + @Override + public void onLocationChanged(@Nullable Location location) { + //Move the camera to the user + if (location != null) { + zoomInOn(location); + userMarker.setPosition(new LatLng(location)); + locationServices.removeLocationListener(this); + loadingDialog.hide(); + } + } + }); + } + + locationServices.toggleGPS(true); + } + }); + } + } + + private void zoomInOn(Location location) { + //Move the camera to the user + if (location != null) { + mapboxMap.setCameraPosition(new CameraPosition.Builder() + .target(new LatLng(location)) + .zoom(16) + .bearing(0) + .tilt(0) + .build()); + } + } + + + /** + * Tracks the camera to animate the marker when overlapping with the picker. + * Makes sure the marker actually points to the user's position by tracking it. + */ + private void trackUserLocationView(final MarkerView markerView) { + final float circleDiameterSize = getResources().getDimension(R.dimen.circle_size); + + //Track camera changes to check for overlap + mapboxMap.setOnCameraChangeListener(new MapboxMap.OnCameraChangeListener() { + + private Animation pulseAnimation; + + @Override + public void onCameraChange(CameraPosition position) { + if (markerView == null) { + return; + } + + //Make drop pin visible, if it wasn't already + showDropPin(); + + //Get the distance from the tip of the location picker to the MarkerView + double distance = getLocationPickerLocation().distanceTo(markerView.getPosition()); + + //If closeby, animate, otherwise, stop animation + View view = mapboxMap.getMarkerViewManager().getView(markerView); + if (view != null) { + View backgroundView = view.findViewById(R.id.background_imageview); + if (pulseAnimation == null && distance < 0.5f * circleDiameterSize) { + pulseAnimation = AnimationUtils.loadAnimation(LocationPickerActivity.this, R.anim.pulse); + pulseAnimation.setRepeatCount(Animation.INFINITE); + pulseAnimation.setRepeatMode(Animation.RESTART); + backgroundView.startAnimation(pulseAnimation); + } else if (pulseAnimation != null && distance >= 0.5f * circleDiameterSize) { + backgroundView.clearAnimation(); + pulseAnimation = null; + } + } + } + }); + + //Track location updates to move the user marker + LocationServices.getLocationServices(getApplicationContext()).addLocationListener(new LocationListener() { + @Override + public void onLocationChanged(Location location) { + if (location != null && markerView != null) { + markerView.setPosition(new LatLng(location)); + } + } + }); + } + + private MarkerView createCustomUserMarker(LatLng markerPosition) { + return mapboxMap.addMarker(new PulseMarkerViewOptions() + .icon(IconFactory.getInstance(getApplicationContext()).fromResource(R.drawable.ic_my_location_24dp)) + .position(markerPosition) + ); + } + + private void createClearSelectionButton() { + clearDisplayViewButton = (ImageButton) findViewById(R.id.clearDisplayViewButton); + clearDisplayViewButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + removeAddressPin(); + hide(clearDisplayViewButton); + showDropPin(); + } + }); + } + + private void createSelectLocationButton() { + Button selectLocationButton = (Button) findViewById(R.id.selectLocationButton); + //noinspection ConstantConditions + selectLocationButton.setOnClickListener( + new View.OnClickListener() { + @Override + public void onClick(View v) { + Log.i(TAG, "Location Selected!"); + if (mapboxMap != null) { + //Control button's state + clearDisplayViewButton.setVisibility(View.VISIBLE); + dropPinView.setVisibility(View.INVISIBLE); + + //Get position for the drop pin + LatLng position = getLocationPickerLocation(); + + //Show the address pin (result) + showAddressPin(position); + + //Get the address for that location and update the marker + geocode(position, new GeocodeCallbacks() { + @Override + public void onResult(String result) { + updateAddressPin(result); + } + + @Override + public void onFailure(Throwable failure) { + showFeedbackMessage("Could not retrieve address: " + failure.getMessage()); + } + }); + } + } + } + ); + } + + private void createDropPin() { + float density = getResources().getDisplayMetrics().density; + + dropPinView = new ImageView(this); + dropPinView.setImageResource(R.drawable.ic_droppin_24dp); + FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, Gravity.CENTER); + params.bottomMargin = (int) (12 * density); + dropPinView.setLayoutParams(params); + + mapView.addView(dropPinView); + } + + private void showDropPin() { + if (dropPinView != null && dropPinView.getVisibility() != View.VISIBLE) { + dropPinView.setVisibility(View.VISIBLE); + } + } + + private void hide(View view) { + if (view != null) { + view.setVisibility(View.INVISIBLE); + } + } + + private void setupActionBar() { + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + + ActionBar actionBar = getSupportActionBar(); + if (actionBar != null) { + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setDisplayShowHomeEnabled(true); + } + } + + /** + * Get address for the given location + */ + private void geocode(LatLng point, final GeocodeCallbacks callbacks) { + try { + //Create Geocoding client + MapboxGeocoding client = new MapboxGeocoding.Builder() + .setAccessToken(getString(R.string.mapbox_access_token)) + .setCoordinates(Position.fromCoordinates(point.getLongitude(), point.getLatitude())) + .setType(GeocodingCriteria.TYPE_ADDRESS) + .build(); + + //Place the request + client.enqueueCall(new Callback() { + @Override + public void onResponse(Call call, Response response) { + + List results = response.body().getFeatures(); + String address = null; + if (results.size() > 0) { + GeocodingFeature feature = results.get(0); + address = feature.getAddress() + " " + feature.getText(); + Log.i(TAG, "address " + address); + } else { + showFeedbackMessage("No results for search."); + } + + callbacks.onResult(address); + } + + @Override + public void onFailure(Call call, Throwable t) { + Log.e(TAG, "Geocoding Failure: " + t.getMessage()); + callbacks.onFailure(t); + } + }); + } catch (ServicesException e) { + Log.e(TAG, "Error geocoding: " + e.toString()); + callbacks.onFailure(e); + } + } + + private LatLng getLocationPickerLocation() { + return mapboxMap.getProjection().fromScreenLocation( + new PointF(dropPinView.getLeft() + (dropPinView.getWidth() / 2), dropPinView.getBottom()) + ); + } + + private Marker showAddressPin(LatLng position) { + if (addressPin != null) { + //Remove previous pin + removeAddressPin(); + } + + //Create new one + addressPin = mapboxMap.addMarker(new MarkerViewOptions().title("Loading address...").position(position)); + mapboxMap.selectMarker(addressPin); + return addressPin; + } + + private void removeAddressPin() { + if (mapboxMap != null && addressPin != null) { + mapboxMap.removeMarker(addressPin); + } + } + + private void updateAddressPin(@Nullable String address) { + if (addressPin != null) { + addressPin.setTitle(address == null ? "No address found" : address); + } + } + + private void showFeedbackMessage(String message) { + Toast.makeText(getApplicationContext(), message, Toast.LENGTH_SHORT).show(); + } + + private boolean arePermissionsGranted() { + if (Build.VERSION.SDK_INT >= 23 && + checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED && + checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + Log.i(TAG, "Requesting permissions"); + ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_PERMISSIONS); + return false; + } + Log.i(TAG, "Permissions already granted"); + return true; + } + + @Override + public void onPause() { + super.onPause(); + mapView.onPause(); + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + mapView.onSaveInstanceState(outState); + } + + @Override + protected void onDestroy() { + super.onDestroy(); + mapView.onDestroy(); + } + + @Override + public void onLowMemory() { + super.onLowMemory(); + mapView.onLowMemory(); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case android.R.id.home: + onBackPressed(); + return true; + default: + return super.onOptionsItemSelected(item); + } + } + + /** + * Custom MarkerViewAdapter for the pulsing marker + */ + private static class PulseMarkerViewAdapter extends MapboxMap.MarkerViewAdapter { + + private LayoutInflater inflater; + + public PulseMarkerViewAdapter(@NonNull Context context) { + super(context); + this.inflater = LayoutInflater.from(context); + } + + @Nullable + @Override + public View getView(@NonNull PulseMarkerView marker, @Nullable View convertView, @NonNull ViewGroup parent) { + ViewHolder viewHolder; + if (convertView == null) { + viewHolder = new ViewHolder(); + convertView = inflater.inflate(R.layout.view_pulse_marker, parent, false); + viewHolder.foregroundImageView = (ImageView) convertView.findViewById(R.id.foreground_imageView); + viewHolder.backgroundImageView = (ImageView) convertView.findViewById(R.id.background_imageview); + convertView.setTag(viewHolder); + } + return convertView; + } + + private static class ViewHolder { + ImageView foregroundImageView; + ImageView backgroundImageView; + } + } + + private interface GeocodeCallbacks { + void onResult(String result); + + void onFailure(Throwable failure); + } +} diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerView.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerView.java new file mode 100644 index 000000000..48867ea5e --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerView.java @@ -0,0 +1,11 @@ +package com.mapbox.mapboxsdk.testapp.model.annotations; + +import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions; +import com.mapbox.mapboxsdk.annotations.MarkerView; + +public class PulseMarkerView extends MarkerView { + + public PulseMarkerView(BaseMarkerViewOptions baseMarkerViewOptions) { + super(baseMarkerViewOptions); + } +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerViewOptions.java b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerViewOptions.java new file mode 100644 index 000000000..70ff6a22e --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/model/annotations/PulseMarkerViewOptions.java @@ -0,0 +1,79 @@ +package com.mapbox.mapboxsdk.testapp.model.annotations; + +import android.graphics.Bitmap; +import android.os.Parcel; +import android.os.Parcelable; + +import com.mapbox.mapboxsdk.annotations.BaseMarkerViewOptions; +import com.mapbox.mapboxsdk.annotations.Icon; +import com.mapbox.mapboxsdk.annotations.IconFactory; +import com.mapbox.mapboxsdk.geometry.LatLng; + +public class PulseMarkerViewOptions extends BaseMarkerViewOptions { + + public PulseMarkerViewOptions() { + } + + protected PulseMarkerViewOptions(Parcel in) { + position((LatLng) in.readParcelable(LatLng.class.getClassLoader())); + snippet(in.readString()); + title(in.readString()); + flat(in.readByte() != 0); + anchor(in.readFloat(), in.readFloat()); + selected = in.readByte() != 0; + rotation(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 = IconFactory.recreate(iconId, iconBitmap); + icon(icon); + } + } + + @Override + public PulseMarkerViewOptions getThis() { + return this; + } + + @Override + public int describeContents() { + return 0; + } + + @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.writeByte((byte) (selected ? 1 : 0)); + out.writeFloat(getRotation()); + Icon icon = getIcon(); + out.writeByte((byte) (icon != null ? 1 : 0)); + if (icon != null) { + out.writeString(getIcon().getId()); + out.writeParcelable(getIcon().getBitmap(), flags); + } + } + + @Override + public PulseMarkerView getMarker() { + return new PulseMarkerView(this); + } + + public static final Parcelable.Creator CREATOR + = new Parcelable.Creator() { + public CountryMarkerViewOptions createFromParcel(Parcel in) { + return new CountryMarkerViewOptions(in); + } + + public CountryMarkerViewOptions[] newArray(int size) { + return new CountryMarkerViewOptions[size]; + } + }; +} \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/anim/pulse.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/anim/pulse.xml new file mode 100644 index 000000000..40bc57ab6 --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/anim/pulse.xml @@ -0,0 +1,24 @@ + + + + + + + + + \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_circle.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_circle.xml new file mode 100644 index 000000000..006b2ce5a --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_circle.xml @@ -0,0 +1,12 @@ + + + + + + + \ No newline at end of file diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_clear_24dp.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_clear_24dp.xml new file mode 100644 index 000000000..1e2d044be --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/drawable/ic_clear_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_picker.xml b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_picker.xml new file mode 100644 index 000000000..f9fe77bfe --- /dev/null +++ b/platform/android/MapboxGLAndroidSDKTestApp/src/main/res/layout/activity_location_picker.xml @@ -0,0 +1,41 @@ + + + + + + + + + +