Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.huawei.hms.maps.HuaweiMap
import com.huawei.hms.maps.MapView
import com.huawei.hms.maps.MapsInitializer
import com.huawei.hms.maps.OnMapReadyCallback
import com.huawei.hms.maps.TextureMapView
import com.huawei.hms.maps.internal.IOnIndoorStateChangeListener
import com.huawei.hms.maps.internal.IOnInfoWindowCloseListener
import com.huawei.hms.maps.internal.IOnInfoWindowLongClickListener
Expand Down Expand Up @@ -93,6 +94,8 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
private var markerId = 0L
val markers = mutableMapOf<String, MarkerImpl>()

private var projectionImpl: ProjectionImpl? = null

init {
val mapContext = MapContext(context)
BitmapDescriptorFactoryImpl.initialize(context.resources)
Expand Down Expand Up @@ -405,7 +408,14 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
}

override fun getProjection(): IProjectionDelegate {
return map?.projection?.let { ProjectionImpl(it) } ?: DummyProjection()
return projectionImpl ?: map?.projection?.let {
val experiment = try {
map?.cameraPosition?.tilt == 0.0f && map?.cameraPosition?.bearing == 0.0f
} catch (e: Exception) {
Log.w(TAG, e);false
}
ProjectionImpl(it, experiment)
}?.also { projectionImpl = it } ?: DummyProjection()
}

override fun setOnCameraChangeListener(listener: IOnCameraChangeListener?) = afterInitialize {
Expand Down Expand Up @@ -609,6 +619,13 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mapView?.let { it.parent?.onDescendantInvalidated(it, it) }
}
map?.let {
val cameraPosition = it.cameraPosition
val tilt = cameraPosition.tilt
val bearing = cameraPosition.bearing
val useFast = tilt < 1f && (bearing % 360f < 1f || bearing % 360f > 359f)
projectionImpl?.updateProjectionState(it.projection, useFast)
}
cameraMoveListener?.onCameraMove()
cameraChangeListener?.onCameraChange(map?.cameraPosition?.toGms())
} catch (e: Exception) {
Expand Down Expand Up @@ -654,7 +671,11 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
Log.d(TAG_LOGO, "create: ${context.packageName},\n$options")
val mapContext = MapContext(context)
MapsInitializer.initialize(mapContext)
val mapView = MapView(mapContext, options.toHms()).apply { visibility = View.INVISIBLE }
val mapView = runCatching {
TextureMapView(mapContext, options.toHms())
}.onFailure {
Log.w(TAG, "onCreate: init TextureMapView error ", it)
}.getOrDefault(MapView(mapContext, options.toHms())).apply { visibility = View.INVISIBLE }
this.mapView = mapView
view.addView(mapView)
mapView.onCreate(savedInstanceState?.toHms())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stu

private var map: GoogleMapImpl? = null
private var options: GoogleMapOptions? = null
private var readyCallbackList: MutableList<IOnMapReadyCallback> = mutableListOf()

override fun onInflate(activity: IObjectWrapper, options: GoogleMapOptions, savedInstanceState: Bundle?) {
Log.d(TAG, "onInflate: $options")
Expand Down Expand Up @@ -49,6 +50,8 @@ class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stu
}
Log.d(TAG, "onCreateView $this : $options")
map!!.onCreate(savedInstanceState)
readyCallbackList.forEach { map!!.getMapAsync(it) }
readyCallbackList.clear()
val view = map!!.view
val parent = view.parent as ViewGroup?
parent?.removeView(view)
Expand All @@ -64,7 +67,14 @@ class MapFragmentImpl(private val activity: Activity) : IMapFragmentDelegate.Stu
override fun onPause() = map?.onPause() ?: Unit
override fun onLowMemory() = map?.onLowMemory() ?: Unit
override fun isReady(): Boolean = this.map != null
override fun getMapAsync(callback: IOnMapReadyCallback) = map?.getMapAsync(callback) ?: Unit
override fun getMapAsync(callback: IOnMapReadyCallback) {
Log.d(TAG, "getMapAsync: map: $map")
if (map == null) {
readyCallbackList.add(callback)
return
}
map?.getMapAsync(callback)
}

override fun onDestroyView() {
Log.d(TAG, "onDestroyView: $this : $options")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,39 +17,104 @@ import com.google.android.gms.maps.model.VisibleRegion
import com.huawei.hms.maps.Projection
import org.microg.gms.maps.hms.utils.toGms
import org.microg.gms.maps.hms.utils.toHms
import kotlin.math.roundToInt

private const val TAG = "GmsMapProjection"

class ProjectionImpl(private val projection: Projection) : IProjectionDelegate.Stub() {
private const val TAG = "GmsProjectionImpl"

class ProjectionImpl(private var projection: Projection, private var withoutTiltOrBearing: Boolean) : IProjectionDelegate.Stub() {
private var lastVisibleRegion: VisibleRegion? = null
private var visibleRegion = projection.visibleRegion

private var farLeft: Point? = visibleRegion.farLeft?.let { projection.toScreenLocation(it) }
private var farRight: Point? = visibleRegion.farRight?.let { projection.toScreenLocation(it) }
private var nearLeft: Point? = visibleRegion.nearLeft?.let { projection.toScreenLocation(it) }

private var farLeftLat = visibleRegion.farLeft?.latitude ?: 0.0
private var nearLeftLat = visibleRegion.nearLeft?.latitude ?: 0.0
private var farLeftLng = visibleRegion.farLeft?.longitude ?: 0.0
private var farRightLng = visibleRegion.farRight?.longitude ?: 0.0
private var farLeftX = farLeft?.x ?: 0
private var farLeftY = farLeft?.y ?: 0
private var farRightX = farRight?.x ?: (farLeftX + 1)
private var nearLeftY = nearLeft?.y ?: (farLeftY + 1)

fun updateProjectionState(newProjection: Projection, useFastMode: Boolean) {
Log.d(TAG, "updateProjectionState: useFastMode: $useFastMode")
projection = newProjection
visibleRegion = newProjection.visibleRegion
withoutTiltOrBearing = useFastMode

farLeft = visibleRegion.farLeft?.let { projection.toScreenLocation(it) }
farRight = visibleRegion.farRight?.let { projection.toScreenLocation(it) }
nearLeft = visibleRegion.nearLeft?.let { projection.toScreenLocation(it) }

farLeftLat = visibleRegion.farLeft?.latitude ?: 0.0
nearLeftLat = visibleRegion.nearLeft?.latitude ?: 0.0
farLeftLng = visibleRegion.farLeft?.longitude ?: 0.0
farRightLng = visibleRegion.farRight?.longitude ?: 0.0
farLeftX = farLeft?.x ?: 0
farLeftY = farLeft?.y ?: 0
farRightX = farRight?.x ?: (farLeftX + 1)
nearLeftY = nearLeft?.y ?: (farLeftY + 1)
}

private fun isInvalid(): Boolean {
return farLeftX == farRightX || farLeftY == nearLeftY || (farRightX == 1 && farLeftX == 0) || (nearLeftY == 1 && farLeftY == 0)
}

override fun fromScreenLocation(obj: IObjectWrapper?): LatLng? {
Log.d(TAG, "fromScreenLocation")
return try {
obj.unwrap<Point>()?.let {
projection.fromScreenLocation(it).toGms()
override fun fromScreenLocation(obj: IObjectWrapper?): LatLng? = try {
obj.unwrap<Point>()?.let {
if (withoutTiltOrBearing && farLeft != null && farRight != null && nearLeft != null) {
if (isInvalid()) {
Log.w(TAG, "Invalid projection layout, fallback to SDK")
projection.fromScreenLocation(Point(it)).toGms()
} else {
val xPercent = (it.x.toFloat() - farLeftX) / (farRightX - farLeftX)
val yPercent = (it.y.toFloat() - farLeftY) / (nearLeftY - farLeftY)

val lon = farLeftLng + xPercent * (farRightLng - farLeftLng)
val lat = farLeftLat + yPercent * (nearLeftLat - farLeftLat)

Log.d(TAG, "fromScreenLocation: $it -> lat: $lat lon: $lon")

LatLng(lat, lon)
}
} else {
projection.fromScreenLocation(Point(it)).toGms()
}
} catch (e: Exception) {
Log.d(TAG, "fromScreenLocation() used from outside UI thread on map with tilt or bearing, expect bugs")
LatLng(0.0, 0.0)
}
} catch (e: Exception) {
Log.d(TAG, "fromScreenLocation() error", e)
LatLng(0.0, 0.0)
}

override fun toScreenLocation(latLng: LatLng?): IObjectWrapper {
Log.d(TAG, "toScreenLocation: $latLng")
return try {
ObjectWrapper.wrap(latLng?.toHms()?.let {
projection.toScreenLocation(it).let { Point(it.x, it.y) }
})
} catch (e: Exception) {
Log.d(TAG, "toScreenLocation() used from outside UI thread on map with tilt or bearing, expect bugs")
ObjectWrapper.wrap(Point(0, 0))
}
override fun toScreenLocation(latLng: LatLng?): IObjectWrapper = try {
ObjectWrapper.wrap(latLng?.toHms()?.let {
if (withoutTiltOrBearing && farLeft != null && farRight != null && nearLeft != null) {
if (isInvalid()) {
Log.w(TAG, "Invalid projection layout, fallback to SDK")
projection.toScreenLocation(it).let { p -> Point(p.x, p.y) }
} else {
val xPercent = (it.longitude - farLeftLng) / (farRightLng - farLeftLng)
val yPercent = (it.latitude - farLeftLat) / (nearLeftLat - farLeftLat)

val x = farLeftX + xPercent * (farRightX - farLeftX)
val y = farLeftY + yPercent * (nearLeftY - farLeftY)

Log.d(TAG, "toScreenLocation: $latLng -> x: $x y: $y")

Point(x.roundToInt(), y.roundToInt())
}
} else {
projection.toScreenLocation(it).let { p -> Point(p.x, p.y) }
}
})
} catch (e: Exception) {
Log.d(TAG, "toScreenLocation() error", e)
ObjectWrapper.wrap(Point(0, 0))
}

override fun getVisibleRegion(): VisibleRegion? {
val visibleRegion = projection.visibleRegion
if (visibleRegion.farLeft.latitude.isNaN() || visibleRegion.farLeft.longitude.isNaN()) {
return lastVisibleRegion
}
Expand Down