package cgeo.geocaching.maps.google.v1;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import cgeo.geocaching.location.Geopoint;
import cgeo.geocaching.location.Viewport;
import cgeo.geocaching.maps.CachesOverlay;
import cgeo.geocaching.maps.PositionAndScaleOverlay;
import cgeo.geocaching.maps.interfaces.GeneralOverlay;
import cgeo.geocaching.maps.interfaces.GeoPointImpl;
import cgeo.geocaching.maps.interfaces.MapControllerImpl;
import cgeo.geocaching.maps.interfaces.MapProjectionImpl;
import cgeo.geocaching.maps.interfaces.MapViewImpl;
import cgeo.geocaching.maps.interfaces.OnMapDragListener;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import org.apache.commons.lang3.reflect.MethodUtils;
import android.support.annotation.NonNull;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.Gravity;
import android.view.MotionEvent;
import android.widget.FrameLayout;
import android.widget.ZoomButtonsController;
public class GoogleMapView extends MapView implements MapViewImpl {
private GestureDetector gestureDetector;
private OnMapDragListener onDragListener;
private final GoogleMapController mapController = new GoogleMapController(getController());
public GoogleMapView(final Context context, final AttributeSet attrs) {
super(context, attrs);
initialize(context);
}
public GoogleMapView(final Context context, final AttributeSet attrs, final int defStyle) {
super(context, attrs, defStyle);
initialize(context);
}
public GoogleMapView(final Context context, final String apiKey) {
super(context, apiKey);
initialize(context);
}
private void initialize(final Context context) {
if (isInEditMode()) {
return;
}
gestureDetector = new GestureDetector(context, new GestureListener());
}
@Override
public void draw(final Canvas canvas) {
try {
if (getMapZoomLevel() > 22) { // to avoid too close zoom level (mostly on Samsung Galaxy S series)
getController().setZoom(22);
}
super.draw(canvas);
} catch (final Exception e) {
Log.e("GoogleMapView.draw", e);
}
}
@Override
public void displayZoomControls(final boolean takeFocus) {
try {
// Push zoom controls to the right
final FrameLayout.LayoutParams zoomParams = new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
zoomParams.gravity = Gravity.RIGHT;
// The call to retrieve the zoom buttons controller is undocumented and works so far on all devices
// supported by Google Play, but fails at least on one Jolla.
final ZoomButtonsController controller = (ZoomButtonsController) MethodUtils.invokeMethod(this, "getZoomButtonsController");
controller.getZoomControls().setLayoutParams(zoomParams);
super.displayZoomControls(takeFocus);
} catch (final NoSuchMethodException | NoSuchMethodError ignored) {
Log.w("GoogleMapView.displayZoomControls: unable to explicitly place the zoom buttons");
} catch (final Exception e) {
Log.e("GoogleMapView.displayZoomControls", e);
}
}
@Override
public MapControllerImpl getMapController() {
return mapController;
}
@Override
@NonNull
public GeoPointImpl getMapViewCenter() {
final GeoPoint point = getMapCenter();
return new GoogleGeoPoint(point.getLatitudeE6(), point.getLongitudeE6());
}
@Override
public Viewport getViewport() {
return new Viewport(getMapViewCenter(), getLatitudeSpan() / 1e6, getLongitudeSpan() / 1e6);
}
@Override
public void clearOverlays() {
getOverlays().clear();
}
@Override
public MapProjectionImpl getMapProjection() {
return new GoogleMapProjection(getProjection());
}
@Override
public CachesOverlay createAddMapOverlay(final Context context, final Drawable drawable) {
final GoogleCacheOverlay ovl = new GoogleCacheOverlay(context, drawable);
getOverlays().add(ovl);
return ovl.getBase();
}
@Override
public PositionAndScaleOverlay createAddPositionAndScaleOverlay(final Geopoint coords, final String geocode) {
final GoogleOverlay ovl = new GoogleOverlay(this, coords, geocode);
getOverlays().add(ovl);
return (PositionAndScaleOverlay) ovl.getBase();
}
@Override
public int getMapZoomLevel() {
return getZoomLevel();
}
@Override
public void setMapSource() {
setSatellite(GoogleMapProvider.isSatelliteSource(Settings.getMapSource()));
}
@Override
public void repaintRequired(final GeneralOverlay overlay) {
invalidate();
}
@Override
public void setOnDragListener(final OnMapDragListener onDragListener) {
this.onDragListener = onDragListener;
}
@Override
public boolean onTouchEvent(final MotionEvent ev) {
try {
gestureDetector.onTouchEvent(ev);
return super.onTouchEvent(ev);
} catch (final Exception e) {
Log.e("GoogleMapView.onTouchEvent", e);
}
return false;
}
private class GestureListener extends SimpleOnGestureListener {
@Override
public boolean onDoubleTap(final MotionEvent e) {
getController().zoomInFixing((int) e.getX(), (int) e.getY());
if (onDragListener != null) {
onDragListener.onDrag();
}
return true;
}
@Override
public boolean onScroll(final MotionEvent e1, final MotionEvent e2,
final float distanceX, final float distanceY) {
if (onDragListener != null) {
onDragListener.onDrag();
}
return super.onScroll(e1, e2, distanceX, distanceY);
}
}
@Override
public boolean needsInvertedColors() {
return false;
}
@Override
public boolean hasMapThemes() {
// Not supported
return false;
}
@Override
public void setMapTheme() {
// Not supported
}
}