55
66package org.microg.gms.maps.hms
77
8+ import android.Manifest
89import android.content.Context
10+ import android.content.pm.PackageManager
911import android.graphics.Bitmap
1012import android.location.Location
1113import android.os.*
@@ -21,16 +23,20 @@ import android.widget.RelativeLayout
2123import androidx.annotation.IdRes
2224import androidx.annotation.Keep
2325import androidx.collection.LongSparseArray
26+ import androidx.core.app.ActivityCompat
2427import com.google.android.gms.dynamic.IObjectWrapper
2528import com.google.android.gms.dynamic.ObjectWrapper
2629import com.google.android.gms.dynamic.unwrap
30+ import com.google.android.gms.location.LocationListener
31+ import com.google.android.gms.location.LocationServices
2732import com.google.android.gms.maps.GoogleMap.MAP_TYPE_TERRAIN
2833import com.google.android.gms.maps.GoogleMapOptions
2934import com.google.android.gms.maps.internal.*
3035import com.google.android.gms.maps.model.*
3136import com.google.android.gms.maps.model.internal.*
3237import com.huawei.hms.maps.CameraUpdate
3338import com.huawei.hms.maps.HuaweiMap
39+ import com.huawei.hms.maps.LocationSource
3440import com.huawei.hms.maps.MapView
3541import com.huawei.hms.maps.MapsInitializer
3642import com.huawei.hms.maps.OnMapReadyCallback
@@ -42,8 +48,11 @@ import com.huawei.hms.maps.internal.IOnPoiClickListener
4248import com.huawei.hms.maps.model.Marker
4349import org.microg.gms.maps.hms.model.*
4450import org.microg.gms.maps.hms.utils.*
51+ import com.google.android.gms.location.LocationRequest
52+ import com.google.android.gms.location.Priority
4553import java.util.concurrent.CopyOnWriteArrayList
4654import java.util.concurrent.atomic.AtomicBoolean
55+ import com.google.android.gms.maps.model.LatLng
4756
4857
4958private fun <T : Any > LongSparseArray<T>.values () = (0 until size()).mapNotNull { valueAt(it) }
@@ -102,6 +111,36 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
102111 private var projectionImpl: ProjectionImpl ? = null
103112 private var inDeveloperAnimation = false
104113
114+ private var locationEnabled: Boolean = false
115+ private var isAddLocationCallback: Boolean = false
116+ private var lastLocation: Location ? = null
117+ private var myLocationChangeListener: IOnMyLocationChangeListener ? = null
118+
119+ private val locationService by lazy { LocationServices .getFusedLocationProviderClient(context) }
120+ private val locationCallback = LocationListener { location ->
121+ lastLocation = location
122+ try {
123+ myLocationChangeListener?.onMyLocationChanged(ObjectWrapper .wrap(location))
124+ } catch (e: RemoteException ) {
125+ Log .w(TAG , " Failed to notify my-location listener" , e)
126+ }
127+ val gcj02Location = Location (location).apply {
128+ val hmsLatLng = LatLng (location.latitude, location.longitude).toHms()
129+ latitude = hmsLatLng.latitude
130+ longitude = hmsLatLng.longitude
131+ }
132+ mLocationChangedListener?.onLocationChanged(gcj02Location)
133+ }
134+ private var mLocationChangedListener: LocationSource .OnLocationChangedListener ? = null
135+ private var hwLocationSource: LocationSource = object : LocationSource {
136+ override fun activate (listener : LocationSource .OnLocationChangedListener ) {
137+ mLocationChangedListener = listener
138+ }
139+ override fun deactivate () {
140+ mLocationChangedListener = null
141+ }
142+ }
143+
105144 init {
106145 BitmapDescriptorFactoryImpl .initialize(context.resources)
107146 runOnMainLooper {
@@ -340,7 +379,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
340379
341380 override fun addMarker (options : MarkerOptions ): IMarkerDelegate {
342381 val marker = MarkerImpl (this , " m${markerId++ } " , options)
343- if (map != null ) {
382+ if (map != null && initialized ) {
344383 marker.update()
345384 } else {
346385 markers[marker.id] = marker
@@ -425,16 +464,53 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
425464
426465 override fun setMyLocationEnabled (myLocation : Boolean ) = afterInitialize {
427466 Log .d(TAG , " setMyLocationEnabled $myLocation " )
428- it.isMyLocationEnabled = myLocation
467+ synchronized(mapLock) {
468+ locationEnabled = myLocation
469+ try {
470+ setLocationSource(null )
471+ } catch (e: Exception ) {
472+ Log .w(TAG , e)
473+ locationEnabled = false
474+ } finally {
475+ it.isMyLocationEnabled = locationEnabled
476+ }
477+ }
429478 }
430479
431- override fun getMyLocation (): Location ? {
432- Log .d(TAG , " deprecated Method: getMyLocation" )
433- return null
434- }
480+ override fun getMyLocation (): Location ? = lastLocation
435481
436482 override fun setLocationSource (locationSource : ILocationSourceDelegate ? ) = afterInitialize {
437- Log .d(TAG , " unimplemented Method: setLocationSource" )
483+ synchronized(mapLock) {
484+ it.setLocationSource(hwLocationSource)
485+ updateLocationEngineListener(locationEnabled)
486+ }
487+ }
488+
489+ private fun updateLocationEngineListener (myLocation : Boolean ) {
490+ if (ActivityCompat .checkSelfPermission(
491+ context, Manifest .permission.ACCESS_FINE_LOCATION
492+ ) == PackageManager .PERMISSION_GRANTED || ActivityCompat .checkSelfPermission(
493+ context, Manifest .permission.ACCESS_COARSE_LOCATION
494+ ) == PackageManager .PERMISSION_GRANTED
495+ ) {
496+ if (myLocation) {
497+ if (! isAddLocationCallback) {
498+ isAddLocationCallback = true
499+ locationService.requestLocationUpdates(
500+ LocationRequest .Builder (DEFAULT_LOCATION_INTERVAL_MILLIS )
501+ .setPriority(Priority .PRIORITY_HIGH_ACCURACY )
502+ .setMinUpdateIntervalMillis(DEFAULT_LOCATION_INTERVAL_MILLIS )
503+ .setMaxUpdateDelayMillis(DEFAULT_LOCATION_INTERVAL_MILLIS )
504+ .build(), locationCallback, Looper .getMainLooper()
505+ )
506+ }
507+ } else {
508+ if (isAddLocationCallback) {
509+ isAddLocationCallback = false
510+ locationService.removeLocationUpdates(locationCallback)
511+ }
512+ }
513+ }
438514 }
439515
440516 override fun setContentDescription (desc : String? ) = afterInitialize {
@@ -507,7 +583,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
507583
508584 override fun setOnMarkerClickListener (listener : IOnMarkerClickListener ? ) = afterInitialize { hmap ->
509585 hmap.setOnMarkerClickListener {
510- Log .d(" GmsGoogleMap " , " setOnMarkerClickListener marker id -> ${it.id} " )
586+ Log .d(TAG , " setOnMarkerClickListener marker id -> ${it.id} " )
511587 listener?.onMarkerClick(markers[it.id]) ? : false
512588 }
513589 }
@@ -557,6 +633,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
557633
558634 override fun setOnMyLocationChangeListener (listener : IOnMyLocationChangeListener ? ) = afterInitialize {
559635 Log .d(TAG , " deprecated Method: setOnMyLocationChangeListener" )
636+ myLocationChangeListener = listener
560637 }
561638
562639 override fun setOnMyLocationButtonClickListener (listener : IOnMyLocationButtonClickListener ? ) = afterInitialize {
@@ -630,11 +707,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
630707 synchronized(mapLock) {
631708 if (loaded) {
632709 Log .d(TAG , " Invoking callback instantly, as map is loaded" )
633- try {
634- scheduleExecute { callback.onMapLoaded() }
635- } catch (e: Exception ) {
636- Log .w(TAG , e)
637- }
710+ callback.scheduleExecute()
638711 } else {
639712 Log .d(TAG , " Delay callback invocation, as map is not yet loaded" )
640713 loadedCallback = callback
@@ -847,8 +920,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
847920 }
848921 internalOnInitializedCallbackList.clear()
849922 fakeWatermark { Log .d(TAG_LOGO , " fakeWatermark success" ) }
850- scheduleExecute { loadedCallback?.onMapLoaded() }
851-
923+ loadedCallback?.scheduleExecute()
852924 mapView?.visibility = View .VISIBLE
853925 }
854926
@@ -862,6 +934,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
862934 override fun onPause () = mapView?.onPause() ? : Unit
863935 override fun onDestroy () {
864936 Log .d(TAG , " onDestroy" )
937+ locationService.removeLocationUpdates(locationCallback)
865938 initializedCallbackList.clear()
866939 internalOnInitializedCallbackList.clear()
867940 circles.map { it.value.remove() }
@@ -877,13 +950,15 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
877950 // TODO can crash?
878951 mapView?.onDestroy()
879952 mapView = null
953+ mLocationChangedListener = null
880954
881955 // Don't make it null; this object is not deleted immediately, and it may want to access map.* stuff
882956 // map = null
883957
884958 created = false
885959 initialized = false
886960 loaded = false
961+ isAddLocationCallback = false
887962 }
888963
889964 override fun onStart () {
@@ -929,6 +1004,16 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
9291004 }
9301005 }
9311006
1007+ private fun IOnMapLoadedCallback.scheduleExecute () {
1008+ Handler (Looper .getMainLooper()).postDelayed({
1009+ try {
1010+ this .onMapLoaded()
1011+ } catch (e: Exception ) {
1012+ Log .w(TAG , e)
1013+ }
1014+ }, ON_MAP_LOADED_CALLBACK_DELAY )
1015+ }
1016+
9321017 private var isInvokingInitializedCallbacks = AtomicBoolean (false )
9331018 private fun tryRunUserInitializedCallbacks (tag : String = "") {
9341019
@@ -958,6 +1043,13 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
9581043 scheduleExecute { runCallbacks() }
9591044 }
9601045 if (! wasCallbackActive) isInvokingInitializedCallbacks.set(false )
1046+ } else if (mapView?.isShown == false ) {
1047+ // Match the Mapbox backend: let applications configure the map while the
1048+ // backend is still initializing. Camera updates and other operations that
1049+ // require HuaweiMap are queued by their existing initialization guards.
1050+ runOnMainLooper(forceQueue = true ) {
1051+ runCallbacks()
1052+ }
9611053 } else {
9621054 Log .d(
9631055 " $TAG :$tag " ,
@@ -987,5 +1079,7 @@ class GoogleMapImpl(private val context: Context, var options: GoogleMapOptions)
9871079
9881080 private const val TAG_LOGO = " fakeWatermark"
9891081 private const val ON_MAP_CALLBACK_DELAY = 300L
1082+ private const val ON_MAP_LOADED_CALLBACK_DELAY = 500L
1083+ private const val DEFAULT_LOCATION_INTERVAL_MILLIS = 1000L
9901084 }
9911085}
0 commit comments