Skip to content
Open
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
1 change: 1 addition & 0 deletions play-services-maps/core/hms/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ apply plugin: 'kotlin-android'
dependencies {
implementation project(':play-services-base-core')
implementation project(':play-services-maps')
implementation project(':play-services-location')

implementation 'com.huawei.hms:maps:6.9.0.300'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

package org.microg.gms.maps.hms

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.location.Location
import android.os.*
Expand All @@ -21,16 +23,20 @@ import android.widget.RelativeLayout
import androidx.annotation.IdRes
import androidx.annotation.Keep
import androidx.collection.LongSparseArray
import androidx.core.app.ActivityCompat
import com.google.android.gms.dynamic.IObjectWrapper
import com.google.android.gms.dynamic.ObjectWrapper
import com.google.android.gms.dynamic.unwrap
import com.google.android.gms.location.LocationListener
import com.google.android.gms.location.LocationServices
import com.google.android.gms.maps.GoogleMap.MAP_TYPE_TERRAIN
import com.google.android.gms.maps.GoogleMapOptions
import com.google.android.gms.maps.internal.*
import com.google.android.gms.maps.model.*
import com.google.android.gms.maps.model.internal.*
import com.huawei.hms.maps.CameraUpdate
import com.huawei.hms.maps.HuaweiMap
import com.huawei.hms.maps.LocationSource
import com.huawei.hms.maps.MapView
import com.huawei.hms.maps.MapsInitializer
import com.huawei.hms.maps.OnMapReadyCallback
Expand All @@ -42,8 +48,12 @@ import com.huawei.hms.maps.internal.IOnPoiClickListener
import com.huawei.hms.maps.model.Marker
import org.microg.gms.maps.hms.model.*
import org.microg.gms.maps.hms.utils.*
import com.google.android.gms.location.LocationRequest
import com.google.android.gms.location.Priority
import java.util.concurrent.CopyOnWriteArrayList
import java.util.concurrent.atomic.AtomicBoolean
import com.google.android.gms.maps.model.LatLng
import kotlin.math.abs


private fun <T : Any> LongSparseArray<T>.values() = (0 until size()).mapNotNull { valueAt(it) }
Expand Down Expand Up @@ -102,6 +112,36 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
private var projectionImpl: ProjectionImpl? = null
private var inDeveloperAnimation = false

private var locationEnabled: Boolean = false
private var isAddLocationCallback: Boolean = false
private var lastLocation: Location? = null
private var myLocationChangeListener: IOnMyLocationChangeListener? = null

private val locationService by lazy { LocationServices.getFusedLocationProviderClient(context) }
private val locationCallback = LocationListener { location ->
lastLocation = location
try {
myLocationChangeListener?.onMyLocationChanged(ObjectWrapper.wrap(location))
} catch (e: RemoteException) {
Log.w(TAG, "Failed to notify my-location listener", e)
}
val gcj02Location = Location(location).apply {
val hmsLatLng = LatLng(location.latitude, location.longitude).toHms()
latitude = hmsLatLng.latitude
longitude = hmsLatLng.longitude
}
mLocationChangedListener?.onLocationChanged(gcj02Location)
}
private var mLocationChangedListener: LocationSource.OnLocationChangedListener? = null
private var hwLocationSource: LocationSource = object : LocationSource {
override fun activate(listener: LocationSource.OnLocationChangedListener) {
mLocationChangedListener = listener
}
override fun deactivate() {
mLocationChangedListener = null
}
}

init {
BitmapDescriptorFactoryImpl.initialize(context.resources)
runOnMainLooper {
Expand Down Expand Up @@ -223,7 +263,16 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
}

override fun getCameraPosition(): CameraPosition {
return map?.cameraPosition?.toGms() ?: CameraPosition(LatLng(0.0, 0.0), 0f, 0f, 0f)
val raw = map?.cameraPosition?.toGms() ?: CameraPosition(LatLng(0.0, 0.0), 0f, 0f, 0f)
val shouldNormalizeOrigin = raw.zoom <= DEFAULT_HMS_MIN_ZOOM &&
abs(raw.target.latitude) < INITIAL_CAMERA_ORIGIN_EPSILON &&
abs(raw.target.longitude) < INITIAL_CAMERA_ORIGIN_EPSILON
val result = if (shouldNormalizeOrigin) {
CameraPosition(LatLng(0.0, 0.0), raw.zoom, raw.tilt, raw.bearing)
} else {
raw
}
return result
}
override fun getMaxZoomLevel(): Float = toHmsZoom(map?.maxZoomLevel ?: 18.toFloat())
override fun getMinZoomLevel(): Float = toHmsZoom(map?.minZoomLevel ?: 3.toFloat())
Expand Down Expand Up @@ -340,7 +389,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)

override fun addMarker(options: MarkerOptions): IMarkerDelegate {
val marker = MarkerImpl(this, "m${markerId++}", options)
if (map != null) {
if (map != null && initialized) {
marker.update()
} else {
markers[marker.id] = marker
Expand Down Expand Up @@ -425,16 +474,53 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)

override fun setMyLocationEnabled(myLocation: Boolean) = afterInitialize {
Log.d(TAG, "setMyLocationEnabled $myLocation")
it.isMyLocationEnabled = myLocation
synchronized(mapLock) {
locationEnabled = myLocation
try {
setLocationSource(null)
} catch (e: Exception) {
Log.w(TAG, e)
locationEnabled = false
} finally {
it.isMyLocationEnabled = locationEnabled
}
}
}

override fun getMyLocation(): Location? {
Log.d(TAG, "deprecated Method: getMyLocation")
return null
}
override fun getMyLocation(): Location? = lastLocation

override fun setLocationSource(locationSource: ILocationSourceDelegate?) = afterInitialize {
Log.d(TAG, "unimplemented Method: setLocationSource")
synchronized(mapLock) {
it.setLocationSource(hwLocationSource)
updateLocationEngineListener(locationEnabled)
}
}

private fun updateLocationEngineListener(myLocation: Boolean) {
if (ActivityCompat.checkSelfPermission(
context, Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED || ActivityCompat.checkSelfPermission(
context, Manifest.permission.ACCESS_COARSE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
if (myLocation) {
if (!isAddLocationCallback) {
isAddLocationCallback = true
locationService.requestLocationUpdates(
LocationRequest.Builder(DEFAULT_LOCATION_INTERVAL_MILLIS)
.setPriority(Priority.PRIORITY_HIGH_ACCURACY)
.setMinUpdateIntervalMillis(DEFAULT_LOCATION_INTERVAL_MILLIS)
.setMaxUpdateDelayMillis(DEFAULT_LOCATION_INTERVAL_MILLIS)
.build(), locationCallback, Looper.getMainLooper()
)
}
} else {
if (isAddLocationCallback) {
isAddLocationCallback = false
locationService.removeLocationUpdates(locationCallback)
}
}
}
}

override fun setContentDescription(desc: String?) = afterInitialize {
Expand Down Expand Up @@ -507,7 +593,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)

override fun setOnMarkerClickListener(listener: IOnMarkerClickListener?) = afterInitialize { hmap ->
hmap.setOnMarkerClickListener {
Log.d("GmsGoogleMap", "setOnMarkerClickListener marker id -> ${it.id}")
Log.d(TAG, "setOnMarkerClickListener marker id -> ${it.id}")
listener?.onMarkerClick(markers[it.id]) ?: false
}
}
Expand Down Expand Up @@ -557,6 +643,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)

override fun setOnMyLocationChangeListener(listener: IOnMyLocationChangeListener?) = afterInitialize {
Log.d(TAG, "deprecated Method: setOnMyLocationChangeListener")
myLocationChangeListener = listener
}

override fun setOnMyLocationButtonClickListener(listener: IOnMyLocationButtonClickListener?) = afterInitialize {
Expand Down Expand Up @@ -630,11 +717,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
synchronized(mapLock) {
if (loaded) {
Log.d(TAG, "Invoking callback instantly, as map is loaded")
try {
scheduleExecute { callback.onMapLoaded() }
} catch (e: Exception) {
Log.w(TAG, e)
}
callback.scheduleExecute()
} else {
Log.d(TAG, "Delay callback invocation, as map is not yet loaded")
loadedCallback = callback
Expand Down Expand Up @@ -847,8 +930,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
}
internalOnInitializedCallbackList.clear()
fakeWatermark { Log.d(TAG_LOGO, "fakeWatermark success") }
scheduleExecute { loadedCallback?.onMapLoaded() }

loadedCallback?.scheduleExecute()
mapView?.visibility = View.VISIBLE
}

Expand All @@ -862,6 +944,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
override fun onPause() = mapView?.onPause() ?: Unit
override fun onDestroy() {
Log.d(TAG, "onDestroy")
locationService.removeLocationUpdates(locationCallback)
initializedCallbackList.clear()
internalOnInitializedCallbackList.clear()
circles.map { it.value.remove() }
Expand All @@ -877,13 +960,15 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
// TODO can crash?
mapView?.onDestroy()
mapView = null
mLocationChangedListener = null

// Don't make it null; this object is not deleted immediately, and it may want to access map.* stuff
//map = null

created = false
initialized = false
loaded = false
isAddLocationCallback = false
}

override fun onStart() {
Expand Down Expand Up @@ -929,6 +1014,16 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
}
}

private fun IOnMapLoadedCallback.scheduleExecute() {
Handler(Looper.getMainLooper()).postDelayed({
try {
this.onMapLoaded()
} catch (e: Exception) {
Log.w(TAG, e)
}
}, ON_MAP_LOADED_CALLBACK_DELAY)
}

private var isInvokingInitializedCallbacks = AtomicBoolean(false)
private fun tryRunUserInitializedCallbacks(tag: String = "") {

Expand All @@ -955,7 +1050,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
Log.d("$TAG:$tag", "Invoking callback now, as map is initialized")
val wasCallbackActive = isInvokingInitializedCallbacks.getAndSet(true)
runOnMainLooper(forceQueue = wasCallbackActive) {
scheduleExecute { runCallbacks() }
runCallbacks()
}
if (!wasCallbackActive) isInvokingInitializedCallbacks.set(false)
} else {
Expand All @@ -975,17 +1070,14 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
}


private fun scheduleExecute(block:() -> Unit) {
Handler(Looper.getMainLooper()).postDelayed({
try { block.invoke() } catch (_: Exception) {}
}, ON_MAP_CALLBACK_DELAY)
}

companion object {
private const val TAG = "GmsGoogleMap"
private const val DEFAULT_HMS_MIN_ZOOM = 3f
private const val INITIAL_CAMERA_ORIGIN_EPSILON = 1e-5
private const val SNAPSHOT_OLD_VERSION_CODE = 4000000

private const val TAG_LOGO = "fakeWatermark"
private const val ON_MAP_CALLBACK_DELAY = 300L
private const val ON_MAP_LOADED_CALLBACK_DELAY = 500L
private const val DEFAULT_LOCATION_INTERVAL_MILLIS = 1000L
}
}