From 6319da544580f184c3e81a6b0d6d63f9607f9b1e Mon Sep 17 00:00:00 2001 From: Kanahia <114223204+kanahia1@users.noreply.github.com> Date: Thu, 18 Jan 2024 10:58:53 +0530 Subject: [PATCH] Replaced mapbox to osmdroid (Upload Activity) (#5443) * Fixed Grey empty screen at Upload wizard caption step after denying files permission * Empty commit * Fixed loop issue * Created docs for earlier commits * Fixed javadoc * Fixed spaces * Added added basic features to OSM Maps * Added search location feature * Added filter to Open Street Maps * Fixed chipGroup in Open Street Maps * Removed mapBox code * Removed mapBox's code * Reformat code * Reformatted code * Removed rotation feature to map * Removed rotation files and Fixed Marker click problem * Ignored failing tests * Added voice input feature * Fixed test cases * Changed caption and description text * Replaced mapbox to osmdroid in upload activity * Fixed Unit Tests * Made selected marker to be fixed on map * Changed color of map marker --- .../LocationPickerActivity.java | 438 +++++++----------- .../drawable-hdpi/map_default_map_marker.png | Bin 4543 -> 0 bytes .../drawable-mdpi/map_default_map_marker.png | Bin 2771 -> 0 bytes .../drawable-xhdpi/map_default_map_marker.png | Bin 6194 -> 0 bytes .../map_default_map_marker.png | Bin 10777 -> 0 bytes .../map_default_map_marker.png | Bin 15733 -> 0 bytes .../res/drawable/map_default_map_marker.xml | 18 + .../res/layout/content_location_picker.xml | 12 +- .../LocationPickerActivityUnitTests.kt | 120 +---- 9 files changed, 206 insertions(+), 382 deletions(-) delete mode 100644 app/src/main/res/drawable-hdpi/map_default_map_marker.png delete mode 100644 app/src/main/res/drawable-mdpi/map_default_map_marker.png delete mode 100644 app/src/main/res/drawable-xhdpi/map_default_map_marker.png delete mode 100644 app/src/main/res/drawable-xxhdpi/map_default_map_marker.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/map_default_map_marker.png create mode 100644 app/src/main/res/drawable/map_default_map_marker.xml diff --git a/app/src/main/java/fr/free/nrw/commons/LocationPicker/LocationPickerActivity.java b/app/src/main/java/fr/free/nrw/commons/LocationPicker/LocationPickerActivity.java index 34ee9ec41..ef4b31a36 100644 --- a/app/src/main/java/fr/free/nrw/commons/LocationPicker/LocationPickerActivity.java +++ b/app/src/main/java/fr/free/nrw/commons/LocationPicker/LocationPickerActivity.java @@ -1,21 +1,20 @@ package fr.free.nrw.commons.LocationPicker; -import static com.mapbox.mapboxsdk.style.layers.Property.NONE; -import static com.mapbox.mapboxsdk.style.layers.Property.VISIBLE; -import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap; -import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconIgnorePlacement; -import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage; -import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility; import static fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.LAST_LOCATION; import static fr.free.nrw.commons.upload.mediaDetails.UploadMediaDetailFragment.LAST_ZOOM; +import static fr.free.nrw.commons.utils.MapUtils.ZOOM_LEVEL; +import android.annotation.SuppressLint; import android.content.Intent; import android.content.pm.PackageManager; -import android.graphics.BitmapFactory; -import android.location.Location; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.drawable.Drawable; import android.os.Bundle; +import android.preference.PreferenceManager; import android.text.Html; import android.text.method.LinkMovementMethod; +import android.view.MotionEvent; import android.view.View; import android.view.Window; import android.view.animation.OvershootInterpolator; @@ -28,32 +27,10 @@ import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.AppCompatTextView; import androidx.constraintlayout.widget.ConstraintLayout; -import androidx.lifecycle.Observer; -import androidx.lifecycle.ViewModelProvider; +import androidx.core.content.ContextCompat; import com.google.android.material.floatingactionbutton.FloatingActionButton; -import com.mapbox.geojson.Point; import com.mapbox.mapboxsdk.camera.CameraPosition; -import com.mapbox.mapboxsdk.camera.CameraPosition.Builder; -import com.mapbox.mapboxsdk.camera.CameraUpdateFactory; import com.mapbox.mapboxsdk.geometry.LatLng; -import com.mapbox.mapboxsdk.location.LocationComponent; -import com.mapbox.mapboxsdk.location.LocationComponentActivationOptions; -import com.mapbox.mapboxsdk.location.engine.LocationEngineCallback; -import com.mapbox.mapboxsdk.location.engine.LocationEngineResult; -import com.mapbox.mapboxsdk.location.modes.CameraMode; -import com.mapbox.mapboxsdk.location.modes.RenderMode; -import com.mapbox.mapboxsdk.location.permissions.PermissionsManager; -import com.mapbox.mapboxsdk.maps.MapView; -import com.mapbox.mapboxsdk.maps.MapboxMap; -import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener; -import com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveStartedListener; -import com.mapbox.mapboxsdk.maps.OnMapReadyCallback; -import com.mapbox.mapboxsdk.maps.Style; -import com.mapbox.mapboxsdk.maps.UiSettings; -import com.mapbox.mapboxsdk.style.layers.Layer; -import com.mapbox.mapboxsdk.style.layers.SymbolLayer; -import com.mapbox.mapboxsdk.style.sources.GeoJsonSource; -import fr.free.nrw.commons.MapStyle; import fr.free.nrw.commons.R; import fr.free.nrw.commons.Utils; import fr.free.nrw.commons.filepicker.Constants; @@ -64,21 +41,24 @@ import fr.free.nrw.commons.location.LocationPermissionsHelper.LocationPermission import fr.free.nrw.commons.location.LocationServiceManager; import fr.free.nrw.commons.theme.BaseActivity; import fr.free.nrw.commons.utils.SystemThemeUtils; +import java.util.List; import javax.inject.Inject; import javax.inject.Named; -import org.jetbrains.annotations.NotNull; -import timber.log.Timber; +import org.osmdroid.tileprovider.tilesource.TileSourceFactory; +import org.osmdroid.util.GeoPoint; +import org.osmdroid.util.constants.GeoConstants; +import org.osmdroid.views.CustomZoomButtonsController; +import org.osmdroid.views.overlay.Marker; +import org.osmdroid.views.overlay.Overlay; +import org.osmdroid.views.overlay.ScaleDiskOverlay; +import org.osmdroid.views.overlay.TilesOverlay; /** * Helps to pick location and return the result with an intent */ -public class LocationPickerActivity extends BaseActivity implements OnMapReadyCallback, - OnCameraMoveStartedListener, OnCameraIdleListener, Observer, LocationPermissionCallback { +public class LocationPickerActivity extends BaseActivity implements + LocationPermissionCallback { - /** - * DROPPED_MARKER_LAYER_ID : id for layer - */ - private static final String DROPPED_MARKER_LAYER_ID = "DROPPED_MARKER_LAYER_ID"; /** * cameraPosition : position of picker */ @@ -88,13 +68,9 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa */ private ImageView markerImage; /** - * mapboxMap : map + * mapView : OSM Map */ - private MapboxMap mapboxMap; - /** - * mapView : view of the map - */ - private MapView mapView; + private org.osmdroid.views.MapView mapView; /** * tvAttribution : credit */ @@ -103,10 +79,6 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa * activity : activity key */ private String activity; - /** - * location : location - */ - private Location location; /** * modifyLocationButton : button for start editing location */ @@ -123,10 +95,6 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa * fabCenterOnLocation: button for center on location; */ FloatingActionButton fabCenterOnLocation; - /** - * droppedMarkerLayer : Layer for static screen - */ - private Layer droppedMarkerLayer; /** * shadow : imageview of shadow */ @@ -152,16 +120,19 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa @Inject SystemThemeUtils systemThemeUtils; private boolean isDarkTheme; + private boolean moveToCurrentLocation; @Inject LocationServiceManager locationManager; + @SuppressLint("ClickableViewAccessibility") @Override protected void onCreate(@Nullable final Bundle savedInstanceState) { getWindow().requestFeature(Window.FEATURE_ACTION_BAR); super.onCreate(savedInstanceState); isDarkTheme = systemThemeUtils.isDeviceInNightMode(); + moveToCurrentLocation = false; getWindow().requestFeature(Window.FEATURE_ACTION_BAR); final ActionBar actionBar = getSupportActionBar(); @@ -176,10 +147,6 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa activity = getIntent().getStringExtra(LocationPickerConstants.ACTIVITY_KEY); } - final LocationPickerViewModel viewModel = new ViewModelProvider(this) - .get(LocationPickerViewModel.class); - viewModel.getResult().observe(this, this); - bindViews(); addBackButtonListener(); addPlaceSelectedButton(); @@ -187,6 +154,31 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa getToolbarUI(); addCenterOnGPSButton(); + org.osmdroid.config.Configuration.getInstance().load(getApplicationContext(), + PreferenceManager.getDefaultSharedPreferences(getApplicationContext())); + + mapView.setTileSource(TileSourceFactory.WIKIMEDIA); + mapView.setTilesScaledToDpi(true); + mapView.setMultiTouchControls(true); + + org.osmdroid.config.Configuration.getInstance().getAdditionalHttpRequestProperties().put( + "Referer", "http://maps.wikimedia.org/" + ); + mapView.getZoomController().setVisibility(CustomZoomButtonsController.Visibility.NEVER); + mapView.getController().setZoom(ZOOM_LEVEL); + mapView.setOnTouchListener((v, event) -> { + if (event.getAction() == MotionEvent.ACTION_MOVE) { + if (markerImage.getTranslationY() == 0) { + markerImage.animate().translationY(-75) + .setInterpolator(new OvershootInterpolator()).setDuration(250).start(); + } + } else if (event.getAction() == MotionEvent.ACTION_UP) { + markerImage.animate().translationY(0) + .setInterpolator(new OvershootInterpolator()).setDuration(250).start(); + } + return false; + }); + if ("UploadActivity".equals(activity)) { placeSelectedButton.setVisibility(View.GONE); modifyLocationButton.setVisibility(View.VISIBLE); @@ -195,10 +187,13 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa smallToolbarText.setText(getResources(). getString(R.string.check_whether_location_is_correct)); fabCenterOnLocation.setVisibility(View.GONE); + markerImage.setVisibility(View.GONE); + shadow.setVisibility(View.GONE); + assert cameraPosition.target != null; + showSelectedLocationMarker(new GeoPoint(cameraPosition.target.getLatitude(), + cameraPosition.target.getLongitude())); } - - mapView.onCreate(savedInstanceState); - mapView.getMapAsync(this); + setupMapView(); } /** @@ -209,6 +204,17 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa tvAttribution.setMovementMethod(LinkMovementMethod.getInstance()); } + /** + * For setting up Dark Theme + */ + private void darkThemeSetup() { + if (isDarkTheme) { + shadow.setColorFilter(Color.argb(255, 255, 255, 255)); + mapView.getOverlayManager().getTilesOverlay() + .setColorFilter(TilesOverlay.INVERT_COLORS); + } + } + /** * Clicking back button destroy locationPickerActivity */ @@ -230,16 +236,6 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa shadow = findViewById(R.id.location_picker_image_view_shadow); } - /** - * Binds the listeners - */ - private void bindListeners() { - mapboxMap.addOnCameraMoveStartedListener( - this); - mapboxMap.addOnCameraIdleListener( - this); - } - /** * Gets toolbar color */ @@ -250,49 +246,12 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa toolbar.setBackgroundColor(getResources().getColor(R.color.primaryColor)); } - /** - * Takes action when map is ready to show - * @param mapboxMap map - */ - @Override - public void onMapReady(final MapboxMap mapboxMap) { - this.mapboxMap = mapboxMap; - mapboxMap.setStyle(isDarkTheme ? MapStyle.DARK : MapStyle.STREETS, this::onStyleLoaded); - } - - /** - * Initializes dropped marker and layer - * Handles camera position based on options - * Enables location components - * - * @param style style - */ - private void onStyleLoaded(final Style style) { - if (modifyLocationButton.getVisibility() == View.VISIBLE) { - initDroppedMarker(style); - adjustCameraBasedOnOptions(); - enableLocationComponent(style); - if (style.getLayer(DROPPED_MARKER_LAYER_ID) != null) { - final GeoJsonSource source = style.getSourceAs("dropped-marker-source-id"); - if (source != null) { - source.setGeoJson(Point.fromLngLat(cameraPosition.target.getLongitude(), - cameraPosition.target.getLatitude())); - } - droppedMarkerLayer = style.getLayer(DROPPED_MARKER_LAYER_ID); - if (droppedMarkerLayer != null) { - droppedMarkerLayer.setProperties(visibility(VISIBLE)); - markerImage.setVisibility(View.GONE); - shadow.setVisibility(View.GONE); - } - } - } else { - adjustCameraBasedOnOptions(); - enableLocationComponent(style); - bindListeners(); - } - + private void setupMapView() { + adjustCameraBasedOnOptions(); modifyLocationButton.setOnClickListener(v -> onClickModifyLocation()); showInMapButton.setOnClickListener(v -> showInMap()); + darkThemeSetup(); + requestLocationPermissions(); } /** @@ -302,13 +261,16 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa placeSelectedButton.setVisibility(View.VISIBLE); modifyLocationButton.setVisibility(View.GONE); showInMapButton.setVisibility(View.GONE); - droppedMarkerLayer.setProperties(visibility(NONE)); markerImage.setVisibility(View.VISIBLE); shadow.setVisibility(View.VISIBLE); largeToolbarText.setText(getResources().getString(R.string.choose_a_location)); smallToolbarText.setText(getResources().getString(R.string.pan_and_zoom_to_adjust)); - bindListeners(); fabCenterOnLocation.setVisibility(View.VISIBLE); + removeSelectedLocationMarker(); + if (cameraPosition.target != null) { + mapView.getController().animateTo(new GeoPoint(cameraPosition.target.getLatitude(), + cameraPosition.target.getLongitude())); + } } /** @@ -316,120 +278,20 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa */ public void showInMap() { Utils.handleGeoCoordinates(this, - new fr.free.nrw.commons.location.LatLng(cameraPosition.target.getLatitude(), - cameraPosition.target.getLongitude(), 0.0f)); - } - - /** - * Initialize Dropped Marker and layer without showing - * @param loadedMapStyle style - */ - private void initDroppedMarker(@NonNull final Style loadedMapStyle) { - // Add the marker image to map - loadedMapStyle.addImage("dropped-icon-image", BitmapFactory.decodeResource( - getResources(), R.drawable.map_default_map_marker)); - loadedMapStyle.addSource(new GeoJsonSource("dropped-marker-source-id")); - loadedMapStyle.addLayer(new SymbolLayer(DROPPED_MARKER_LAYER_ID, - "dropped-marker-source-id").withProperties( - iconImage("dropped-icon-image"), - visibility(NONE), - iconAllowOverlap(true), - iconIgnorePlacement(true) - )); + new fr.free.nrw.commons.location.LatLng(mapView.getMapCenter().getLatitude(), + mapView.getMapCenter().getLongitude(), 0.0f)); } /** * move the location to the current media coordinates */ private void adjustCameraBasedOnOptions() { - mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)); - } - - /** - * Enables location components - * @param loadedMapStyle Style - */ - @SuppressWarnings( {"MissingPermission"}) - private void enableLocationComponent(@NonNull final Style loadedMapStyle) { - final UiSettings uiSettings = mapboxMap.getUiSettings(); - uiSettings.setAttributionEnabled(false); - - // Check if permissions are enabled and if not request - if (PermissionsManager.areLocationPermissionsGranted(this)) { - - // Get an instance of the component - final LocationComponent locationComponent = mapboxMap.getLocationComponent(); - - // Activate with options - locationComponent.activateLocationComponent( - LocationComponentActivationOptions.builder(this, loadedMapStyle).build()); - - // Enable to make component visible - locationComponent.setLocationComponentEnabled(true); - - // Set the component's camera mode - locationComponent.setCameraMode(CameraMode.NONE); - - // Set the component's render mode - locationComponent.setRenderMode(RenderMode.NORMAL); - - // Get the component's location engine to receive user's last location - locationComponent.getLocationEngine().getLastLocation( - new LocationEngineCallback() { - @Override - public void onSuccess(LocationEngineResult result) { - location = result.getLastLocation(); - } - - @Override - public void onFailure(@NonNull Exception exception) { - } - }); - - - } else { - requestLocationPermissions(); + if (cameraPosition.target != null) { + mapView.getController().setCenter(new GeoPoint(cameraPosition.target.getLatitude(), + cameraPosition.target.getLongitude())); } } - /** - * Acts on camera moving - * @param reason int - */ - @Override - public void onCameraMoveStarted(final int reason) { - Timber.v("Map camera has begun moving."); - if (markerImage.getTranslationY() == 0) { - markerImage.animate().translationY(-75) - .setInterpolator(new OvershootInterpolator()).setDuration(250).start(); - } - } - - /** - * Acts on camera idle - */ - @Override - public void onCameraIdle() { - Timber.v("Map camera is now idling."); - markerImage.animate().translationY(0) - .setInterpolator(new OvershootInterpolator()).setDuration(250).start(); - } - - /** - * Takes action on camera position - * @param position position of picker - */ - @Override - public void onChanged(@Nullable CameraPosition position) { - if (position == null) { - position = new Builder() - .target(new LatLng(mapboxMap.getCameraPosition().target.getLatitude(), - mapboxMap.getCameraPosition().target.getLongitude())) - .zoom(16).build(); - } - cameraPosition = position; - } - /** * Select the preferable location */ @@ -444,23 +306,60 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa void placeSelected() { if (activity.equals("NoLocationUploadActivity")) { applicationKvStore.putString(LAST_LOCATION, - mapboxMap.getCameraPosition().target.getLatitude() + mapView.getMapCenter().getLatitude() + "," - + mapboxMap.getCameraPosition().target.getLongitude()); - applicationKvStore.putString(LAST_ZOOM, mapboxMap.getCameraPosition().zoom + ""); + + mapView.getMapCenter().getLongitude()); + applicationKvStore.putString(LAST_ZOOM, mapView.getZoomLevel() + ""); } final Intent returningIntent = new Intent(); returningIntent.putExtra(LocationPickerConstants.MAP_CAMERA_POSITION, - mapboxMap.getCameraPosition()); + new CameraPosition(new LatLng(mapView.getMapCenter().getLatitude(), + mapView.getMapCenter().getLongitude()), 14f, 0, 0)); setResult(AppCompatActivity.RESULT_OK, returningIntent); finish(); } + /** * Center the camera on the last saved location */ - private void addCenterOnGPSButton(){ + private void addCenterOnGPSButton() { fabCenterOnLocation = findViewById(R.id.center_on_gps); - fabCenterOnLocation.setOnClickListener(view -> requestLocationPermissions()); + fabCenterOnLocation.setOnClickListener(view -> { + moveToCurrentLocation = true; + requestLocationPermissions(); + }); + } + + /** + * Adds selected location marker on the map + */ + private void showSelectedLocationMarker(GeoPoint point) { + Drawable icon = ContextCompat.getDrawable(this, R.drawable.map_default_map_marker); + Marker marker = new Marker(mapView); + marker.setPosition(point); + marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM); + marker.setIcon(icon); + marker.setInfoWindow(null); + mapView.getOverlays().add(marker); + mapView.invalidate(); + } + + /** + * Removes selected location marker from the map + */ + private void removeSelectedLocationMarker() { + List overlays = mapView.getOverlays(); + for (int i = 0; i < overlays.size(); i++) { + if (overlays.get(i) instanceof Marker) { + Marker item = (Marker) overlays.get(i); + if (cameraPosition.target.getLatitude() == item.getPosition().getLatitude() + && cameraPosition.target.getLongitude() == item.getPosition().getLongitude()) { + mapView.getOverlays().remove(i); + mapView.invalidate(); + break; + } + } + } } /** @@ -478,13 +377,16 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa ); LocationPermissionsHelper locationPermissionsHelper = new LocationPermissionsHelper( this, locationManager, this); - locationPermissionsHelper.handleLocationPermissions(locationAccessDialog, locationOffDialog); + locationPermissionsHelper.handleLocationPermissions(locationAccessDialog, + locationOffDialog); } @Override - public void onRequestPermissionsResult(final int requestCode, @NonNull final String[] permissions, + public void onRequestPermissionsResult(final int requestCode, + @NonNull final String[] permissions, @NonNull final int[] grantResults) { - if (requestCode == Constants.RequestCodes.LOCATION && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + if (requestCode == Constants.RequestCodes.LOCATION + && grantResults[0] == PackageManager.PERMISSION_GRANTED) { onLocationPermissionGranted(); } else { onLocationPermissionDenied(""); @@ -492,12 +394,6 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa super.onRequestPermissionsResult(requestCode, permissions, grantResults); } - @Override - protected void onStart() { - super.onStart(); - mapView.onStart(); - } - @Override protected void onResume() { super.onResume(); @@ -510,30 +406,6 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa mapView.onPause(); } - @Override - protected void onStop() { - super.onStop(); - mapView.onStop(); - } - - @Override - protected void onSaveInstanceState(final @NotNull 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 void onLocationPermissionDenied(String toastMessage) { //do nothing @@ -541,19 +413,49 @@ public class LocationPickerActivity extends BaseActivity implements OnMapReadyCa @Override public void onLocationPermissionGranted() { - if (mapboxMap.getStyle() != null) { - enableLocationComponent(mapboxMap.getStyle()); - } fr.free.nrw.commons.location.LatLng currLocation = locationManager.getLastLocation(); if (currLocation != null) { - final CameraPosition position; - position = new CameraPosition.Builder() - .target(new com.mapbox.mapboxsdk.geometry.LatLng(currLocation.getLatitude(), - currLocation.getLongitude(), 0)) // Sets the new camera position - .zoom(mapboxMap.getCameraPosition().zoom) // Same zoom level - .build(); - - mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(position), 1000); + GeoPoint currLocationGeopoint = new GeoPoint(currLocation.getLatitude(), + currLocation.getLongitude()); + addLocationMarker(currLocationGeopoint); + if (moveToCurrentLocation) { + mapView.getController().setCenter(currLocationGeopoint); + mapView.getController().animateTo(currLocationGeopoint); + moveToCurrentLocation = false; + } + markerImage.setTranslationY(0); } } + + private void addLocationMarker(GeoPoint geoPoint) { + if (moveToCurrentLocation) { + mapView.getOverlays().clear(); + } + ScaleDiskOverlay diskOverlay = + new ScaleDiskOverlay(this, + geoPoint, 2000, GeoConstants.UnitOfMeasure.foot); + Paint circlePaint = new Paint(); + circlePaint.setColor(Color.rgb(128, 128, 128)); + circlePaint.setStyle(Paint.Style.STROKE); + circlePaint.setStrokeWidth(2f); + diskOverlay.setCirclePaint2(circlePaint); + Paint diskPaint = new Paint(); + diskPaint.setColor(Color.argb(40, 128, 128, 128)); + diskPaint.setStyle(Paint.Style.FILL_AND_STROKE); + diskOverlay.setCirclePaint1(diskPaint); + diskOverlay.setDisplaySizeMin(900); + diskOverlay.setDisplaySizeMax(1700); + mapView.getOverlays().add(diskOverlay); + org.osmdroid.views.overlay.Marker startMarker = new org.osmdroid.views.overlay.Marker( + mapView); + startMarker.setPosition(geoPoint); + startMarker.setAnchor(org.osmdroid.views.overlay.Marker.ANCHOR_CENTER, + org.osmdroid.views.overlay.Marker.ANCHOR_BOTTOM); + startMarker.setIcon( + ContextCompat.getDrawable(this, R.drawable.current_location_marker)); + startMarker.setTitle("Your Location"); + startMarker.setTextLabelFontSize(24); + mapView.getOverlays().add(startMarker); + } + } diff --git a/app/src/main/res/drawable-hdpi/map_default_map_marker.png b/app/src/main/res/drawable-hdpi/map_default_map_marker.png deleted file mode 100644 index ef993a0f55ae78fc0cfb0347c655eb73c9d6f0bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4543 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 S)1NOI!1%I-e$^${xPJkL9ayda diff --git a/app/src/main/res/drawable-mdpi/map_default_map_marker.png b/app/src/main/res/drawable-mdpi/map_default_map_marker.png deleted file mode 100644 index 45ca4ab58f3738c2c05c4910549db1b4bac606a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2771 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 O($dVy-kx6Ab1B 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 + + + + + diff --git a/app/src/main/res/layout/content_location_picker.xml b/app/src/main/res/layout/content_location_picker.xml index 656f4cdd0..c8627e4da 100644 --- a/app/src/main/res/layout/content_location_picker.xml +++ b/app/src/main/res/layout/content_location_picker.xml @@ -22,17 +22,15 @@ android:id="@+id/location_picker_image_view_shadow" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:contentDescription="@string/location_picker_image_view_shadow" android:elevation="1dp" - app:layout_constraintBottom_toBottomOf="@+id/map_view" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="@+id/location_picker_image_view_marker" - app:layout_constraintVertical_bias="0.0" - app:srcCompat="@drawable/map_default_map_marker_shadow" - android:contentDescription="@string/location_picker_image_view_shadow" /> + app:srcCompat="@drawable/map_default_map_marker_shadow" /> - + app:layout_constraintTop_toTopOf="parent"/> + - diff --git a/app/src/test/kotlin/fr/free/nrw/commons/locationpicker/LocationPickerActivityUnitTests.kt b/app/src/test/kotlin/fr/free/nrw/commons/locationpicker/LocationPickerActivityUnitTests.kt index 1b45102db..ca1826c95 100644 --- a/app/src/test/kotlin/fr/free/nrw/commons/locationpicker/LocationPickerActivityUnitTests.kt +++ b/app/src/test/kotlin/fr/free/nrw/commons/locationpicker/LocationPickerActivityUnitTests.kt @@ -32,6 +32,8 @@ import org.junit.runner.RunWith import org.mockito.Mock import org.mockito.Mockito.* import org.mockito.MockitoAnnotations +import org.osmdroid.api.IMapController +import org.osmdroid.util.GeoPoint import org.powermock.reflect.Whitebox import org.robolectric.Robolectric import org.robolectric.RobolectricTestRunner @@ -54,7 +56,7 @@ class LocationPickerActivityUnitTests { private lateinit var applicationKvStore: JsonKvStore @Mock - private lateinit var mapboxMap: MapboxMap + private lateinit var mapView: org.osmdroid.views.MapView @Mock private lateinit var cameraPosition: CameraPosition @@ -68,9 +70,6 @@ class LocationPickerActivityUnitTests { @Mock private lateinit var showInMapButton: TextView - @Mock - private lateinit var droppedMarkerLayer: Layer - @Mock private lateinit var markerImage: ImageView @@ -89,22 +88,18 @@ class LocationPickerActivityUnitTests { @Mock private lateinit var tvAttribution: AppCompatTextView - @Mock - private lateinit var style: Style - @Before fun setUp() { MockitoAnnotations.initMocks(this) context = RuntimeEnvironment.getApplication().applicationContext activity = Robolectric.buildActivity(LocationPickerActivity::class.java).get() - Whitebox.setInternalState(activity, "mapboxMap", mapboxMap) + Whitebox.setInternalState(activity, "mapView", mapView) Whitebox.setInternalState(activity, "applicationKvStore", applicationKvStore) Whitebox.setInternalState(activity, "cameraPosition", cameraPosition) Whitebox.setInternalState(activity, "modifyLocationButton", modifyLocationButton) Whitebox.setInternalState(activity, "placeSelectedButton", placeSelectedButton) Whitebox.setInternalState(activity, "showInMapButton", showInMapButton) - Whitebox.setInternalState(activity, "droppedMarkerLayer", droppedMarkerLayer) Whitebox.setInternalState(activity, "markerImage", markerImage) Whitebox.setInternalState(activity, "shadow", shadow) Whitebox.setInternalState(activity, "largeToolbarText", largeToolbarText) @@ -119,42 +114,6 @@ class LocationPickerActivityUnitTests { Assert.assertNotNull(activity) } - @Test - @Throws(Exception::class) - fun testBindListeners() { - val method: Method = LocationPickerActivity::class.java.getDeclaredMethod( - "bindListeners" - ) - method.isAccessible = true - method.invoke(activity) - verify(mapboxMap, times(1)).addOnCameraMoveStartedListener(activity) - verify(mapboxMap, times(1)).addOnCameraIdleListener(activity) - } - - @Test - @Throws(Exception::class) - fun testOnMapReady() { - val method: Method = LocationPickerActivity::class.java.getDeclaredMethod( - "onMapReady", - MapboxMap::class.java - ) - method.isAccessible = true - try { - method.invoke(activity, mapboxMap) - fail("Expected an exception to be thrown") - } catch (e: InvocationTargetException) { - assertTrue((e.targetException is MapboxConfigurationException) || - (e.targetException is ExceptionInInitializerError)) - if (e.targetException is MapboxConfigurationException) { - assertEquals( - "\nUsing MapView requires calling Mapbox.getInstance(Context context, String apiKey," - + " WellKnownTileServer wellKnownTileServer) before inflating or creating the view.", - e.targetException.message - ) - } - } - } - @Test @Throws(Exception::class) fun testAddCredits() { @@ -167,49 +126,6 @@ class LocationPickerActivityUnitTests { verify(tvAttribution).movementMethod = any() } - @Test - @Throws(Exception::class) - fun testAdjustCameraBasedOnOptions() { - val method: Method = LocationPickerActivity::class.java.getDeclaredMethod( - "adjustCameraBasedOnOptions" - ) - method.isAccessible = true - method.invoke(activity) - verify(mapboxMap, times(1)) - .moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)) - } - - @Test - @Throws(Exception::class) - fun testOnChanged() { - val method: Method = LocationPickerActivity::class.java.getDeclaredMethod( - "onChanged", - CameraPosition::class.java - ) - method.isAccessible = true - method.invoke(activity, mock(CameraPosition::class.java)) - verify(mapboxMap, times(0)).cameraPosition - } - - @Test - @Throws(Exception::class) - fun testOnStyleLoaded() { - whenever(modifyLocationButton.visibility).thenReturn(View.INVISIBLE) - whenever(mapboxMap.uiSettings).thenReturn(mock(UiSettings::class.java)) - val method: Method = LocationPickerActivity::class.java.getDeclaredMethod( - "onStyleLoaded", - Style::class.java - ) - method.isAccessible = true - method.invoke(activity, style) - verify(modifyLocationButton, times(1)).visibility - verify(mapboxMap, times(1)) - .moveCamera(CameraUpdateFactory.newCameraPosition(cameraPosition)) - verify(mapboxMap, times(1)).uiSettings - verify(mapboxMap, times(1)).addOnCameraMoveStartedListener(activity) - verify(mapboxMap, times(1)).addOnCameraIdleListener(activity) - } - @Test @Throws(Exception::class) fun testOnClickModifyLocation() { @@ -223,12 +139,9 @@ class LocationPickerActivityUnitTests { verify(showInMapButton, times(1)).visibility = View.GONE verify(markerImage, times(1)).visibility = View.VISIBLE verify(shadow, times(1)).visibility = View.VISIBLE - verify(droppedMarkerLayer, times(1)).setProperties(any()) verify(largeToolbarText, times(1)).text = "Choose a location" verify(smallToolbarText, times(1)).text = "Pan and zoom to adjust" verify(fabCenterOnLocation, times(1)).visibility = View.VISIBLE - verify(mapboxMap, times(1)).addOnCameraMoveStartedListener(activity) - verify(mapboxMap, times(1)).addOnCameraIdleListener(activity) } @Test @@ -236,27 +149,20 @@ class LocationPickerActivityUnitTests { fun testPlaceSelected() { Shadows.shadowOf(Looper.getMainLooper()).idle() Whitebox.setInternalState(activity,"activity", "NoLocationUploadActivity") - val position = CameraPosition.Builder().target( - LatLng( - 51.50550, - -0.07520, - 0.0 - ) - ).zoom(15.0).build() - `when`(mapboxMap.cameraPosition).thenReturn(position) + val position = GeoPoint(51.50550, -0.07520) val method: Method = LocationPickerActivity::class.java.getDeclaredMethod( "placeSelected" ) + `when`(mapView.mapCenter).thenReturn(position) + `when`(mapView.zoomLevel).thenReturn(15) method.isAccessible = true method.invoke(activity) - verify(applicationKvStore, times(1)) - .putString(LAST_LOCATION, position.target!!.latitude.toString() - + "," - + position.target!!.longitude - ) - verify(applicationKvStore, times(1)) - .putString(LAST_ZOOM, position.zoom.toString()) - verify(mapboxMap, times(4)).cameraPosition + verify(applicationKvStore, times(1)).putString( + LAST_LOCATION, + position.latitude.toString() + "," + position.longitude.toString() + ) + verify(applicationKvStore, times(1)).putString(LAST_ZOOM, mapView.zoomLevel.toString()) } + } \ No newline at end of file