Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3b8a0ee5 authored by Fynn Godau's avatar Fynn Godau
Browse files

Points on single layer

parent 4bdbc20f
Loading
Loading
Loading
Loading
+62 −20
Original line number Diff line number Diff line
@@ -51,9 +51,12 @@ import com.mapbox.mapboxsdk.plugins.annotation.*
import com.mapbox.mapboxsdk.plugins.annotation.Annotation
import com.mapbox.mapboxsdk.style.layers.Property.LINE_CAP_ROUND
import com.google.android.gms.dynamic.unwrap
import com.mapbox.geojson.FeatureCollection
import com.mapbox.mapboxsdk.WellKnownTileServer
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource
import org.microg.gms.maps.MapsConstants.*
import org.microg.gms.maps.mapbox.model.*
import org.microg.gms.maps.mapbox.model.BitmapDescriptorFactoryImpl.withAllBitmaps
import org.microg.gms.maps.mapbox.utils.MapContext
import org.microg.gms.maps.mapbox.utils.MultiArchLoader
import org.microg.gms.maps.mapbox.utils.toGms
@@ -97,6 +100,12 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
    private var markerClickListener: IOnMarkerClickListener? = null
    private var markerDragListener: IOnMarkerDragListener? = null

    /**
     * Tracks whether a call to applyMapType has been posted to run at the next
     * draw of the map.
     */
    private var mapUpdatePosted: Boolean = false

    var lineManager: LineManager? = null
    val pendingLines = mutableSetOf<PolylineImpl>()
    var lineId = 0L
@@ -109,9 +118,14 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
    val pendingCircles = mutableSetOf<CircleImpl>()
    var circleId = 0L

    var markerManager: MarkerManager = MarkerManager()

    /**
     * We store draggable markers as symbols.
     */
    var symbolManager: SymbolManager? = null
    val pendingMarkers = mutableSetOf<MarkerImpl>()
    val markers = mutableMapOf<Long, MarkerImpl>()
    val pendingDraggableMarkers = mutableSetOf<MarkerImpl>()
    val draggableMarkers = mutableMapOf<Long, MarkerImpl>()
    var markerId = 0L

    var groundId = 0L
@@ -121,6 +135,8 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
    val waitingCameraUpdates = mutableListOf<CameraUpdate>()
    var locationEnabled: Boolean = false

    lateinit var geoJsonSource: GeoJsonSource

    init {
        val mapContext = MapContext(context)
        BitmapDescriptorFactoryImpl.initialize(mapContext.resources, context.resources)
@@ -280,13 +296,16 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)

    override fun addMarker(options: MarkerOptions): IMarkerDelegate {
        val marker = MarkerImpl(this, "m${markerId++}", options)
        synchronized(this) {
        if (options.isDraggable) synchronized(this) {
            val symbolManager = symbolManager
            if (symbolManager == null) {
                pendingMarkers.add(marker)
                pendingDraggableMarkers.add(marker)
            } else {
                marker.update(symbolManager)
            }
        } else {
            markerManager.add(marker)
            postMapUpdate()
        }
        return marker
    }
@@ -346,24 +365,37 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
        val lines = lineManager?.annotations?.values()
        val fills = fillManager?.annotations?.values()
        val symbols = symbolManager?.annotations?.values()
        val update: (Style) -> Unit = {
        val onStyleLoadedCallback: (Style) -> Unit = {
            circles?.let { runCatching { circleManager?.update(it) } }
            lines?.let { runCatching { lineManager?.update(it) } }
            fills?.let { runCatching { fillManager?.update(it) } }
            symbols?.let { runCatching { symbolManager?.update(it) } }

            geoJsonSource = GeoJsonSource("geojson",
                FeatureCollection.fromFeatures(markerManager.asFeatures())
            )
            it.addSource(geoJsonSource)
        }

        // TODO: Serve map styles locally
        map?.setStyle(
            Style.Builder().fromUri(
                when (storedMapType) {
            MAP_TYPE_SATELLITE -> map?.setStyle(Style.Builder().fromUri("mapbox://styles/microg/cjxgloted25ap1ct4uex7m6hi"), update)
            MAP_TYPE_TERRAIN -> map?.setStyle(Style.Builder().fromUri("mapbox://styles/mapbox/outdoors-v12"), update)
            MAP_TYPE_HYBRID -> map?.setStyle(Style.Builder().fromUri("mapbox://styles/microg/cjxgloted25ap1ct4uex7m6hi"), update)
                    MAP_TYPE_SATELLITE -> "mapbox://styles/microg/cjxgloted25ap1ct4uex7m6hi"
                    MAP_TYPE_TERRAIN -> "mapbox://styles/mapbox/outdoors-v12"
                    MAP_TYPE_HYBRID -> "mapbox://styles/microg/cjxgloted25ap1ct4uex7m6hi"
                    //MAP_TYPE_NONE, MAP_TYPE_NORMAL,
            else -> map?.setStyle(Style.Builder().fromUrl("mapbox://styles/microg/cjui4020201oo1fmca7yuwbor"), update)
                    else -> "mapbox://styles/microg/cjui4020201oo1fmca7yuwbor"
                }
            )
                .withMarkerLayer()
                .withAllBitmaps(),
            onStyleLoadedCallback
        )

        map?.let { BitmapDescriptorFactoryImpl.registerMap(it) }

        mapUpdatePosted = false
    }

    override fun setWatermarkEnabled(watermark: Boolean) {
@@ -667,7 +699,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
                symbolManager.iconAllowOverlap = true
                symbolManager.addClickListener {
                    try {
                        markers[it.id]?.let { markerClickListener?.onMarkerClick(it) } == true
                        draggableMarkers[it.id]?.let { markerClickListener?.onMarkerClick(it) } == true
                    } catch (e: Exception) {
                        Log.w(TAG, e)
                        false
@@ -676,7 +708,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
                symbolManager.addDragListener(object : OnSymbolDragListener {
                    override fun onAnnotationDragStarted(annotation: Symbol?) {
                        try {
                            markers[annotation?.id]?.let { markerDragListener?.onMarkerDragStart(it) }
                            draggableMarkers[annotation?.id]?.let { markerDragListener?.onMarkerDragStart(it) }
                        } catch (e: Exception) {
                            Log.w(TAG, e)
                        }
@@ -684,7 +716,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)

                    override fun onAnnotationDrag(annotation: Symbol?) {
                        try {
                            markers[annotation?.id]?.let { markerDragListener?.onMarkerDrag(it) }
                            draggableMarkers[annotation?.id]?.let { markerDragListener?.onMarkerDrag(it) }
                        } catch (e: Exception) {
                            Log.w(TAG, e)
                        }
@@ -692,7 +724,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)

                    override fun onAnnotationDragFinished(annotation: Symbol?) {
                        try {
                            markers[annotation?.id]?.let { markerDragListener?.onMarkerDragEnd(it) }
                            draggableMarkers[annotation?.id]?.let { markerDragListener?.onMarkerDragEnd(it) }
                        } catch (e: Exception) {
                            Log.w(TAG, e)
                        }
@@ -704,8 +736,8 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
                pendingFills.clear()
                pendingLines.forEach { it.update(lineManager) }
                pendingLines.clear()
                pendingMarkers.forEach { it.update(symbolManager) }
                pendingMarkers.clear()
                pendingDraggableMarkers.forEach { it.update(symbolManager) }
                pendingDraggableMarkers.clear()

                val mapContext = MapContext(context)
                map.locationComponent.apply {
@@ -734,6 +766,16 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
        }
    }

    fun postMapUpdate() {
        // Only refresh sources once per UI draw
        if (!mapUpdatePosted) {
            mapView?.post {
                applyMapType()
            }
            mapUpdatePosted = true
        }
    }

    override fun useViewLifecycleWhenInFragment(): Boolean {
        Log.d(TAG, "unimplemented Method: useViewLifecycleWhenInFragment")
        return false
@@ -755,8 +797,8 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
        symbolManager?.onDestroy()
        symbolManager = null

        pendingMarkers.clear()
        markers.clear()
        pendingDraggableMarkers.clear()
        draggableMarkers.clear()

        BitmapDescriptorFactoryImpl.unregisterMap(map)

+50 −0
Original line number Diff line number Diff line
package org.microg.gms.maps.mapbox

import com.mapbox.geojson.Feature
import com.mapbox.mapboxsdk.maps.Style
import com.mapbox.mapboxsdk.style.expressions.Expression
import com.mapbox.mapboxsdk.style.layers.Property
import com.mapbox.mapboxsdk.style.layers.PropertyFactory
import com.mapbox.mapboxsdk.style.layers.SymbolLayer
import org.microg.gms.maps.mapbox.model.*

class MarkerManager {

    private val markers: MutableList<MarkerImpl> = ArrayList()

    fun asFeatures(): List<Feature> {
        return markers.map { it.feature }
    }

    fun add(marker: MarkerImpl) {
        markers.add(marker)
    }

    fun remove(marker: MarkerImpl) {
        markers.remove(marker)
    }

}

fun Style.Builder.withMarkerLayer(): Style.Builder {
    return withLayer(
        SymbolLayer("markers", "geojson").withProperties(
            PropertyFactory.iconImage(
                Expression.get(PROPERTY_BITMAP_ID)
            ),
            PropertyFactory.iconAnchor(Property.ICON_ANCHOR_TOP_LEFT),
            PropertyFactory.iconOffset(
                Expression.get(PROPERTY_OFFSET_ARRAY)
            ),
            PropertyFactory.iconRotate(
                Expression.get(PROPERTY_ROTATION)
            ),
            PropertyFactory.iconOpacity(
                Expression.get(PROPERTY_ALPHA)
            ),
            PropertyFactory.symbolZOrder(
                Expression.get(PROPERTY_Z_INDEX)
            )
        ).withFilter(Expression.get(PROPERTY_VISIBLE))
    )
}
 No newline at end of file
+10 −2
Original line number Diff line number Diff line
@@ -24,9 +24,17 @@ import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions
import com.mapbox.mapboxsdk.style.layers.Property.ICON_ANCHOR_TOP_LEFT
import com.mapbox.mapboxsdk.utils.ColorUtils

open class BitmapDescriptorImpl(private val id: String, private val size: FloatArray) {
open class BitmapDescriptorImpl(val id: String, private val size: FloatArray) {
    open fun applyTo(options: SymbolOptions, anchor: FloatArray, dpiFactor: Float): SymbolOptions {
        return options.withIconImage(id).withIconAnchor(ICON_ANCHOR_TOP_LEFT).withIconOffset(arrayOf(-anchor[0] * size[0] / dpiFactor, -anchor[1] * size[1] / dpiFactor))
        return options.withIconImage(id)
            .withIconAnchor(ICON_ANCHOR_TOP_LEFT)
            .withIconOffset(
                asOffset(anchor, dpiFactor)
            )
    }

    fun asOffset(anchor: FloatArray, dpiFactor: Float): Array<Float> {
        return arrayOf(-anchor[0] * size[0] / dpiFactor, -anchor[1] * size[1] / dpiFactor)
    }

    open fun applyTo(symbol: Symbol, anchor: FloatArray, dpiFactor: Float) {
+11 −2
Original line number Diff line number Diff line
@@ -18,14 +18,13 @@ package org.microg.gms.maps.mapbox.model

import android.content.res.Resources
import android.graphics.*
import android.os.Handler
import android.os.Looper
import android.os.Parcel
import android.util.Log
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.maps.model.internal.IBitmapDescriptorFactoryDelegate
import com.mapbox.mapboxsdk.maps.MapboxMap
import com.mapbox.mapboxsdk.maps.Style
import org.microg.gms.maps.mapbox.R
import org.microg.gms.maps.mapbox.runOnMainLooper

@@ -151,6 +150,16 @@ object BitmapDescriptorFactoryImpl : IBitmapDescriptorFactoryDelegate.Stub() {
        return ObjectWrapper.wrap(ColorBitmapDescriptorImpl(id, bitmapSize(id), hue))
    }

    /**
     * Adds all bitmaps registered via bitmap descriptor factory to the style.
     */
    fun Style.Builder.withAllBitmaps(): Style.Builder {
        for (bitmap in bitmaps) {
            withImage(bitmap.key, bitmap.value)
        }
        return this
    }

    override fun fromBitmap(bitmap: Bitmap): IObjectWrapper? {
        val id = "bitmap-${bitmap.hashCode()}"
        registerBitmap(id) { bitmap }
+65 −7
Original line number Diff line number Diff line
@@ -23,13 +23,24 @@ import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.maps.model.LatLng
import com.google.android.gms.maps.model.MarkerOptions
import com.google.android.gms.maps.model.internal.IMarkerDelegate
import com.mapbox.mapboxsdk.plugins.annotation.AnnotationManager
import com.mapbox.mapboxsdk.plugins.annotation.Symbol
import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions
import com.google.android.gms.dynamic.unwrap
import com.google.gson.JsonArray
import com.google.gson.JsonObject
import com.mapbox.geojson.Feature
import com.mapbox.geojson.Point
import com.mapbox.mapboxsdk.plugins.annotation.AnnotationManager
import org.microg.gms.maps.mapbox.GoogleMapImpl
import org.microg.gms.maps.mapbox.utils.toMapbox

const val PROPERTY_BITMAP_ID = "bitmap"
const val PROPERTY_VISIBLE = "visible"
const val PROPERTY_OFFSET_ARRAY = "offset"
const val PROPERTY_ROTATION = "rotation"
const val PROPERTY_ALPHA = "alpha"
const val PROPERTY_Z_INDEX = "z"

class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options: MarkerOptions) : IMarkerDelegate.Stub(), Markup<Symbol, SymbolOptions> {
    private var position: LatLng = options.position
    private var visible: Boolean = options.isVisible
@@ -60,21 +71,60 @@ class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options
            return symbolOptions
        }

    val feature: Feature
        get() = Feature.fromGeometry(
            Point.fromLngLat(position.longitude, position.latitude),
            // Properties are evaluated using expressions in style, see MarkerManager
            JsonObject().apply {
                icon?.let {
                    addProperty(PROPERTY_BITMAP_ID, it.id)
                    add(PROPERTY_OFFSET_ARRAY,
                        JsonArray().apply {
                            for (float in it.asOffset(anchor, map.dpiFactor)) {
                                add(float)
                            }
                        }
                    )}
                // Draggable icons are added as symbols, make them invisible in GeoJSON
                addProperty(PROPERTY_VISIBLE, visible && !draggable)
                addProperty(PROPERTY_ROTATION, rotation)
                addProperty(PROPERTY_ALPHA, alpha)
                addProperty(PROPERTY_Z_INDEX, zIndex)
            }, id
        )

    override fun remove() {
        removed = true
        map.markerManager.remove(this)
        map.symbolManager?.let { update(it) }
        map.postMapUpdate()
    }

    /**
     * Updates marker's representation inside SymbolManager. Only draggable markers
     * are added to SymbolManager!
     */
    override fun update(manager: AnnotationManager<*, Symbol, SymbolOptions, *, *, *>) {
        synchronized(this) {
            val id = annotation?.id
            if (removed && id != null) {
                map.markers.remove(id)
            if ((removed || !draggable) && annotation?.id != null) {
                map.draggableMarkers.remove(id)
            }
            super.update(manager)

            if ((removed || ! draggable) && annotation != null) {
                manager.delete(annotation)
                annotation = null
            } else if (annotation != null) {
                manager.update(annotation)
            } else if (!removed && draggable) {
                Log.d(TAG, "added marker as symbol")
                annotation = manager.create(annotationOptions)

                // Store marker to find it if dragged
                val annotation = annotation
            if (annotation != null && id == null) {
                map.markers[annotation.id] = this
                if (annotation != null) {
                    map.draggableMarkers[annotation.id] = this
                }
            }
        }
    }
@@ -85,6 +135,7 @@ class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options
        this.position = position ?: return
        annotation?.latLng = position.toMapbox()
        map.symbolManager?.let { update(it) }
        map.postMapUpdate()
    }

    override fun getPosition(): LatLng = position
@@ -105,6 +156,7 @@ class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options
        this.draggable = draggable
        annotation?.isDraggable = draggable
        map.symbolManager?.let { update(it) }
        map.postMapUpdate()
    }

    override fun isDraggable(): Boolean = draggable
@@ -128,6 +180,7 @@ class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options
        this.visible = visible
        annotation?.iconOpacity = if (visible) alpha else 0f
        map.symbolManager?.let { update(it) }
        map.postMapUpdate()
    }

    override fun isVisible(): Boolean = visible
@@ -156,12 +209,14 @@ class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options
            annotation?.let { icon.applyTo(it, anchor, map.dpiFactor) }
        }
        map.symbolManager?.let { update(it) }
        map.postMapUpdate()
    }

    override fun setAnchor(x: Float, y: Float) {
        anchor = floatArrayOf(x, y)
        annotation?.let { icon?.applyTo(it, anchor, map.dpiFactor) }
        map.symbolManager?.let { update(it) }
        map.postMapUpdate()
    }

    override fun setFlat(flat: Boolean) {
@@ -177,6 +232,7 @@ class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options
        this.rotation = rotation
        annotation?.iconRotate = rotation
        map.symbolManager?.let { update(it) }
        map.postMapUpdate()
    }

    override fun getRotation(): Float = rotation
@@ -189,6 +245,7 @@ class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options
        this.alpha = alpha
        annotation?.iconOpacity = if (visible) alpha else 0f
        map.symbolManager?.let { update(it) }
        map.postMapUpdate()
    }

    override fun getAlpha(): Float = alpha
@@ -197,6 +254,7 @@ class MarkerImpl(private val map: GoogleMapImpl, private val id: String, options
        this.zIndex = zIndex
        annotation?.symbolSortKey = zIndex
        map.symbolManager?.let { update(it) }
        map.postMapUpdate()
    }

    override fun getZIndex(): Float = zIndex
Loading