diff --git a/android/build.gradle b/android/build.gradle index e6cee6f..125c24b 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -1,13 +1,3 @@ -buildscript { - repositories { - jcenter() - } - - dependencies { - classpath 'com.android.tools.build:gradle:1.3.0' - } -} - apply plugin: 'com.android.library' android { @@ -30,8 +20,9 @@ repositories { } dependencies { - compile 'com.facebook.react:react-native:0.19.+' - compile('com.mapbox.mapboxsdk:mapbox-android-sdk:4.2.2@aar') { + compile 'com.facebook.react:react-native:+' + compile 'com.mapbox.mapboxsdk:mapbox-android-telemetry:2.1.0@aar' + compile('com.mapbox.mapboxsdk:mapbox-android-sdk:5.0.2@aar') { transitive = true } } diff --git a/android/install.md b/android/install.md index b72fa1d..dd8ad81 100644 --- a/android/install.md +++ b/android/install.md @@ -70,3 +70,19 @@ Also, add the Mapbox analytics service to the `` node: ``` #### Step 4 - Add to project, [see example](../example.js) + +#### Troubleshoot + +You may get `com.android.dex.DexException: Multiple dex files define Lokhttp3/internal/ws/WebSocketReader$FrameCallback` +error when building the android app. You can solve it by adding this. +```gradle +// file: android/app/build.gradle +... + +configurations.all { + resolutionStrategy { + force "com.squareup.okhttp3:okhttp:3.4.2" + force "com.squareup.okhttp3:okhttp-ws:3.4.2" + } +} +``` \ No newline at end of file diff --git a/android/src/main/java/com/mapbox/reactnativemapboxgl/RNMGLAnnotationOptionsFactory.java b/android/src/main/java/com/mapbox/reactnativemapboxgl/RNMGLAnnotationOptionsFactory.java index efd98ed..f2ee1cd 100644 --- a/android/src/main/java/com/mapbox/reactnativemapboxgl/RNMGLAnnotationOptionsFactory.java +++ b/android/src/main/java/com/mapbox/reactnativemapboxgl/RNMGLAnnotationOptionsFactory.java @@ -3,6 +3,7 @@ package com.mapbox.reactnativemapboxgl; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.graphics.Canvas; import android.graphics.Color; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; @@ -124,7 +125,14 @@ public class RNMGLAnnotationOptionsFactory { if ((drawable instanceof BitmapDrawable) && width == intrinsicWidth && height == intrinsicHeight) { icon = iconFactory.fromBitmap(((BitmapDrawable)drawable).getBitmap()); } else { - icon = iconFactory.fromDrawable(drawable, width, height); + // Conversion taken from mapbox-gl-native/issues/7897#issuecomment-277302450 + Bitmap bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), + drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); + Canvas canvas = new Canvas(bitmap); + drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); + //DrawableCompat.setTint(drawable, colorRes); + drawable.draw(canvas); + icon = iconFactory.fromBitmap(bitmap); } iconCache.put(cacheKey, icon); diff --git a/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLModule.java b/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLModule.java index d7ae38b..71ed25d 100644 --- a/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLModule.java +++ b/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLModule.java @@ -1,27 +1,10 @@ package com.mapbox.reactnativemapboxgl; -import android.content.Context; -import android.os.Bundle; import android.os.Handler; -import android.os.Parcel; -import android.support.annotation.MainThread; -import android.support.annotation.UiThread; import android.util.Log; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.ObjectInput; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; - -import com.facebook.common.logging.FLog; import com.facebook.react.bridge.Arguments; -import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; @@ -29,26 +12,30 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; -import com.facebook.react.bridge.ReadableNativeMap; import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; -import com.facebook.react.bridge.WritableNativeArray; -import com.facebook.react.modules.core.DeviceEventManagerModule; import com.facebook.react.modules.core.RCTNativeAppEventEmitter; -import com.facebook.react.uimanager.annotations.ReactProp; -import com.mapbox.mapboxsdk.MapboxAccountManager; -import com.mapbox.mapboxsdk.constants.MyLocationTracking; +import com.mapbox.mapboxsdk.Mapbox; import com.mapbox.mapboxsdk.constants.MyBearingTracking; +import com.mapbox.mapboxsdk.constants.MyLocationTracking; import com.mapbox.mapboxsdk.constants.Style; import com.mapbox.mapboxsdk.geometry.LatLng; import com.mapbox.mapboxsdk.geometry.LatLngBounds; import com.mapbox.mapboxsdk.offline.OfflineManager; import com.mapbox.mapboxsdk.offline.OfflineRegion; -import com.mapbox.mapboxsdk.offline.OfflineRegionDefinition; import com.mapbox.mapboxsdk.offline.OfflineRegionError; import com.mapbox.mapboxsdk.offline.OfflineRegionStatus; import com.mapbox.mapboxsdk.offline.OfflineTilePyramidRegionDefinition; -import com.mapbox.mapboxsdk.telemetry.MapboxEventManager; +import com.mapbox.services.android.telemetry.MapboxTelemetry; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; import javax.annotation.Nullable; @@ -125,7 +112,7 @@ public class ReactNativeMapboxGLModule extends ReactContextBaseJavaModule { mapStyles.put("light", Style.LIGHT); mapStyles.put("dark", Style.DARK); mapStyles.put("streets", Style.MAPBOX_STREETS); - mapStyles.put("emerald", Style.EMERALD); + mapStyles.put("outdoors", Style.OUTDOORS); mapStyles.put("satellite", Style.SATELLITE); mapStyles.put("hybrid", Style.SATELLITE_STREETS); @@ -143,7 +130,8 @@ public class ReactNativeMapboxGLModule extends ReactContextBaseJavaModule { // Other constants constants.put("unknownResourceCount", Long.MAX_VALUE); - constants.put("metricsEnabled", MapboxEventManager.getMapboxEventManager().isTelemetryEnabled()); + // FIXME you cannot get telemetry enabled status before you set access token +// constants.put("metricsEnabled", MapboxTelemetry.getInstance().isTelemetryEnabled()); constants.put("userTrackingMode", userTrackingMode); constants.put("mapStyles", mapStyles); @@ -161,7 +149,7 @@ public class ReactNativeMapboxGLModule extends ReactContextBaseJavaModule { throw new JSApplicationIllegalArgumentException("Invalid access token. Register to mapbox.com and request an access token, then pass it to setAccessToken()"); } if (initialized) { - String oldToken = MapboxAccountManager.getInstance().getAccessToken(); + String oldToken = Mapbox.getAccessToken(); if (!oldToken.equals(accessToken)) { JSApplicationIllegalArgumentException error = new JSApplicationIllegalArgumentException("Mapbox access token cannot be initialized twice with different values"); @@ -175,7 +163,7 @@ public class ReactNativeMapboxGLModule extends ReactContextBaseJavaModule { mainHandler.post(new Runnable() { @Override public void run() { - MapboxAccountManager.start(context.getApplicationContext(), accessToken); + Mapbox.getInstance(context.getApplicationContext(), accessToken); promise.resolve(null); } }); @@ -184,14 +172,14 @@ public class ReactNativeMapboxGLModule extends ReactContextBaseJavaModule { // Connected @ReactMethod public void setConnected(boolean connected) { - MapboxAccountManager.getInstance().setConnected(connected); + Mapbox.getInstance(context.getApplicationContext(), Mapbox.getAccessToken()).setConnected(connected); } // Metrics @ReactMethod public void setMetricsEnabled(boolean value) { - MapboxEventManager.getMapboxEventManager().setTelemetryEnabled(value); + MapboxTelemetry.getInstance().setTelemetryEnabled(value); } // Offline packs @@ -652,4 +640,4 @@ public class ReactNativeMapboxGLModule extends ReactContextBaseJavaModule { public void setOfflinePackProgressThrottleInterval(int milis) { throttleInterval = milis; } -} \ No newline at end of file +} diff --git a/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLView.java b/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLView.java index 331671f..c5e9117 100644 --- a/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLView.java +++ b/android/src/main/java/com/mapbox/reactnativemapboxgl/ReactNativeMapboxGLView.java @@ -19,7 +19,6 @@ import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.WritableMap; import com.facebook.react.touch.OnInterceptTouchEventListener; import com.facebook.react.uimanager.events.RCTEventEmitter; -import com.google.common.collect.Sets; import com.mapbox.mapboxsdk.annotations.Annotation; import com.mapbox.mapboxsdk.annotations.Marker; import com.mapbox.mapboxsdk.annotations.MarkerView; @@ -105,6 +104,7 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements if (_mapView != null) { return; } setupMapView(); _paused = false; + _mapView.onStart(); _mapView.onResume(); _manager.getContext().addLifecycleEventListener(this); } @@ -116,6 +116,7 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements if (!_paused) { _paused = true; _mapView.onPause(); + _mapView.onStop(); } destroyMapView(); _mapView = null; @@ -124,6 +125,7 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements @Override public void onHostResume() { _paused = false; + _mapView.onStart(); _mapView.onResume(); } @@ -131,6 +133,7 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements public void onHostPause() { _paused = true; _mapView.onPause(); + _mapView.onStop(); } @Override @@ -159,8 +162,8 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements _map.getTrackingSettings().setMyLocationTrackingMode(_locationTrackingMode); _map.getTrackingSettings().setMyBearingTrackingMode(_bearingTrackingMode); _map.setPadding(_paddingLeft, _paddingTop, _paddingRight, _paddingBottom); - _map.setMinZoom(_minimumZoomLevel); - _map.setMaxZoom(_maximumZoomLevel); + _map.setMinZoomPreference(_minimumZoomLevel); + _map.setMaxZoomPreference(_maximumZoomLevel); UiSettings uiSettings = _map.getUiSettings(); uiSettings.setZoomGesturesEnabled(_zoomEnabled); @@ -242,8 +245,8 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements private void updateMarkerAnnotations() { Set newAnnotationViews = new HashSet<>(_manager.getAnnotationViews(this)); Set currentViews = new HashSet<>(_customAnnotationViewMap.values()); - Collection addedChildren = Sets.difference(newAnnotationViews, currentViews); - Collection removedChildren = Sets.difference(currentViews, newAnnotationViews); + Collection addedChildren = Utils.difference(newAnnotationViews, currentViews); + Collection removedChildren = Utils.difference(currentViews, newAnnotationViews); for (RNMGLAnnotationView annotationView : removedChildren) { annotationView.removePropertyListener(_propertyListeners.get(annotationView)); @@ -346,7 +349,7 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements if (_minimumZoomLevel == value) { return; } _minimumZoomLevel = value; if (_map != null) { - _map.setMinZoom(value); + _map.setMinZoomPreference(value); } } @@ -354,7 +357,7 @@ public class ReactNativeMapboxGLView extends RelativeLayout implements if (_maximumZoomLevel == value) { return; } _maximumZoomLevel = value; if (_map != null) { - _map.setMaxZoom(value); + _map.setMaxZoomPreference(value); } } diff --git a/android/src/main/java/com/mapbox/reactnativemapboxgl/Utils.java b/android/src/main/java/com/mapbox/reactnativemapboxgl/Utils.java new file mode 100644 index 0000000..b9f2f86 --- /dev/null +++ b/android/src/main/java/com/mapbox/reactnativemapboxgl/Utils.java @@ -0,0 +1,100 @@ +package com.mapbox.reactnativemapboxgl; + +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.NoSuchElementException; +import java.util.Set; + +import javax.annotation.Nullable; + +public class Utils { + public static Collection difference(final Set set1, final Set set2) { + return new AbstractSet() { + @Override + public Iterator iterator() { + final Iterator iterator = set1.iterator(); + + return new AbstractIterator() { + @Override + protected E computeNext() { + while (iterator.hasNext()) { + E ele = iterator.next(); + if (!set2.contains(ele)) { + return ele; + } + } + + return endOfData(); + } + }; + } + + @Override + public int size() { + throw new RuntimeException("stub"); + } + }; + } + + abstract static class AbstractIterator implements Iterator { + private State state = State.NOT_READY; + + protected AbstractIterator() {} + + private enum State { + READY, + NOT_READY, + DONE, + FAILED, + } + + private T next; + + protected abstract T computeNext(); + + @Nullable + protected final T endOfData() { + state = State.DONE; + return null; + } + + @Override + public final boolean hasNext() { + switch (state) { + case READY: + return true; + case DONE: + return false; + default: + } + return tryToComputeNext(); + } + + private boolean tryToComputeNext() { + state = State.FAILED; // temporary pessimism + next = computeNext(); + if (state != State.DONE) { + state = State.READY; + return true; + } + return false; + } + + @Override + public final T next() { + if (!hasNext()) { + throw new NoSuchElementException(); + } + state = State.NOT_READY; + T result = next; + next = null; + return result; + } + + @Override + public final void remove() { + throw new UnsupportedOperationException(); + } + } +}