1515
1616import android .annotation .SuppressLint ;
1717import android .app .Activity ;
18+ import android .util .Log ;
1819import androidx .core .util .Supplier ;
1920import com .facebook .react .bridge .UiThreadUtil ;
2021import com .google .android .gms .maps .CameraUpdateFactory ;
2122import com .google .android .gms .maps .GoogleMap ;
23+ import com .google .android .gms .maps .GoogleMap .CameraPerspective ;
2224import com .google .android .gms .maps .model .BitmapDescriptor ;
2325import com .google .android .gms .maps .model .BitmapDescriptorFactory ;
2426import com .google .android .gms .maps .model .CameraPosition ;
2527import com .google .android .gms .maps .model .Circle ;
2628import com .google .android .gms .maps .model .CircleOptions ;
29+ import com .google .android .gms .maps .model .FollowMyLocationOptions ;
2730import com .google .android .gms .maps .model .GroundOverlay ;
2831import com .google .android .gms .maps .model .GroundOverlayOptions ;
2932import com .google .android .gms .maps .model .LatLng ;
4245import java .util .Map ;
4346
4447public class MapViewController implements INavigationViewControllerProperties {
48+ private static final String TAG = "MapViewController" ;
4549 private GoogleMap mGoogleMap ;
4650 private Supplier <Activity > activitySupplier ;
4751 private INavigationViewCallback mNavigationViewCallback ;
@@ -883,23 +887,35 @@ public void setMinZoomLevel(float minZoomLevel) {
883887 return ;
884888 }
885889
886- // Get the effective max zoom for comparison
887- float maxZoom =
890+ minZoomLevelPreference = minZoomLevel ;
891+
892+ // Reset both preferences first so the new min/max pair is always applied
893+ // atomically. Without this, Fabric can deliver minZoomLevel and maxZoomLevel
894+ // prop updates in any order, causing a transient state where min > max.
895+ mGoogleMap .resetMinMaxZoomPreference ();
896+
897+ float effectiveMin = (minZoomLevel < 0.0f ) ? mGoogleMap .getMinZoomLevel () : minZoomLevel ;
898+ float effectiveMax =
888899 (maxZoomLevelPreference != null && maxZoomLevelPreference >= 0.0f )
889900 ? maxZoomLevelPreference
890901 : mGoogleMap .getMaxZoomLevel ();
891902
892- // Validate that min is not greater than max (unless using -1 sentinel)
893- if (minZoomLevel >= 0.0f && minZoomLevel > maxZoom ) {
894- throw new IllegalArgumentException (
895- "Minimum zoom level cannot be greater than maximum zoom level" );
903+ if (effectiveMin > effectiveMax ) {
904+ Log .w (
905+ TAG ,
906+ "minZoomLevel ("
907+ + effectiveMin
908+ + ") is greater than maxZoomLevel ("
909+ + effectiveMax
910+ + "). Ignoring zoom level constraints." );
911+ return ;
896912 }
897913
898- minZoomLevelPreference = minZoomLevel ;
899-
900- // Use map's current minZoomLevel if -1 is provided
901- float effectiveMin = (minZoomLevel < 0.0f ) ? mGoogleMap .getMinZoomLevel () : minZoomLevel ;
902914 mGoogleMap .setMinZoomPreference (effectiveMin );
915+
916+ if (maxZoomLevelPreference != null ) {
917+ mGoogleMap .setMaxZoomPreference (effectiveMax );
918+ }
903919 }
904920
905921 @ Override
@@ -908,23 +924,35 @@ public void setMaxZoomLevel(float maxZoomLevel) {
908924 return ;
909925 }
910926
911- // Get the effective min zoom for comparison
912- float minZoom =
927+ maxZoomLevelPreference = maxZoomLevel ;
928+
929+ // Reset both preferences first so the new min/max pair is always applied
930+ // atomically. Without this, Fabric can deliver minZoomLevel and maxZoomLevel
931+ // prop updates in any order, causing a transient state where min > max.
932+ mGoogleMap .resetMinMaxZoomPreference ();
933+
934+ float effectiveMax = (maxZoomLevel < 0.0f ) ? mGoogleMap .getMaxZoomLevel () : maxZoomLevel ;
935+ float effectiveMin =
913936 (minZoomLevelPreference != null && minZoomLevelPreference >= 0.0f )
914937 ? minZoomLevelPreference
915938 : mGoogleMap .getMinZoomLevel ();
916939
917- // Validate that max is not less than min (unless using -1 sentinel)
918- if (maxZoomLevel >= 0.0f && maxZoomLevel < minZoom ) {
919- throw new IllegalArgumentException (
920- "Maximum zoom level cannot be less than minimum zoom level" );
940+ if (effectiveMin > effectiveMax ) {
941+ Log .w (
942+ TAG ,
943+ "minZoomLevel ("
944+ + effectiveMin
945+ + ") is greater than maxZoomLevel ("
946+ + effectiveMax
947+ + "). Ignoring zoom level constraints." );
948+ return ;
921949 }
922950
923- maxZoomLevelPreference = maxZoomLevel ;
924-
925- // Use map's current maxZoomLevel if -1 is provided
926- float effectiveMax = (maxZoomLevel < 0.0f ) ? mGoogleMap .getMaxZoomLevel () : maxZoomLevel ;
927951 mGoogleMap .setMaxZoomPreference (effectiveMax );
952+
953+ if (minZoomLevelPreference != null ) {
954+ mGoogleMap .setMinZoomPreference (effectiveMin );
955+ }
928956 }
929957
930958 public void setZoomGesturesEnabled (boolean enabled ) {
@@ -1005,16 +1033,27 @@ public void resetMinMaxZoomLevel() {
10051033 return ;
10061034 }
10071035
1036+ minZoomLevelPreference = null ;
1037+ maxZoomLevelPreference = null ;
10081038 mGoogleMap .resetMinMaxZoomPreference ();
10091039 }
10101040
10111041 @ SuppressLint ("MissingPermission" )
1012- public void setFollowingPerspective (int jsValue ) {
1042+ public void setFollowingPerspective (int jsValue , Float zoomLevel ) {
10131043 if (mGoogleMap == null ) {
10141044 return ;
10151045 }
10161046
1017- mGoogleMap .followMyLocation (EnumTranslationUtil .getCameraPerspectiveFromJsValue (jsValue ));
1047+ @ CameraPerspective
1048+ int perspective = EnumTranslationUtil .getCameraPerspectiveFromJsValue (jsValue );
1049+
1050+ if (zoomLevel != null ) {
1051+ FollowMyLocationOptions options =
1052+ FollowMyLocationOptions .builder ().setZoomLevel (zoomLevel ).build ();
1053+ mGoogleMap .followMyLocation (perspective , options );
1054+ } else {
1055+ mGoogleMap .followMyLocation (perspective );
1056+ }
10181057 }
10191058
10201059 public void setPadding (int top , int left , int bottom , int right ) {
0 commit comments