content: package com.airbnb.android.airmapview;
  
  import android.content.Context;
  import android.util.AttributeSet;
  import android.view.LayoutInflater;
  import android.view.MotionEvent;
  import android.widget.FrameLayout;
  
  import androidx.annotation.NonNull;
  import androidx.fragment.app.Fragment;
  import androidx.fragment.app.FragmentManager;
  import com.airbnb.android.airmapview.listeners.InfoWindowCreator;
  import com.airbnb.android.airmapview.listeners.OnCameraChangeListener;
  import com.airbnb.android.airmapview.listeners.OnCameraMoveListener;
  import com.airbnb.android.airmapview.listeners.OnInfoWindowClickListener;
  import com.airbnb.android.airmapview.listeners.OnLatLngScreenLocationCallback;
  import com.airbnb.android.airmapview.listeners.OnMapBoundsCallback;
  import com.airbnb.android.airmapview.listeners.OnMapClickListener;
  import com.airbnb.android.airmapview.listeners.OnMapInitializedListener;
  import com.airbnb.android.airmapview.listeners.OnMapLoadedListener;
  import com.airbnb.android.airmapview.listeners.OnMapMarkerClickListener;
  import com.airbnb.android.airmapview.listeners.OnMapMarkerDragListener;
  import com.google.android.gms.maps.GoogleMap;
  import com.google.android.gms.maps.model.LatLng;
  import com.google.android.gms.maps.model.LatLngBounds;
  import com.google.android.gms.maps.model.Marker;
  
  import org.json.JSONException;
  
  public class AirMapView extends FrameLayout
      implements OnCameraChangeListener, OnMapClickListener, OnMapMarkerDragListener,
      OnMapMarkerClickListener, OnMapLoadedListener, OnInfoWindowClickListener {
  
    private static final int INVALID_ZOOM = -1;
  
    protected AirMapInterface mapInterface;
    private OnCameraMoveListener onCameraMoveListener;
    private OnCameraChangeListener onCameraChangeListener;
    private boolean mOnCameraMoveTriggered;
    private OnMapInitializedListener onMapInitializedListener;
    private OnMapMarkerClickListener onMapMarkerClickListener;
    private OnMapMarkerDragListener onMapMarkerDragListener;
    private OnMapClickListener onMapClickListener;
    private OnInfoWindowClickListener onInfoWindowClickListener;
  
    public AirMapView(Context context) {
      super(context);
      inflateView();
    }
  
    public AirMapView(Context context, AttributeSet attrs) {
      super(context, attrs);
      inflateView();
    }
  
    public AirMapView(Context context, AttributeSet attrs, int defStyle) {
      super(context, attrs, defStyle);
      inflateView();
    }
  
    private void inflateView() {
      LayoutInflater.from(getContext()).inflate(R.layout.map_view, this);
    }
  
    public void initialize(FragmentManager fragmentManager, AirMapInterface mapInterface) {
      if (mapInterface == null || fragmentManager == null) {
        throw new IllegalArgumentException("Either mapInterface or fragmentManager is null");
      }
  
      this.mapInterface = mapInterface;
      this.mapInterface.setOnMapLoadedListener(this);
  
      fragmentManager.beginTransaction()
          .replace(getId(), (Fragment) this.mapInterface)
          .commit();
  
      fragmentManager.executePendingTransactions();
    }
  
    /**
     * Used for initialization of the underlying map provider.
     *
     * @param fragmentManager required for initialization
     */
    public void initialize(FragmentManager fragmentManager) {
      AirMapInterface mapInterface = (AirMapInterface)
          fragmentManager.findFragmentById(R.id.map_frame);
  
      if (mapInterface != null) {
        initialize(fragmentManager, mapInterface);
      } else {
        initialize(fragmentManager, new DefaultAirMapViewBuilder(getContext()).builder().build());
      }
    }
  
    public void setOnMapInitializedListener(OnMapInitializedListener mapInitializedListener) {
      onMapInitializedListener = mapInitializedListener;
    }
  
    @Override public boolean dispatchTouchEvent(@NonNull MotionEvent ev) {
      if (ev.getAction() == MotionEvent.ACTION_MOVE) {
        if (onCameraMoveListener != null && !mOnCameraMoveTriggered) {
          onCameraMoveListener.onCameraMove();
          mOnCameraMoveTriggered = true;
        }
      } else if (ev.getAction() == MotionEvent.ACTION_UP) {
        mOnCameraMoveTriggered = false;
      }
  
      return super.dispatchTouchEvent(ev);
    }
  
    public void setOnCameraChangeListener(OnCameraChangeListener onCameraChangeListener) {
      this.onCameraChangeListener = onCameraChangeListener;
    }
  
    /**
     * Sets the map {@link com.airbnb.android.airmapview.listeners.OnCameraMoveListener}
     *
     * @param onCameraMoveListener The OnCameraMoveListener to be set
     */
    public void setOnCameraMoveListener(OnCameraMoveListener onCameraMoveListener) {
      this.onCameraMoveListener = onCameraMoveListener;
    }
  
    public final AirMapInterface getMapInterface() {
      return mapInterface;
    }
  
    public void onDestroyView() {
      if (isInitialized()) {
        mapInterface.setMyLocationEnabled(false);
      }
    }
  
    public int getZoom() {
      if (isInitialized()) {
        return mapInterface.getZoom();
      }
  
      return INVALID_ZOOM;
    }
  
    public LatLng getCenter() {
      if (isInitialized()) {
        return mapInterface.getCenter();
      }
      return null;
    }
  
    public boolean setCenter(LatLng latLng) {
      if (isInitialized()) {
        mapInterface.setCenter(latLng);
        return true;
      }
      return false;
    }
  
    public boolean animateCenter(LatLng latLng) {
      if (isInitialized()) {
        mapInterface.animateCenter(latLng);
        return true;
      }
      return false;
    }
  
    public boolean setZoom(int zoom) {
      if (isInitialized()) {
        mapInterface.setZoom(zoom);
        return true;
      }
      return false;
    }
  
    public boolean setCenterZoom(LatLng latLng, int zoom) {
      if (isInitialized()) {
        mapInterface.setCenterZoom(latLng, zoom);
        return true;
      }
      return false;
    }
  
    public boolean animateCenterZoom(LatLng latLng, int zoom) {
      if (isInitialized()) {
        mapInterface.animateCenterZoom(latLng, zoom);
        return true;
      }
      return false;
    }
  
    public boolean setBounds(LatLngBounds latLngBounds, int boundsPadding) {
      if (isInitialized()) {
        mapInterface.setCenter(latLngBounds, boundsPadding);
        return true;
      }
      return false;
    }
  
    public void getScreenBounds(OnMapBoundsCallback callback) {
      if (isInitialized()) {
        mapInterface.getMapScreenBounds(callback);
      }
    }
  
    public void getMapMarkerScreenLocation(LatLng latLng, OnLatLngScreenLocationCallback callback) {
      if (isInitialized()) {
        mapInterface.getScreenLocation(latLng, callback);
      }
    }
  
    public void drawCircle(LatLng latLng, int radius) {
      if (isInitialized()) {
        mapInterface.drawCircle(latLng, radius);
      }
    }
  
    public void drawCircle(LatLng latLng, int radius, int strokeColor) {
      if (isInitialized()) {
        mapInterface.drawCircle(latLng, radius, strokeColor);
      }
    }
  
    public void drawCircle(LatLng latLng, int radius, int strokeColor, int strokeWidth) {
      if (isInitialized()) {
        mapInterface.drawCircle(latLng, radius, strokeColor, strokeWidth);
      }
    }
  
    public void drawCircle(LatLng latLng, int radius, int strokeColor, int strokeWidth,
        int fillColor) {
      if (isInitialized()) {
        mapInterface.drawCircle(latLng, radius, strokeColor, strokeWidth, fillColor);
      }
    }
  
    public void setPadding(int left, int top, int right, int bottom) {
      if (isInitialized()) {
        mapInterface.setPadding(left, top, right, bottom);
      }
    }
  
    public void setOnMarkerClickListener(OnMapMarkerClickListener listener) {
      onMapMarkerClickListener = listener;
    }
  
    public void setOnMarkerDragListener(OnMapMarkerDragListener listener) {
      onMapMarkerDragListener = listener;
    }
  
    public void setOnMapClickListener(OnMapClickListener listener) {
      onMapClickListener = listener;
    }
  
    public void setInfoWindowAdapter(GoogleMap.InfoWindowAdapter adapter, InfoWindowCreator creator) {
      if (isInitialized()) {
        mapInterface.setInfoWindowCreator(adapter, creator);
      }
    }
  
    public void setOnInfoWindowClickListener(OnInfoWindowClickListener listener) {
      onInfoWindowClickListener = listener;
    }
  
    public void clearMarkers() {
      if (isInitialized()) {
        mapInterface.clearMarkers();
      }
    }
  
    public <T> boolean addPolyline(AirMapPolyline<T> polyline) {
      if (isInitialized()) {
        mapInterface.addPolyline(polyline);
        return true;
      }
      return false;
    }
  
    public void setMapType(MapType mapType) {
      mapInterface.setMapType(mapType);
    }
  
    public <T> boolean removePolyline(AirMapPolyline<T> polyline) {
      if (isInitialized()) {
        mapInterface.removePolyline(polyline);
        return true;
      }
      return false;
    }
  
    public <T> boolean addPolygon(AirMapPolygon<T> polygon) {
      if (isInitialized()) {
        mapInterface.addPolygon(polygon);
        return true;
      }
      return false;
    }
  
    public <T> boolean removePolygon(AirMapPolygon<T> polygon) {
      if (isInitialized()) {
        mapInterface.removePolygon(polygon);
        return true;
      }
      return false;
    }
  
    public void setGeoJsonLayer(AirMapGeoJsonLayer layer) throws JSONException {
      if (!isInitialized()) {
        return;
      }
      mapInterface.setGeoJsonLayer(layer);
    }
  
    public void clearGeoJsonLayer() {
      if (!isInitialized()) {
        return;
      }
      mapInterface.clearGeoJsonLayer();
    }
  
    public boolean isInitialized() {
      return mapInterface != null && mapInterface.isInitialized();
    }
  
    public boolean addMarker(AirMapMarker<?> marker) {
      if (isInitialized()) {
        mapInterface.addMarker(marker);
        return true;
      }
      return false;
    }
  
    public boolean removeMarker(AirMapMarker<?> marker) {
      if (isInitialized()) {
        mapInterface.removeMarker(marker);
        return true;
      }
      return false;
    }
  
    public boolean moveMarker(AirMapMarker<?> marker, LatLng to) {
      if (isInitialized()) {
        mapInterface.moveMarker(marker, to);
        return true;
      }
      return false;
    }
  
    public void setMyLocationEnabled(boolean trackUserLocation) {
      mapInterface.setMyLocationEnabled(trackUserLocation);
    }
  
    public void setMyLocationButtonEnabled(boolean enabled) {
      mapInterface.setMyLocationButtonEnabled(enabled);
    }
  
    @Override public void onCameraChanged(LatLng latLng, int zoom) {
      if (onCameraChangeListener != null) {
        onCameraChangeListener.onCameraChanged(latLng, zoom);
      }
    }
  
    @Override public void onMapClick(LatLng latLng) {
      if (onMapClickListener != null) {
        onMapClickListener.onMapClick(latLng);
      }
    }
  
    @Override public boolean onMapMarkerClick(AirMapMarker<?> airMarker) {
      if (onMapMarkerClickListener != null) {
        return onMapMarkerClickListener.onMapMarkerClick(airMarker);
      } else {
        return false;
      }
    }
  
    @Override public void onMapMarkerDragStart(Marker marker) {
      if (onMapMarkerDragListener != null) {
        onMapMarkerDragListener.onMapMarkerDragStart(marker);
      }
    }
  
    @Override public void onMapMarkerDrag(Marker marker) {
      if (onMapMarkerDragListener != null) {
        onMapMarkerDragListener.onMapMarkerDrag(marker);
      }
    }
  
    @Override public void onMapMarkerDragEnd(Marker marker) {
      if (onMapMarkerDragListener != null) {
        onMapMarkerDragListener.onMapMarkerDragEnd(marker);
      }
    }
  
    @Override public void onMapMarkerDragStart(long id, LatLng latLng) {
      if (onMapMarkerDragListener != null) {
        onMapMarkerDragListener.onMapMarkerDragStart(id, latLng);
      }
    }
  
    @Override public void onMapMarkerDrag(long id, LatLng latLng) {
      if (onMapMarkerDragListener != null) {
        onMapMarkerDragListener.onMapMarkerDrag(id, latLng);
      }
    }
  
    @Override public void onMapMarkerDragEnd(long id, LatLng latLng) {
      if (onMapMarkerDragListener != null) {
        onMapMarkerDragListener.onMapMarkerDragEnd(id, latLng);
      }
    }
  
    @Override public void onMapLoaded() {
      if (isInitialized()) {
        mapInterface.setOnCameraChangeListener(this);
        mapInterface.setOnMapClickListener(this);
        mapInterface.setOnMarkerClickListener(this);
        mapInterface.setOnMarkerDragListener(this);
        mapInterface.setOnInfoWindowClickListener(this);
  
        if (onMapInitializedListener != null) {
          // only send map Initialized callback if map initialized successfully and is laid out
          // initialization can fail if the map leaves the screen before it loads
          MapLaidOutCheckKt.doWhenMapIsLaidOut(this, () -> onMapInitializedListener.onMapInitialized());
        }
      }
    }
  
    @Override public void onInfoWindowClick(AirMapMarker<?> airMarker) {
      if (onInfoWindowClickListener != null) {
        onInfoWindowClickListener.onInfoWindowClick(airMarker);
      }
    }
  }
  