From f7ed7f1e93e4158c5fc4be2082c92d0233c3e7bf Mon Sep 17 00:00:00 2001 From: johan12345 Date: Mon, 20 Jul 2020 22:39:22 +0200 Subject: [PATCH] use AnyMaps to make the map view able to use OSM maps --- app/build.gradle | 6 ++ .../vonforst/evmap/fragment/MapFragment.kt | 90 ++++++++++++------- .../net/vonforst/evmap/ui/IconGenerators.kt | 8 +- .../java/net/vonforst/evmap/ui/MarkerUtils.kt | 39 ++++---- .../vonforst/evmap/viewmodel/MapViewModel.kt | 12 +-- app/src/main/res/layout/fragment_map.xml | 5 +- app/src/main/res/layout/map_layers.xml | 14 +-- 7 files changed, 104 insertions(+), 70 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9076d1ec..5dba6397 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -98,6 +98,12 @@ dependencies { implementation 'com.airbnb.android:lottie:3.4.0' implementation 'io.michaelrocks:bimap:1.0.2' + // AnyMaps + def anyMapsVersion = 'd48b22df9f' + implementation "com.github.johan12345.AnyMaps:anymaps-base:$anyMapsVersion" + implementation "com.github.johan12345.AnyMaps:anymaps-google:$anyMapsVersion" + implementation "com.github.johan12345.AnyMaps:anymaps-osm:$anyMapsVersion" + // Google Maps v3 Beta implementation 'com.google.android.libraries.maps:maps:3.1.0-beta' implementation name:'places-maps-sdk-3.1.0-beta', ext:'aar' diff --git a/app/src/main/java/net/vonforst/evmap/fragment/MapFragment.kt b/app/src/main/java/net/vonforst/evmap/fragment/MapFragment.kt index 67ff6e01..71c231af 100644 --- a/app/src/main/java/net/vonforst/evmap/fragment/MapFragment.kt +++ b/app/src/main/java/net/vonforst/evmap/fragment/MapFragment.kt @@ -33,13 +33,15 @@ import androidx.recyclerview.widget.DividerItemDecoration import androidx.recyclerview.widget.LinearLayoutManager import androidx.transition.TransitionInflater import androidx.transition.TransitionManager +import com.car2go.maps.AnyMap +import com.car2go.maps.MapFragment +import com.car2go.maps.OnMapReadyCallback +import com.car2go.maps.model.LatLng +import com.car2go.maps.model.Marker +import com.car2go.maps.model.MarkerOptions +import com.car2go.maps.osm.MapsConfiguration import com.google.android.gms.location.FusedLocationProviderClient import com.google.android.gms.location.LocationServices -import com.google.android.libraries.maps.CameraUpdateFactory -import com.google.android.libraries.maps.GoogleMap -import com.google.android.libraries.maps.OnMapReadyCallback -import com.google.android.libraries.maps.SupportMapFragment -import com.google.android.libraries.maps.model.* import com.google.android.libraries.places.api.model.Place import com.google.android.libraries.places.widget.Autocomplete import com.google.android.libraries.places.widget.model.AutocompleteActivityMode @@ -83,7 +85,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac } }) private val galleryVm: GalleryViewModel by activityViewModels() - private var map: GoogleMap? = null + private var map: AnyMap? = null private lateinit var fusedLocationClient: FusedLocationProviderClient private lateinit var bottomSheetBehavior: BottomSheetBehaviorGoogleMapsLike private lateinit var detailAppBarBehavior: MergedAppBarLayoutBehavior @@ -116,6 +118,11 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac } } + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + MapsConfiguration.getInstance().initialize(context) + } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, @@ -127,8 +134,6 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac fusedLocationClient = LocationServices.getFusedLocationProviderClient(requireContext()) clusterIconGenerator = ClusterIconGenerator(requireContext()) - chargerIconGenerator = ChargerIconGenerator(requireContext()) - animator = MarkerAnimator(chargerIconGenerator) setHasOptionsMenu(true) postponeEnterTransition() @@ -153,7 +158,7 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - val mapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment + val mapFragment = childFragmentManager.findFragmentById(R.id.map) as MapFragment mapFragment.getMapAsync(this) bottomSheetBehavior = BottomSheetBehaviorGoogleMapsLike.from(binding.bottomSheet) detailAppBarBehavior = MergedAppBarLayoutBehavior.from(binding.detailAppBar) @@ -344,33 +349,33 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac vm.favorites.observe(viewLifecycleOwner, Observer { updateFavoriteToggle() }) - vm.searchResult.observe(viewLifecycleOwner, Observer { place -> + /* TODO: vm.searchResult.observe(viewLifecycleOwner, Observer { place -> val map = this.map ?: return@Observer searchResultMarker?.remove() searchResultMarker = null if (place != null) { if (place.viewport != null) { - map.animateCamera(CameraUpdateFactory.newLatLngBounds(place.viewport, 0)) + map.animateCamera(map.cameraUpdateFactory.newLatLngBounds(AnyMapAdapter.adapt(place.viewport), 0)) } else { - map.animateCamera(CameraUpdateFactory.newLatLngZoom(place.latLng, 12f)) + map.animateCamera(map.cameraUpdateFactory.newLatLngZoom(AnyMapAdapter.adapt(place.latLng), 12f)) } - searchResultMarker = map.addMarker(MarkerOptions().position(place.latLng!!)) + searchResultMarker = map.addMarker(MarkerOptions().position(AnyMapAdapter.adapt(place.latLng!!))).anchor(0.5f, 1f) } updateBackPressedCallback() - }) + })*/ vm.layersMenuOpen.observe(viewLifecycleOwner, Observer { open -> binding.fabLayers.visibility = if (open) View.GONE else View.VISIBLE binding.layersSheet.visibility = if (open) View.VISIBLE else View.GONE updateBackPressedCallback() }) vm.mapType.observe(viewLifecycleOwner, Observer { - map?.mapType = it + map?.setMapType(it) }) vm.mapTrafficEnabled.observe(viewLifecycleOwner, Observer { - map?.isTrafficEnabled = it + map?.setTrafficEnabled(it) }) updateBackPressedCallback() @@ -528,11 +533,13 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac }.show() } - override fun onMapReady(map: GoogleMap) { + override fun onMapReady(map: AnyMap) { this.map = map - map.uiSettings.isTiltGesturesEnabled = false - map.isIndoorEnabled = false - map.uiSettings.isIndoorLevelPickerEnabled = false + chargerIconGenerator = ChargerIconGenerator(requireContext(), map.bitmapDescriptorFactory) + animator = MarkerAnimator(chargerIconGenerator) + map.uiSettings.setTiltGesturesEnabled(false) + map.setIndoorEnabled(false) + map.uiSettings.setIndoorLevelPickerEnabled(false) map.setOnCameraIdleListener { vm.mapPosition.value = MapPosition( map.projection.visibleRegion.latLngBounds, map.cameraPosition.zoom @@ -546,7 +553,12 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac } in clusterMarkers -> { val newZoom = map.cameraPosition.zoom + 2 - map.animateCamera(CameraUpdateFactory.newLatLngZoom(marker.position, newZoom)) + map.animateCamera( + map.cameraUpdateFactory.newLatLngZoom( + marker.position, + newZoom + ) + ) true } else -> false @@ -563,11 +575,12 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac map.setPadding(0, binding.toolbarContainer.height, 0, 0) val mode = resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK + /* TODO: map.setMapStyle( if (mode == Configuration.UI_MODE_NIGHT_YES) { MapStyleOptions.loadRawResourceStyle(context, R.raw.maps_night_mode) } else null - ) + )*/ val position = vm.mapPosition.value @@ -577,12 +590,12 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac if (position != null) { val cameraUpdate = - CameraUpdateFactory.newLatLngZoom(position.bounds.center, position.zoom) + map.cameraUpdateFactory.newLatLngZoom(position.bounds.center, position.zoom) map.moveCamera(cameraUpdate) positionSet = true } else if (lat != null && lon != null) { // show given position - val cameraUpdate = CameraUpdateFactory.newLatLngZoom(LatLng(lat, lon), 16f) + val cameraUpdate = map.cameraUpdateFactory.newLatLngZoom(LatLng(lat, lon), 16f) map.moveCamera(cameraUpdate) // show charger detail after chargers were loaded @@ -609,7 +622,8 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac } if (!positionSet) { // center the camera on Europe - val cameraUpdate = CameraUpdateFactory.newLatLngZoom(LatLng(50.113388, 9.252536), 3.5f) + val cameraUpdate = + map.cameraUpdateFactory.newLatLngZoom(LatLng(50.113388, 9.252536), 3.5f) map.moveCamera(cameraUpdate) } @@ -621,14 +635,14 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac @SuppressLint("MissingPermission") private fun enableLocation(moveTo: Boolean, animate: Boolean) { val map = this.map ?: return - map.isMyLocationEnabled = true + map.setMyLocationEnabled(true) vm.myLocationEnabled.value = true - map.uiSettings.isMyLocationButtonEnabled = false + map.uiSettings.setMyLocationButtonEnabled(false) if (moveTo) { fusedLocationClient.lastLocation.addOnSuccessListener { location -> if (location != null) { val latLng = LatLng(location.latitude, location.longitude) - val camUpdate = CameraUpdateFactory.newLatLngZoom(latLng, 13f) + val camUpdate = map.cameraUpdateFactory.newLatLngZoom(latLng, 13f) if (animate) { map.animateCamera(camUpdate) } else { @@ -697,7 +711,16 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac val marker = map.addMarker( MarkerOptions() .position(LatLng(charger.coordinates.lat, charger.coordinates.lng)) - .visible(false) + .icon( + chargerIconGenerator.getBitmapDescriptor( + tint, + 0, + 255, + highlight, + fault + ) + ) + .anchor(0.5f, 1f) ) animator.animateMarkerAppear(marker, tint, highlight, fault) markers[marker] = charger @@ -709,7 +732,14 @@ class MapFragment : Fragment(), OnMapReadyCallback, MapsActivity.FragmentCallbac map.addMarker( MarkerOptions() .position(LatLng(cluster.coordinates.lat, cluster.coordinates.lng)) - .icon(BitmapDescriptorFactory.fromBitmap(clusterIconGenerator.makeIcon(cluster.clusterCount.toString()))) + .icon( + map.bitmapDescriptorFactory.fromBitmap( + clusterIconGenerator.makeIcon( + cluster.clusterCount.toString() + ) + ) + ) + .anchor(0.5f, 0.5f) ) } } diff --git a/app/src/main/java/net/vonforst/evmap/ui/IconGenerators.kt b/app/src/main/java/net/vonforst/evmap/ui/IconGenerators.kt index 01e7f055..0787d388 100644 --- a/app/src/main/java/net/vonforst/evmap/ui/IconGenerators.kt +++ b/app/src/main/java/net/vonforst/evmap/ui/IconGenerators.kt @@ -11,8 +11,8 @@ import androidx.annotation.ColorRes import androidx.core.content.ContextCompat import androidx.core.graphics.drawable.DrawableCompat import androidx.core.widget.TextViewCompat -import com.google.android.libraries.maps.model.BitmapDescriptor -import com.google.android.libraries.maps.model.BitmapDescriptorFactory +import com.car2go.maps.BitmapDescriptorFactory +import com.car2go.maps.model.BitmapDescriptor import com.google.maps.android.ui.IconGenerator import com.google.maps.android.ui.SquareTextView import net.vonforst.evmap.R @@ -41,7 +41,7 @@ class ClusterIconGenerator(context: Context) : IconGenerator(context) { } -class ChargerIconGenerator(val context: Context) { +class ChargerIconGenerator(val context: Context, val factory: BitmapDescriptorFactory) { data class BitmapData( val tint: Int, val scale: Int, @@ -94,7 +94,7 @@ class ChargerIconGenerator(val context: Context) { cachedImg } else { val bitmap = generateBitmap(data) - val bmd = BitmapDescriptorFactory.fromBitmap(bitmap) + val bmd = factory.fromBitmap(bitmap) cache.put(data, bmd) bmd } diff --git a/app/src/main/java/net/vonforst/evmap/ui/MarkerUtils.kt b/app/src/main/java/net/vonforst/evmap/ui/MarkerUtils.kt index 3870bacd..b2673b05 100644 --- a/app/src/main/java/net/vonforst/evmap/ui/MarkerUtils.kt +++ b/app/src/main/java/net/vonforst/evmap/ui/MarkerUtils.kt @@ -5,7 +5,7 @@ import android.view.animation.BounceInterpolator import androidx.core.animation.addListener import androidx.interpolator.view.animation.FastOutLinearInInterpolator import androidx.interpolator.view.animation.LinearOutSlowInInterpolator -import com.google.android.libraries.maps.model.Marker +import com.car2go.maps.model.Marker import net.vonforst.evmap.R import net.vonforst.evmap.api.goingelectric.ChargeLocation import kotlin.math.max @@ -22,7 +22,7 @@ fun getMarkerTint( } class MarkerAnimator(val gen: ChargerIconGenerator) { - private val animatingMarkers = hashMapOf() + private val animatingMarkers = hashMapOf() fun animateMarkerAppear( marker: Marker, @@ -30,9 +30,9 @@ class MarkerAnimator(val gen: ChargerIconGenerator) { highlight: Boolean, fault: Boolean ) { - animatingMarkers[marker.id]?.let { + animatingMarkers[marker]?.let { it.cancel() - animatingMarkers.remove(marker.id) + animatingMarkers.remove(marker) } val anim = ValueAnimator.ofInt(0, 20).apply { @@ -48,15 +48,14 @@ class MarkerAnimator(val gen: ChargerIconGenerator) { fault = fault ) ) - marker.isVisible = true } addListener(onEnd = { - animatingMarkers.remove(marker.id) + animatingMarkers.remove(marker) }, onCancel = { - animatingMarkers.remove(marker.id) + animatingMarkers.remove(marker) }) } - animatingMarkers[marker.id] = anim + animatingMarkers[marker] = anim anim.start() } @@ -66,9 +65,9 @@ class MarkerAnimator(val gen: ChargerIconGenerator) { highlight: Boolean, fault: Boolean ) { - animatingMarkers[marker.id]?.let { + animatingMarkers[marker]?.let { it.cancel() - animatingMarkers.remove(marker.id) + animatingMarkers.remove(marker) } val anim = ValueAnimator.ofInt(20, 0).apply { @@ -87,28 +86,28 @@ class MarkerAnimator(val gen: ChargerIconGenerator) { } addListener(onEnd = { marker.remove() - animatingMarkers.remove(marker.id) + animatingMarkers.remove(marker) }, onCancel = { marker.remove() - animatingMarkers.remove(marker.id) + animatingMarkers.remove(marker) }) } - animatingMarkers[marker.id] = anim + animatingMarkers[marker] = anim anim.start() } fun deleteMarker(marker: Marker) { - animatingMarkers[marker.id]?.let { + animatingMarkers[marker]?.let { it.cancel() - animatingMarkers.remove(marker.id) + animatingMarkers.remove(marker) } marker.remove() } fun animateMarkerBounce(marker: Marker) { - animatingMarkers[marker.id]?.let { + animatingMarkers[marker]?.let { it.cancel() - animatingMarkers.remove(marker.id) + animatingMarkers.remove(marker) } val anim = ValueAnimator.ofFloat(0f, 1f).apply { @@ -119,12 +118,12 @@ class MarkerAnimator(val gen: ChargerIconGenerator) { marker.setAnchor(0.5f, 1.0f + t) } addListener(onEnd = { - animatingMarkers.remove(marker.id) + animatingMarkers.remove(marker) }, onCancel = { - animatingMarkers.remove(marker.id) + animatingMarkers.remove(marker) }) } - animatingMarkers[marker.id] = anim + animatingMarkers[marker] = anim anim.start() } } \ No newline at end of file diff --git a/app/src/main/java/net/vonforst/evmap/viewmodel/MapViewModel.kt b/app/src/main/java/net/vonforst/evmap/viewmodel/MapViewModel.kt index d7ded25d..28e3699a 100644 --- a/app/src/main/java/net/vonforst/evmap/viewmodel/MapViewModel.kt +++ b/app/src/main/java/net/vonforst/evmap/viewmodel/MapViewModel.kt @@ -2,8 +2,8 @@ package net.vonforst.evmap.viewmodel import android.app.Application import androidx.lifecycle.* -import com.google.android.libraries.maps.GoogleMap -import com.google.android.libraries.maps.model.LatLngBounds +import com.car2go.maps.AnyMap +import com.car2go.maps.model.LatLngBounds import com.google.android.libraries.places.api.model.Place import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job @@ -156,9 +156,9 @@ class MapViewModel(application: Application, geApiKey: String) : AndroidViewMode MutableLiveData() } - val mapType: MutableLiveData by lazy { - MutableLiveData().apply { - value = GoogleMap.MAP_TYPE_NORMAL + val mapType: MutableLiveData by lazy { + MutableLiveData().apply { + value = AnyMap.Type.NORMAL } } @@ -177,7 +177,7 @@ class MapViewModel(application: Application, geApiKey: String) : AndroidViewMode } } - fun setMapType(type: Int) { + fun setMapType(type: AnyMap.Type) { mapType.value = type } diff --git a/app/src/main/res/layout/fragment_map.xml b/app/src/main/res/layout/fragment_map.xml index 41243f16..20f03c91 100644 --- a/app/src/main/res/layout/fragment_map.xml +++ b/app/src/main/res/layout/fragment_map.xml @@ -21,10 +21,9 @@ + android:layout_height="match_parent" /> - +