diff --git a/google-maps/src/main/java/org/odk/collect/googlemaps/GoogleMapFragment.java b/google-maps/src/main/java/org/odk/collect/googlemaps/GoogleMapFragment.java index e2c62e6cc59..93fcf9e40be 100644 --- a/google-maps/src/main/java/org/odk/collect/googlemaps/GoogleMapFragment.java +++ b/google-maps/src/main/java/org/odk/collect/googlemaps/GoogleMapFragment.java @@ -19,9 +19,13 @@ import android.location.Location; import android.os.Bundle; import android.os.Handler; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.fragment.app.Fragment; import com.google.android.gms.location.LocationListener; import com.google.android.gms.maps.CameraUpdate; @@ -46,6 +50,7 @@ import org.odk.collect.androidshared.system.ContextUtils; import org.odk.collect.androidshared.ui.ToastUtils; import org.odk.collect.googlemaps.GoogleMapConfigurator.GoogleMapTypeOption; +import org.odk.collect.googlemaps.scaleview.MapScaleView; import org.odk.collect.location.LocationClient; import org.odk.collect.maps.LineDescription; import org.odk.collect.maps.MapConfigurator; @@ -72,7 +77,7 @@ import timber.log.Timber; -public class GoogleMapFragment extends SupportMapFragment implements +public class GoogleMapFragment extends Fragment implements MapFragment, LocationListener, LocationClient.LocationClientListener, GoogleMap.OnMapClickListener, GoogleMap.OnMapLongClickListener, GoogleMap.OnMarkerClickListener, GoogleMap.OnMarkerDragListener, @@ -100,6 +105,9 @@ public class GoogleMapFragment extends SupportMapFragment implements ); private GoogleMap map; + private MapScaleView scaleView; + private ReadyListener readyListener; + private ErrorListener errorListener; private Marker locationCrosshairs; private Circle accuracyCircle; private final List gpsLocationReadyListeners = new ArrayList<>(); @@ -121,9 +129,27 @@ public class GoogleMapFragment extends SupportMapFragment implements private boolean hasCenter; @Override - @SuppressLint("MissingPermission") // Permission checks for location services handled in widgets public void init(@Nullable ReadyListener readyListener, @Nullable ErrorListener errorListener) { - getMapAsync((GoogleMap googleMap) -> { + this.readyListener = readyListener; + this.errorListener = errorListener; + } + + @Override + public void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mapFragmentDelegate.onCreate(savedInstanceState); + } + + @Nullable + @Override + @SuppressLint("MissingPermission") // Permission checks for location services handled in widgets + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.map_layout, container, false); + + scaleView = view.findViewById(R.id.scale_view); + + SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.map); + mapFragment.getMapAsync((GoogleMap googleMap) -> { if (googleMap == null) { ToastUtils.showShortToast(requireContext(), org.odk.collect.strings.R.string.google_play_services_error_occured); if (errorListener != null) { @@ -144,7 +170,9 @@ public void init(@Nullable ReadyListener readyListener, @Nullable ErrorListener googleMap.setMyLocationEnabled(false); googleMap.setMinZoomPreference(1); googleMap.moveCamera(CameraUpdateFactory.newLatLngZoom( - toLatLng(INITIAL_CENTER), INITIAL_ZOOM)); + toLatLng(INITIAL_CENTER), INITIAL_ZOOM)); + googleMap.setOnCameraMoveListener(() -> scaleView.update(googleMap.getCameraPosition().zoom, googleMap.getCameraPosition().target.latitude)); + googleMap.setOnCameraIdleListener(() -> scaleView.update(googleMap.getCameraPosition().zoom, googleMap.getCameraPosition().target.latitude)); loadReferenceOverlay(); // If the screen is rotated before the map is ready, this fragment @@ -155,12 +183,8 @@ public void init(@Nullable ReadyListener readyListener, @Nullable ErrorListener readyListener.onReady(this); } }); - } - @Override - public void onCreate(@Nullable Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - mapFragmentDelegate.onCreate(savedInstanceState); + return view; } @Override public void onAttach(@NonNull Context context) { diff --git a/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/Drawer.java b/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/Drawer.java new file mode 100644 index 00000000000..80ad6d0c96a --- /dev/null +++ b/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/Drawer.java @@ -0,0 +1,190 @@ +/* + * This file includes code from MapScaleView (https://github.com/pengrad/MapScaleView), + * licensed under the Apache License, Version 2.0. + */ +package org.odk.collect.googlemaps.scaleview; + +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.Rect; +import android.graphics.Typeface; + +public class Drawer { + + private final Paint textPaint = new Paint(); + private final Paint strokePaint = new Paint(); + private final Path strokePath = new Path(); + + private final Paint outlinePaint = new Paint(); + private final Path outlineDiffPath = new Path(); + private float outlineStrokeWidth = 2; // strokeWidth * 2 + private float outlineStrokeDiff = outlineStrokeWidth / 2 / 2; // strokeWidth / 2 + private float outlineTextStrokeWidth = 3; // density * 2 + private boolean outlineEnabled = true; + + private float textHeight; + private float horizontalLineY; + + private boolean expandRtlEnabled; + private int viewWidth; + + private Scales scales = new Scales(null, null); + + Drawer(int color, float textSize, float strokeWidth, float density, boolean outlineEnabled, boolean expandRtlEnabled) { + textPaint.setAntiAlias(true); + textPaint.setColor(color); + textPaint.setStyle(Paint.Style.FILL); + textPaint.setTextSize(textSize); + + strokePaint.setAntiAlias(true); + strokePaint.setColor(color); + strokePaint.setStyle(Paint.Style.STROKE); + strokePaint.setStrokeWidth(strokeWidth); + + outlinePaint.set(strokePaint); + outlinePaint.setARGB(255, 255, 255, 255); + outlineStrokeWidth = strokeWidth * 2; + outlineStrokeDiff = strokeWidth / 2; + outlineTextStrokeWidth = density * 2; + this.outlineEnabled = outlineEnabled; + this.expandRtlEnabled = expandRtlEnabled; + + update(); + } + + private void update() { + outlinePaint.setTextSize(textPaint.getTextSize()); + outlinePaint.setTypeface(textPaint.getTypeface()); + outlinePaint.setStrokeWidth(outlineTextStrokeWidth); + + Rect textRect = new Rect(); + Paint highestPaint = outlineEnabled ? outlinePaint : textPaint; + String possibleText = "1234567890kmift"; + highestPaint.getTextBounds(possibleText, 0, possibleText.length(), textRect); + textHeight = textRect.height(); + + horizontalLineY = textHeight + textHeight / 2; + } + + int getWidth() { + return (int) (scales.maxLength() + strokePaint.getStrokeWidth()); + } + + int getHeight() { + if (scales.bottom() != null) { + return (int) (textHeight * 3 + outlineTextStrokeWidth / 2); + } else { + return (int) (horizontalLineY + strokePaint.getStrokeWidth()); + } + } + + void setScales(Scales scales) { + this.scales = scales; + } + + void setColor(int color) { + textPaint.setColor(color); + strokePaint.setColor(color); + } + + void setTextSize(float textSize) { + textPaint.setTextSize(textSize); + update(); + } + + void setTextFont(Typeface font) { + textPaint.setTypeface(font); + update(); + } + + void setStrokeWidth(float strokeWidth) { + strokePaint.setStrokeWidth(strokeWidth); + outlineStrokeWidth = strokeWidth * 2; + outlineStrokeDiff = strokeWidth / 2; + update(); + } + + void setOutlineEnabled(boolean enabled) { + outlineEnabled = enabled; + update(); + } + + void setExpandRtlEnabled(boolean enabled) { + expandRtlEnabled = enabled; + } + + void setViewWidth(int width) { + viewWidth = width; + } + + void draw(Canvas canvas) { + Scale top = scales.top(); + if (top == null) { + return; + } + if (expandRtlEnabled && viewWidth == 0) { + expandRtlEnabled = false; + } + + if (expandRtlEnabled) { + outlinePaint.setTextAlign(Paint.Align.RIGHT); + textPaint.setTextAlign(Paint.Align.RIGHT); + } else { + outlinePaint.setTextAlign(Paint.Align.LEFT); + textPaint.setTextAlign(Paint.Align.LEFT); + } + + if (outlineEnabled) { + outlinePaint.setStrokeWidth(outlineTextStrokeWidth); + canvas.drawText(top.text(), expandRtlEnabled ? viewWidth : 0, textHeight, outlinePaint); + } + canvas.drawText(top.text(), expandRtlEnabled ? viewWidth : 0, textHeight, textPaint); + + strokePath.rewind(); + strokePath.moveTo(expandRtlEnabled ? (viewWidth - outlineStrokeDiff) : outlineStrokeDiff, horizontalLineY); + strokePath.lineTo(expandRtlEnabled ? (viewWidth - top.length()) : top.length(), horizontalLineY); + if (outlineEnabled) { + strokePath.lineTo(expandRtlEnabled ? (viewWidth - top.length()) : top.length(), textHeight + outlineStrokeDiff); + } else { + strokePath.lineTo(expandRtlEnabled ? (viewWidth - top.length()) : top.length(), textHeight); + } + + Scale bottom = scales.bottom(); + if (bottom != null) { + + if (bottom.length() > top.length()) { + strokePath.moveTo(expandRtlEnabled ? (viewWidth - top.length()) : top.length(), horizontalLineY); + strokePath.lineTo(expandRtlEnabled ? (viewWidth - bottom.length()) : bottom.length(), horizontalLineY); + } else { + strokePath.moveTo(expandRtlEnabled ? (viewWidth - bottom.length()) : bottom.length(), horizontalLineY); + } + + strokePath.lineTo(expandRtlEnabled ? (viewWidth - bottom.length()) : bottom.length(), textHeight * 2); + + float bottomTextY = horizontalLineY + textHeight + textHeight / 2; + if (outlineEnabled) { + canvas.drawText(bottom.text(), expandRtlEnabled ? viewWidth : 0, bottomTextY, outlinePaint); + } + canvas.drawText(bottom.text(), expandRtlEnabled ? viewWidth : 0, bottomTextY, textPaint); + } + + if (outlineEnabled) { + outlinePaint.setStrokeWidth(outlineStrokeWidth); + outlineDiffPath.rewind(); + outlineDiffPath.moveTo(expandRtlEnabled ? viewWidth : 0, horizontalLineY); + outlineDiffPath.lineTo(expandRtlEnabled ? (viewWidth - outlineStrokeDiff) : outlineStrokeDiff, horizontalLineY); + outlineDiffPath.moveTo(expandRtlEnabled ? (viewWidth - top.length()) : top.length(), textHeight + outlineStrokeDiff); + outlineDiffPath.lineTo(expandRtlEnabled ? (viewWidth - top.length()) : top.length(), textHeight); + if (bottom != null) { + outlineDiffPath.moveTo(expandRtlEnabled ? (viewWidth - bottom.length()) : bottom.length(), textHeight * 2); + outlineDiffPath.lineTo(expandRtlEnabled ? (viewWidth - bottom.length()) : bottom.length(), textHeight * 2 + outlineStrokeDiff); + } + + canvas.drawPath(outlineDiffPath, outlinePaint); + canvas.drawPath(strokePath, outlinePaint); + } + + canvas.drawPath(strokePath, strokePaint); + } +} diff --git a/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/MapScaleModel.java b/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/MapScaleModel.java new file mode 100644 index 00000000000..d0590845c1d --- /dev/null +++ b/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/MapScaleModel.java @@ -0,0 +1,100 @@ +/* + * This file includes code from MapScaleView (https://github.com/pengrad/MapScaleView), + * licensed under the Apache License, Version 2.0. + */ +package org.odk.collect.googlemaps.scaleview; + +class MapScaleModel { + + private static final double EQUATOR_LENGTH_METERS = 40075016.686; + private static final double EQUATOR_LENGTH_FEET = 131479713.537; + + private static final int FT_IN_MILE = 5280; + + private static final float[] METERS = {0.2f, 0.5f, 1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, + 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000}; + + private static final float[] FT = {1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, + FT_IN_MILE, 2 * FT_IN_MILE, 5 * FT_IN_MILE, 10 * FT_IN_MILE, 20 * FT_IN_MILE, 50 * FT_IN_MILE, + 100 * FT_IN_MILE, 200 * FT_IN_MILE, 500 * FT_IN_MILE, 1000 * FT_IN_MILE, 2000 * FT_IN_MILE}; + + private final float density; + private int maxWidth; + + private float lastZoom = -1; + private double lastLatitude = -100; + + private double tileSizeMetersAt0Zoom = EQUATOR_LENGTH_METERS / 256; + private double tileSizeFeetAt0Zoom = EQUATOR_LENGTH_FEET / 256; + + MapScaleModel(float density) { + this.density = density; + } + + // returns true if width changed + boolean updateMaxWidth(int width) { + if (maxWidth != width) { + maxWidth = width; + return true; + } else { + return false; + } + } + + void setTileSize(int tileSize) { + tileSizeMetersAt0Zoom = EQUATOR_LENGTH_METERS / tileSize; + tileSizeFeetAt0Zoom = EQUATOR_LENGTH_FEET / tileSize; + } + + void setPosition(float zoom, double latitude) { + lastZoom = zoom; + lastLatitude = latitude; + } + + /** + * See http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#Resolution_and_Scale + */ + Scale update(boolean meters) { + float zoom = lastZoom; + double latitude = lastLatitude; + if (zoom < 0 || Math.abs(latitude) > 90) { + return null; + } + + double tileSizeAtZoom0 = meters ? tileSizeMetersAt0Zoom : tileSizeFeetAt0Zoom; + float[] distances = meters ? METERS : FT; + + final double resolution = tileSizeAtZoom0 / density * Math.cos(latitude * Math.PI / 180) / Math.pow(2, zoom); + + float distance = 0; + int distanceIndex = distances.length; + double screenDistance = maxWidth + 1; + + while (screenDistance > maxWidth && distanceIndex > 0) { + distance = distances[--distanceIndex]; + screenDistance = Math.abs(distance / resolution); + } + + lastZoom = zoom; + lastLatitude = latitude; + return new Scale(text(distance, meters), (float) screenDistance); + } + + private String text(float distance, boolean meters) { + if (meters) { + if (distance < 1) { + return (int) (distance * 100) + " cm"; + } else if (distance < 1000) { + return (int) distance + " m"; + } else { + return (int) distance / 1000 + " km"; + } + } else { + if (distance < FT_IN_MILE) { + return (int) distance + " ft"; + } else { + return (int) distance / FT_IN_MILE + " mi"; + } + } + } +} diff --git a/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/MapScaleView.java b/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/MapScaleView.java new file mode 100644 index 00000000000..f2f0db3e648 --- /dev/null +++ b/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/MapScaleView.java @@ -0,0 +1,182 @@ +/* + * This file includes code from MapScaleView (https://github.com/pengrad/MapScaleView), + * licensed under the Apache License, Version 2.0. + */ +package org.odk.collect.googlemaps.scaleview; + +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Typeface; +import android.util.AttributeSet; +import android.view.View; + +import androidx.annotation.ColorInt; + +public class MapScaleView extends View { + + private final MapScaleModel mapScaleModel; + private final Drawer drawer; + + private final int maxWidth; + + private ScaleType scaleType = ScaleType.BOTH; + + private enum ScaleType { + METERS_ONLY, MILES_ONLY, BOTH + } + + public MapScaleView(Context context) { + this(context, null); + } + + public MapScaleView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public MapScaleView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + float density = getResources().getDisplayMetrics().density; + mapScaleModel = new MapScaleModel(density); + + ViewConfig viewConfig = new ViewConfig(context, attrs); + drawer = new Drawer(viewConfig.color, viewConfig.textSize, viewConfig.strokeWidth, density, viewConfig.outline, viewConfig.expandRtl); + + maxWidth = viewConfig.maxWidth; + + if (viewConfig.isMiles) { + scaleType = ScaleType.MILES_ONLY; + } + } + + public void setTileSize(int tileSize) { + mapScaleModel.setTileSize(tileSize); + updateScales(); + } + + public void setColor(@ColorInt int color) { + drawer.setColor(color); + invalidate(); + } + + public void setTextSize(float textSize) { + drawer.setTextSize(textSize); + invalidate(); + requestLayout(); + } + + public void setTextFont(Typeface font) { + drawer.setTextFont(font); + invalidate(); + requestLayout(); + } + + public void setStrokeWidth(float strokeWidth) { + drawer.setStrokeWidth(strokeWidth); + invalidate(); + requestLayout(); + } + + public void setOutlineEnabled(boolean enabled) { + drawer.setOutlineEnabled(enabled); + invalidate(); + } + + public void setExpandRtlEnabled(boolean enabled) { + drawer.setExpandRtlEnabled(enabled); + invalidate(); + } + + /** + * @deprecated Use milesOnly() + */ + @Deprecated + public void setIsMiles(boolean miles) { + if (miles) { + milesOnly(); + } else { + metersAndMiles(); + } + } + + public void metersOnly() { + scaleType = ScaleType.METERS_ONLY; + updateScales(); + } + + public void milesOnly() { + scaleType = ScaleType.MILES_ONLY; + updateScales(); + } + + public void metersAndMiles() { + scaleType = ScaleType.BOTH; + updateScales(); + } + + public void update(float zoom, double latitude) { + mapScaleModel.setPosition(zoom, latitude); + updateScales(); + } + + private void updateScales() { + Scale top; + Scale bottom = null; + + if (scaleType == ScaleType.MILES_ONLY) { + top = mapScaleModel.update(false); + } else { + top = mapScaleModel.update(true); + if (scaleType == ScaleType.BOTH) { + bottom = mapScaleModel.update(false); + } + } + + drawer.setScales(new Scales(top, bottom)); + invalidate(); + requestLayout(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int width = measureDimension(desiredWidth(), widthMeasureSpec); + int height = measureDimension(desiredHeight(), heightMeasureSpec); + + if (mapScaleModel.updateMaxWidth(width)) { + updateScales(); + } + + if (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.EXACTLY) { + width = drawer.getWidth(); + } + + drawer.setViewWidth(width); + setMeasuredDimension(width, height); + } + + private int desiredWidth() { + return maxWidth; + } + + private int desiredHeight() { + return drawer.getHeight(); + } + + private int measureDimension(int desiredSize, int measureSpec) { + int mode = View.MeasureSpec.getMode(measureSpec); + int size = View.MeasureSpec.getSize(measureSpec); + + if (mode == View.MeasureSpec.EXACTLY) { + return size; + } else if (mode == View.MeasureSpec.AT_MOST) { + return Math.min(desiredSize, size); + } else { + return desiredSize; + } + } + + @Override + public void onDraw(Canvas canvas) { + drawer.draw(canvas); + } +} diff --git a/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/Scale.java b/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/Scale.java new file mode 100644 index 00000000000..ead0b26ac3f --- /dev/null +++ b/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/Scale.java @@ -0,0 +1,24 @@ +/* + * This file includes code from MapScaleView (https://github.com/pengrad/MapScaleView), + * licensed under the Apache License, Version 2.0. + */ +package org.odk.collect.googlemaps.scaleview; + +class Scale { + + private final String text; + private final float length; + + Scale(String text, float length) { + this.text = text; + this.length = length; + } + + public String text() { + return text; + } + + public float length() { + return length; + } +} diff --git a/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/Scales.java b/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/Scales.java new file mode 100644 index 00000000000..b4f5f33bfe9 --- /dev/null +++ b/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/Scales.java @@ -0,0 +1,31 @@ +/* + * This file includes code from MapScaleView (https://github.com/pengrad/MapScaleView), + * licensed under the Apache License, Version 2.0. + */ +package org.odk.collect.googlemaps.scaleview; + +import androidx.annotation.Nullable; + +class Scales { + private final Scale top; + private final Scale bottom; + + Scales(Scale top, Scale bottom) { + this.top = top; + this.bottom = bottom; + } + + @Nullable + Scale top() { + return top; + } + + @Nullable + Scale bottom() { + return bottom; + } + + float maxLength() { + return Math.max(top != null ? top.length() : 0, bottom != null ? bottom.length() : 0); + } +} diff --git a/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/ViewConfig.java b/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/ViewConfig.java new file mode 100644 index 00000000000..632ce4e908d --- /dev/null +++ b/google-maps/src/main/java/org/odk/collect/googlemaps/scaleview/ViewConfig.java @@ -0,0 +1,40 @@ +/* + * This file includes code from MapScaleView (https://github.com/pengrad/MapScaleView), + * licensed under the Apache License, Version 2.0. + */ +package org.odk.collect.googlemaps.scaleview; + +import android.content.Context; +import android.content.res.TypedArray; +import android.graphics.Color; +import android.util.AttributeSet; + +import org.odk.collect.googlemaps.R; + +class ViewConfig { + + final int maxWidth; + final int color; + final float textSize; + final float strokeWidth; + final boolean isMiles; + final boolean outline; + final boolean expandRtl; + + ViewConfig(Context context, AttributeSet attrs) { + float density = context.getResources().getDisplayMetrics().density; + + TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.MapScaleView, 0, 0); + try { + maxWidth = a.getDimensionPixelSize(R.styleable.MapScaleView_scale_maxWidth, (int) (100 * density)); + color = a.getColor(R.styleable.MapScaleView_scale_color, Color.parseColor("#333333")); + textSize = a.getDimension(R.styleable.MapScaleView_scale_textSize, 12 * density); + strokeWidth = a.getDimension(R.styleable.MapScaleView_scale_strokeWidth, 1.5f * density); + isMiles = a.getBoolean(R.styleable.MapScaleView_scale_miles, false); + outline = a.getBoolean(R.styleable.MapScaleView_scale_outline, true); + expandRtl = a.getBoolean(R.styleable.MapScaleView_scale_expandRtl, false); + } finally { + a.recycle(); + } + } +} diff --git a/google-maps/src/main/res/layout/map_layout.xml b/google-maps/src/main/res/layout/map_layout.xml new file mode 100644 index 00000000000..3d4fe30600d --- /dev/null +++ b/google-maps/src/main/res/layout/map_layout.xml @@ -0,0 +1,22 @@ + + + + + + + + diff --git a/google-maps/src/main/res/values/attrs.xml b/google-maps/src/main/res/values/attrs.xml new file mode 100644 index 00000000000..ab9bdbb93ae --- /dev/null +++ b/google-maps/src/main/res/values/attrs.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + diff --git a/mapbox/src/main/java/org/odk/collect/mapbox/MapboxMapFragment.kt b/mapbox/src/main/java/org/odk/collect/mapbox/MapboxMapFragment.kt index f7ee7e55a05..207b6e7e7d2 100644 --- a/mapbox/src/main/java/org/odk/collect/mapbox/MapboxMapFragment.kt +++ b/mapbox/src/main/java/org/odk/collect/mapbox/MapboxMapFragment.kt @@ -44,7 +44,6 @@ import com.mapbox.maps.plugin.gestures.OnMapLongClickListener import com.mapbox.maps.plugin.gestures.addOnMapClickListener import com.mapbox.maps.plugin.gestures.addOnMapLongClickListener import com.mapbox.maps.plugin.locationcomponent.location -import com.mapbox.maps.plugin.scalebar.scalebar import kotlinx.coroutines.delay import kotlinx.coroutines.launch import org.odk.collect.androidshared.utils.ScreenUtils @@ -152,7 +151,6 @@ class MapboxMapFragment : savedInstanceState: Bundle? ): View { mapView = MapView(inflater.context).apply { - scalebar.enabled = false compass.position = Gravity.TOP or Gravity.START compass.marginTop = 36f compass.marginBottom = 36f diff --git a/osmdroid/src/main/java/org/odk/collect/osmdroid/OsmDroidMapFragment.java b/osmdroid/src/main/java/org/odk/collect/osmdroid/OsmDroidMapFragment.java index eb081b9cc70..63154965de9 100644 --- a/osmdroid/src/main/java/org/odk/collect/osmdroid/OsmDroidMapFragment.java +++ b/osmdroid/src/main/java/org/odk/collect/osmdroid/OsmDroidMapFragment.java @@ -67,6 +67,7 @@ import org.osmdroid.views.overlay.Overlay; import org.osmdroid.views.overlay.Polygon; import org.osmdroid.views.overlay.Polyline; +import org.osmdroid.views.overlay.ScaleBarOverlay; import org.osmdroid.views.overlay.TilesOverlay; import org.osmdroid.views.overlay.mylocation.IMyLocationConsumer; import org.osmdroid.views.overlay.mylocation.IMyLocationProvider; @@ -201,6 +202,7 @@ public View onCreateView(@NonNull LayoutInflater inflater, map.getController().setZoom((int) INITIAL_ZOOM); map.setTilesScaledToDpi(true); map.setFlingEnabled(false); + map.getOverlays().add(new ScaleBarOverlay(map)); addAttributionAndMapEventsOverlays(); loadReferenceOverlay(); addMapLayoutChangeListener(map);