@@ -19,8 +19,11 @@ package com.google.maps.flutter.navigation
19
19
import android.annotation.SuppressLint
20
20
import android.content.res.Resources
21
21
import android.graphics.Point
22
+ import android.graphics.SurfaceTexture
22
23
import android.location.Location
24
+ import android.view.TextureView
23
25
import android.view.View
26
+ import android.view.ViewGroup
24
27
import com.google.android.gms.maps.CameraUpdate
25
28
import com.google.android.gms.maps.CameraUpdateFactory
26
29
import com.google.android.gms.maps.GoogleMap
@@ -34,19 +37,13 @@ import com.google.android.gms.maps.model.MapStyleOptions
34
37
import com.google.android.gms.maps.model.Marker
35
38
import com.google.android.gms.maps.model.Polygon
36
39
import com.google.android.gms.maps.model.Polyline
37
- import com.google.android.libraries.navigation.NavigationView
38
40
39
41
abstract class GoogleMapsBaseMapView (
40
42
protected val viewId : Int? ,
41
43
mapOptions : MapOptions ,
42
44
protected val viewEventApi : ViewEventApi ? ,
43
45
private val imageRegistry : ImageRegistry ,
44
46
) {
45
- companion object {
46
- const val INVALIDATION_FRAME_SKIP_AMOUNT = 4 // Amount of skip frames before invalidation
47
- }
48
-
49
- private val _frameDelayHandler = FrameDelayHandler (INVALIDATION_FRAME_SKIP_AMOUNT )
50
47
private var _map : GoogleMap ? = null
51
48
private val _markers = mutableListOf<MarkerController >()
52
49
private val _polygons = mutableListOf<PolygonController >()
@@ -107,6 +104,9 @@ abstract class GoogleMapsBaseMapView(
107
104
}
108
105
109
106
protected fun mapReady () {
107
+ // Install custom invalidator for the map view.
108
+ installInvalidator()
109
+
110
110
// Call and clear view ready callback if available.
111
111
_mapReadyCallback ?.let { callback ->
112
112
callback(Result .success(Unit ))
@@ -214,27 +214,55 @@ abstract class GoogleMapsBaseMapView(
214
214
)
215
215
}
216
216
217
- /* *
218
- * Workaround for map view not showing added or edited map objects immediately after add/edit.
219
- * Schedules [NavigationView.invalidate] call after a certain amount of frames are drawn. In
220
- * marker updates short delay is not enough, [doubleInvalidate] is set to true.
221
- *
222
- * @param doubleInvalidate if true, schedules another invalidate event after the first one.
223
- */
224
- protected fun invalidateViewAfterMapLoad (doubleInvalidate : Boolean = false) {
225
- if (_loadedCallbackPending ) {
217
+ // Installs a custom invalidator for the map view.
218
+ private fun installInvalidator () {
219
+ if (getView() == null ) {
220
+ // This should only happen in tests.
221
+ return
222
+ }
223
+ val textureView = findTextureView(getView()!! )
224
+ if (textureView == null ) {
226
225
return
227
226
}
228
- _loadedCallbackPending = true
229
- getMap().setOnMapLoadedCallback {
230
- _loadedCallbackPending = false
231
- _frameDelayHandler .scheduleActionWithFrameDelay {
232
- getView().invalidate()
233
- if (doubleInvalidate) {
234
- _frameDelayHandler .scheduleActionWithFrameDelay { getView().invalidate() }
227
+ val internalListener = textureView.surfaceTextureListener
228
+
229
+ // Override the Maps internal SurfaceTextureListener with one that invalidates mapview on
230
+ // texture update.
231
+ textureView.surfaceTextureListener =
232
+ object : TextureView .SurfaceTextureListener {
233
+ override fun onSurfaceTextureAvailable (surface : SurfaceTexture , width : Int , height : Int ) {
234
+ internalListener?.onSurfaceTextureAvailable(surface, width, height)
235
+ }
236
+
237
+ override fun onSurfaceTextureDestroyed (surface : SurfaceTexture ): Boolean {
238
+ return internalListener?.onSurfaceTextureDestroyed(surface) ? : true
239
+ }
240
+
241
+ override fun onSurfaceTextureSizeChanged (surface : SurfaceTexture , width : Int , height : Int ) {
242
+ internalListener?.onSurfaceTextureSizeChanged(surface, width, height)
243
+ }
244
+
245
+ override fun onSurfaceTextureUpdated (surface : SurfaceTexture ) {
246
+ internalListener?.onSurfaceTextureUpdated(surface)
247
+ // Invalidate the view to ensure it is redrawn.
248
+ getView()?.invalidate()
249
+ }
250
+ }
251
+ }
252
+
253
+ // Returns the first TextureView found in the view hierarchy.
254
+ private fun findTextureView (view : View ): TextureView ? {
255
+ if (view is TextureView ) {
256
+ return view
257
+ }
258
+ if (view is ViewGroup ) {
259
+ for (i in 0 until view.childCount) {
260
+ findTextureView(view.getChildAt(i))?.let {
261
+ return it
235
262
}
236
263
}
237
264
}
265
+ return null
238
266
}
239
267
240
268
@Throws(FlutterError ::class )
@@ -304,22 +332,18 @@ abstract class GoogleMapsBaseMapView(
304
332
305
333
@SuppressLint(" MissingPermission" )
306
334
fun setMyLocationEnabled (enabled : Boolean ) {
307
- invalidateViewAfterMapLoad()
308
335
getMap().isMyLocationEnabled = enabled
309
336
}
310
337
311
338
fun setMyLocationButtonEnabled (enabled : Boolean ) {
312
- invalidateViewAfterMapLoad()
313
339
getMap().uiSettings.isMyLocationButtonEnabled = enabled
314
340
}
315
341
316
342
fun setZoomGesturesEnabled (enabled : Boolean ) {
317
- invalidateViewAfterMapLoad()
318
343
getMap().uiSettings.isZoomGesturesEnabled = enabled
319
344
}
320
345
321
346
fun setZoomControlsEnabled (enabled : Boolean ) {
322
- invalidateViewAfterMapLoad()
323
347
getMap().uiSettings.isZoomControlsEnabled = enabled
324
348
}
325
349
@@ -364,7 +388,6 @@ abstract class GoogleMapsBaseMapView(
364
388
}
365
389
366
390
fun setCompassEnabled (enabled : Boolean ) {
367
- invalidateViewAfterMapLoad()
368
391
getMap().uiSettings.isCompassEnabled = enabled
369
392
}
370
393
@@ -576,20 +599,17 @@ abstract class GoogleMapsBaseMapView(
576
599
}
577
600
578
601
fun setMapType (mapType : Int ) {
579
- invalidateViewAfterMapLoad()
580
602
getMap().mapType = mapType
581
603
}
582
604
583
605
fun setMapStyle (styleJson : String ) {
584
- invalidateViewAfterMapLoad()
585
606
if (! getMap().setMapStyle(MapStyleOptions (styleJson))) {
586
607
throw FlutterError (" mapStyleError" , " Failed to set map style" )
587
608
}
588
609
}
589
610
590
611
@SuppressLint(" MissingPermission" )
591
612
fun followMyLocation (perspective : Int , zoomLevel : Double? ) {
592
- invalidateViewAfterMapLoad()
593
613
getMap().followMyLocation(perspective)
594
614
if (zoomLevel != null ) {
595
615
val options: FollowMyLocationOptions =
@@ -657,9 +677,6 @@ abstract class GoogleMapsBaseMapView(
657
677
result.add(it)
658
678
}
659
679
}
660
- // Double invalidate map view. Marker icon updates seem to take extra
661
- // time and some times icon did not update properly after single invalidate.
662
- invalidateViewAfterMapLoad(true )
663
680
return result
664
681
}
665
682
@@ -677,15 +694,11 @@ abstract class GoogleMapsBaseMapView(
677
694
}
678
695
}
679
696
error?.let { throw error as Throwable }
680
- // Double invalidate map view. Marker icon updates seem to take extra
681
- // time and some times icon did not update properly after single invalidate.
682
- invalidateViewAfterMapLoad(true )
683
697
return result
684
698
}
685
699
686
700
@Throws(FlutterError ::class )
687
701
fun removeMarkers (markers : List <MarkerDto >) {
688
- invalidateViewAfterMapLoad()
689
702
var error: Throwable ? = null
690
703
markers.forEach {
691
704
findMarkerController(it.markerId)?.let { controller ->
@@ -700,7 +713,6 @@ abstract class GoogleMapsBaseMapView(
700
713
}
701
714
702
715
fun clearMarkers () {
703
- invalidateViewAfterMapLoad()
704
716
_markers .forEach { controller -> controller.remove() }
705
717
_markers .clear()
706
718
}
@@ -722,7 +734,6 @@ abstract class GoogleMapsBaseMapView(
722
734
723
735
fun addPolygons (polygons : List <PolygonDto >): List <PolygonDto > {
724
736
val density = Resources .getSystem().displayMetrics.density
725
- invalidateViewAfterMapLoad()
726
737
val result = mutableListOf<PolygonDto >()
727
738
polygons.forEach {
728
739
val builder = PolygonBuilder ()
@@ -739,7 +750,6 @@ abstract class GoogleMapsBaseMapView(
739
750
}
740
751
741
752
fun updatePolygons (polygons : List <PolygonDto >): List <PolygonDto > {
742
- invalidateViewAfterMapLoad()
743
753
var error: Throwable ? = null
744
754
val result = mutableListOf<PolygonDto >()
745
755
val density = Resources .getSystem().displayMetrics.density
@@ -759,7 +769,6 @@ abstract class GoogleMapsBaseMapView(
759
769
}
760
770
761
771
fun removePolygons (polygons : List <PolygonDto >) {
762
- invalidateViewAfterMapLoad()
763
772
var error: Throwable ? = null
764
773
polygons.forEach {
765
774
findPolygonController(it.polygonId)?.let { controller ->
@@ -775,7 +784,6 @@ abstract class GoogleMapsBaseMapView(
775
784
}
776
785
777
786
fun clearPolygons () {
778
- invalidateViewAfterMapLoad()
779
787
_polygons .forEach { controller -> controller.remove() }
780
788
_polygons .clear()
781
789
}
@@ -789,7 +797,6 @@ abstract class GoogleMapsBaseMapView(
789
797
790
798
fun addPolylines (polylines : List <PolylineDto >): List <PolylineDto > {
791
799
val density = Resources .getSystem().displayMetrics.density
792
- invalidateViewAfterMapLoad()
793
800
val result = mutableListOf<PolylineDto >()
794
801
polylines.forEach {
795
802
val builder = PolylineBuilder ()
@@ -808,7 +815,6 @@ abstract class GoogleMapsBaseMapView(
808
815
fun updatePolylines (polylines : List <PolylineDto >): List <PolylineDto > {
809
816
var error: Throwable ? = null
810
817
val density = Resources .getSystem().displayMetrics.density
811
- invalidateViewAfterMapLoad()
812
818
val result = mutableListOf<PolylineDto >()
813
819
polylines.forEach {
814
820
findPolylineController(it.polylineId)?.let { controller ->
@@ -825,7 +831,6 @@ abstract class GoogleMapsBaseMapView(
825
831
}
826
832
827
833
fun removePolylines (polylines : List <PolylineDto >) {
828
- invalidateViewAfterMapLoad()
829
834
var error: Throwable ? = null
830
835
polylines.forEach {
831
836
findPolylineController(it.polylineId)?.let { controller ->
@@ -841,7 +846,6 @@ abstract class GoogleMapsBaseMapView(
841
846
}
842
847
843
848
fun clearPolylines () {
844
- invalidateViewAfterMapLoad()
845
849
_polylines .forEach { controller -> controller.remove() }
846
850
_polylines .clear()
847
851
}
@@ -855,7 +859,6 @@ abstract class GoogleMapsBaseMapView(
855
859
856
860
fun addCircles (circles : List <CircleDto >): List <CircleDto > {
857
861
val density = Resources .getSystem().displayMetrics.density
858
- invalidateViewAfterMapLoad()
859
862
val result = mutableListOf<CircleDto >()
860
863
circles.forEach {
861
864
val builder = CircleBuilder ()
@@ -873,7 +876,6 @@ abstract class GoogleMapsBaseMapView(
873
876
874
877
fun updateCircles (circles : List <CircleDto >): List <CircleDto > {
875
878
val density = Resources .getSystem().displayMetrics.density
876
- invalidateViewAfterMapLoad()
877
879
val result = mutableListOf<CircleDto >()
878
880
var error: Throwable ? = null
879
881
circles.forEach {
@@ -890,7 +892,6 @@ abstract class GoogleMapsBaseMapView(
890
892
}
891
893
892
894
fun removeCircles (circles : List <CircleDto >) {
893
- invalidateViewAfterMapLoad()
894
895
var error: Throwable ? = null
895
896
circles.forEach {
896
897
findCircleController(it.circleId)?.let { controller ->
@@ -905,7 +906,6 @@ abstract class GoogleMapsBaseMapView(
905
906
}
906
907
907
908
fun clearCircles () {
908
- invalidateViewAfterMapLoad()
909
909
_circles .forEach { controller -> controller.remove() }
910
910
_circles .clear()
911
911
}
0 commit comments