All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.xtremelabs.robolectric.shadows.ShadowMapView Maven / Gradle / Ivy

There is a newer version: 1.2
Show newest version
package com.xtremelabs.robolectric.shadows;

import android.content.Context;
import android.graphics.Point;
import android.view.MotionEvent;
import android.widget.ZoomButtonsController;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;
import com.xtremelabs.robolectric.Robolectric;
import com.xtremelabs.robolectric.internal.Implementation;
import com.xtremelabs.robolectric.internal.Implements;

import java.util.ArrayList;
import java.util.List;

import static com.xtremelabs.robolectric.RobolectricForMaps.shadowOf;

/**
 * Shadow of {@code MapView} that simulates the internal state of a {@code MapView}. Supports {@code Projection}s,
 * {@code Overlay}s, and {@code TouchEvent}s
 */
@SuppressWarnings({"UnusedDeclaration"})
@Implements(MapView.class)
public class ShadowMapView extends ShadowViewGroup {
    private boolean satelliteOn;
    private MapController mapController;
    private List overlays = new ArrayList();
    GeoPoint mapCenter = new GeoPoint(10, 10);
    int longitudeSpan = 20;
    int latitudeSpan = 30;
    int zoomLevel = 1;
    private ShadowMapController shadowMapController;
    private ZoomButtonsController zoomButtonsController;
    private MapView realMapView;
    private Projection projection;
    private boolean useBuiltInZoomMapControls;
    private boolean mouseDownOnMe = false;
    private Point lastTouchEventPoint;
    private GeoPoint mouseDownCenter;
    private boolean preLoadWasCalled;
    private boolean canCoverCenter = true;

    public ShadowMapView(MapView mapView) {
        realMapView = mapView;
        zoomButtonsController = new ZoomButtonsController(mapView);
    }

    public void __constructor__(Context context, String title) {
        super.__constructor__(context);
    }

    public static int toE6(double d) {
        return (int) (d * 1e6);
    }

    public static double fromE6(int i) {
        return i / 1e6;
    }

    @Implementation
    public void setSatellite(boolean satelliteOn) {
        this.satelliteOn = satelliteOn;
    }

    @Implementation
    public boolean isSatellite() {
        return satelliteOn;
    }

    @Implementation
    public boolean canCoverCenter() {
        return canCoverCenter;
    }

    @Implementation
    public MapController getController() {
        if (mapController == null) {
            try {
                mapController = Robolectric.newInstanceOf(MapController.class);
                shadowMapController = shadowOf(mapController);
                shadowMapController.setShadowMapView(this);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return mapController;
    }

    @Implementation
    public ZoomButtonsController getZoomButtonsController() {
        return zoomButtonsController;
    }

    @Implementation
    public void setBuiltInZoomControls(boolean useBuiltInZoomMapControls) {
        this.useBuiltInZoomMapControls = useBuiltInZoomMapControls;
    }

    @Implementation
    public com.google.android.maps.Projection getProjection() {
        if (projection == null) {
            projection = new Projection() {
                @Override public Point toPixels(GeoPoint geoPoint, Point point) {
                    if (point == null) {
                        point = new Point();
                    }

                    point.y = scaleDegree(geoPoint.getLatitudeE6(), bottom, top, mapCenter.getLatitudeE6(), latitudeSpan);
                    point.x = scaleDegree(geoPoint.getLongitudeE6(), left, right, mapCenter.getLongitudeE6(), longitudeSpan);
                    return point;
                }

                @Override public GeoPoint fromPixels(int x, int y) {
                    int lat = scalePixel(y, bottom, -realMapView.getHeight(), mapCenter.getLatitudeE6(), latitudeSpan);
                    int lng = scalePixel(x, left, realMapView.getWidth(), mapCenter.getLongitudeE6(), longitudeSpan);
                    return new GeoPoint(lat, lng);
                }

                @Override public float metersToEquatorPixels(float v) {
                    return 0;
                }
            };
        }
        return projection;
    }

    private int scalePixel(int pixel, int minPixel, int maxPixel, int centerDegree, int spanDegrees) {
        int offsetPixels = pixel - minPixel;
        double ratio = offsetPixels / ((double) maxPixel);
        int minDegrees = centerDegree - spanDegrees / 2;
        return (int) (minDegrees + spanDegrees * ratio);
    }

    private int scaleDegree(int degree, int minPixel, int maxPixel, int centerDegree, int spanDegrees) {
        int minDegree = centerDegree - spanDegrees / 2;
        int offsetDegrees = degree - minDegree;
        double ratio = offsetDegrees / ((double) spanDegrees);
        int spanPixels = maxPixel - minPixel;
        return (int) (minPixel + spanPixels * ratio);
    }

    @Implementation
    public List getOverlays() {
        return overlays;
    }

    @Implementation
    public GeoPoint getMapCenter() {
        return mapCenter;
    }

    @Implementation
    public int getLatitudeSpan() {
        return latitudeSpan;
    }

    @Implementation
    public int getLongitudeSpan() {
        return longitudeSpan;
    }

    @Implementation
    public int getZoomLevel() {
        return zoomLevel;
    }

    @Implementation
    @Override public boolean dispatchTouchEvent(MotionEvent event) {
        for (Overlay overlay : overlays) {
            if (overlay.onTouchEvent(event, realMapView)) {
                return true;
            }
        }

        GeoPoint mouseGeoPoint = getProjection().fromPixels((int) event.getX(), (int) event.getY());
        int diffX = 0;
        int diffY = 0;
        if (mouseDownOnMe) {
            diffX = (int) event.getX() - lastTouchEventPoint.x;
            diffY = (int) event.getY() - lastTouchEventPoint.y;
        }

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                mouseDownOnMe = true;
                mouseDownCenter = getMapCenter();
                break;
            case MotionEvent.ACTION_MOVE:
                if (mouseDownOnMe) {
                    moveByPixels(-diffX, -diffY);
                }
                break;
            case MotionEvent.ACTION_UP:
                if (mouseDownOnMe) {
                    moveByPixels(-diffX, -diffY);
                    mouseDownOnMe = false;
                }
                break;

            case MotionEvent.ACTION_CANCEL:
                getController().setCenter(mouseDownCenter);
                mouseDownOnMe = false;
                break;
        }

        lastTouchEventPoint = new Point((int) event.getX(), (int) event.getY());

        return super.dispatchTouchEvent(event);
    }

    @Implementation
    public void preLoad() {
        preLoadWasCalled = true;
    }

    private void moveByPixels(int x, int y) {
        Point center = getProjection().toPixels(mapCenter, null);
        center.offset(x, y);
        mapCenter = getProjection().fromPixels(center.x, center.y);
    }

    /**
     * Non-Android accessor.
     *
     * @return whether to use built in zoom map controls
     */
    public boolean getUseBuiltInZoomMapControls() {
        return useBuiltInZoomMapControls;
    }

    /**
     * Non-Android accessor.
     *
     * @return whether {@link #preLoad()} has been called on this {@code MapView}
     */
    public boolean preLoadWasCalled() {
        return preLoadWasCalled;
    }

    /**
     * Non-Android accessor to set the latitude span (the absolute value of the difference between the Northernmost and
     * Southernmost latitudes visible on the map) of this {@code MapView}
     *
     * @param latitudeSpan the new latitude span for this {@code MapView}
     */
    public void setLatitudeSpan(int latitudeSpan) {
        this.latitudeSpan = latitudeSpan;
    }

    /**
     * Non-Android accessor to set the longitude span (the absolute value of the difference between the Easternmost and
     * Westernmost longitude visible on the map) of this {@code MapView}
     *
     * @param longitudeSpan the new latitude span for this {@code MapView}
     */
    public void setLongitudeSpan(int longitudeSpan) {
        this.longitudeSpan = longitudeSpan;
    }

    /**
     * Non-Android accessor that controls the value to be returned by {@link #canCoverCenter()}
     *
     * @param canCoverCenter the value to be returned by {@link #canCoverCenter()}
     */
    public void setCanCoverCenter(boolean canCoverCenter) {
        this.canCoverCenter = canCoverCenter;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy