From c7e910af4b022877b0424011eec7336ef86c7f4e Mon Sep 17 00:00:00 2001 From: mar-v-in Date: Fri, 9 Jan 2015 22:41:22 +0100 Subject: [PATCH] Add more API + docs (including TileProvider) --- .../gms/maps/model/CameraPosition.java | 9 +- .../gms/maps/model/GroundOverlayOptions.java | 21 +-- .../google/android/gms/maps/model/LatLng.java | 8 +- .../android/gms/maps/model/LatLngBounds.java | 176 +++++++++++++++++- .../gms/maps/model/PolygonOptions.java | 4 + .../gms/maps/model/PolylineOptions.java | 4 + .../google/android/gms/maps/model/Tile.java | 78 ++++++++ .../gms/maps/model/TileOverlayOptions.java | 100 +++++++++- .../android/gms/maps/model/TileProvider.java | 25 +++ 9 files changed, 401 insertions(+), 24 deletions(-) create mode 100644 src/com/google/android/gms/maps/model/Tile.java create mode 100644 src/com/google/android/gms/maps/model/TileProvider.java diff --git a/src/com/google/android/gms/maps/model/CameraPosition.java b/src/com/google/android/gms/maps/model/CameraPosition.java index ea00da74..f9bb0bed 100644 --- a/src/com/google/android/gms/maps/model/CameraPosition.java +++ b/src/com/google/android/gms/maps/model/CameraPosition.java @@ -173,7 +173,12 @@ public final class CameraPosition implements SafeParcelable { @Override public String toString() { - return super.toString(); // TODO + return "CameraPosition{" + + "target=" + target + + ", zoom=" + zoom + + ", tilt=" + tilt + + ", bearing=" + bearing + + '}'; } @Override @@ -222,7 +227,7 @@ public final class CameraPosition implements SafeParcelable { * Builds a {@link CameraPosition}. */ public CameraPosition build() { - return null; + return new CameraPosition(target, zoom, tilt, bearing); } /** diff --git a/src/com/google/android/gms/maps/model/GroundOverlayOptions.java b/src/com/google/android/gms/maps/model/GroundOverlayOptions.java index 0792a825..3cf9cfb4 100644 --- a/src/com/google/android/gms/maps/model/GroundOverlayOptions.java +++ b/src/com/google/android/gms/maps/model/GroundOverlayOptions.java @@ -251,14 +251,9 @@ public class GroundOverlayOptions implements SafeParcelable { */ public GroundOverlayOptions position(LatLng location, float width, float height) throws IllegalArgumentException, IllegalStateException { - if (location == null) - throw new IllegalArgumentException("location must not be null"); - if (width < 0 || height < 0) - throw new IllegalArgumentException("Width and height must not be negative"); - if (bounds != null) - throw new IllegalStateException("Position already set using positionFromBounds"); - this.location = location; - this.width = width; + position(location, width); + if (height < 0) + throw new IllegalArgumentException("height must not be negative"); this.height = height; return this; } @@ -284,10 +279,10 @@ public class GroundOverlayOptions implements SafeParcelable { throws IllegalArgumentException, IllegalStateException { if (location == null) throw new IllegalArgumentException("location must not be null"); - if (width < 0 || height < 0) - throw new IllegalArgumentException("Width must not be negative"); + if (width < 0) + throw new IllegalArgumentException("width must not be negative"); if (bounds != null) - throw new IllegalStateException("Position already set using positionFromBounds"); + throw new IllegalStateException("Position already set using positionFromBounds()"); this.location = location; this.width = width; return this; @@ -305,6 +300,8 @@ public class GroundOverlayOptions implements SafeParcelable { */ public GroundOverlayOptions positionFromBounds(LatLngBounds bounds) throws IllegalStateException { + if (location != null) + throw new IllegalStateException("Position already set using position()"); this.bounds = bounds; return this; } @@ -320,6 +317,8 @@ public class GroundOverlayOptions implements SafeParcelable { * @throws IllegalArgumentException if the transparency is outside the range [0..1]. */ public GroundOverlayOptions transparency(float transparency) throws IllegalArgumentException { + if (transparency < 0 || transparency > 1) + throw new IllegalArgumentException("transparency must be in range [0..1]"); this.transparency = transparency; return this; } diff --git a/src/com/google/android/gms/maps/model/LatLng.java b/src/com/google/android/gms/maps/model/LatLng.java index 0844021e..94a25340 100644 --- a/src/com/google/android/gms/maps/model/LatLng.java +++ b/src/com/google/android/gms/maps/model/LatLng.java @@ -96,10 +96,10 @@ public final class LatLng implements SafeParcelable { @Override public final int hashCode() { - long lat = Double.doubleToLongBits(latitude); - int tmp = 31 + (int) (lat ^ lat >>> 32); - long lon = Double.doubleToLongBits(longitude); - return tmp * 31 + (int) (lon ^ lon >>> 32); + long tmp1 = Double.doubleToLongBits(latitude); + int tmp2 = 31 + (int) (tmp1 ^ tmp1 >>> 32); + tmp1 = Double.doubleToLongBits(longitude); + return tmp2 * 31 + (int) (tmp1 ^ tmp1 >>> 32); } @Override diff --git a/src/com/google/android/gms/maps/model/LatLngBounds.java b/src/com/google/android/gms/maps/model/LatLngBounds.java index b864857e..ac849e37 100644 --- a/src/com/google/android/gms/maps/model/LatLngBounds.java +++ b/src/com/google/android/gms/maps/model/LatLngBounds.java @@ -21,6 +21,8 @@ import org.microg.safeparcel.SafeParcelUtil; import org.microg.safeparcel.SafeParcelable; import org.microg.safeparcel.SafeParceled; +import java.util.Arrays; + /** * An immutable class representing a latitude/longitude aligned rectangle. */ @@ -52,20 +54,145 @@ public final class LatLngBounds implements SafeParcelable { SafeParcelUtil.readObject(this, in); } + /** + * Creates a new bounds based on a southwest and a northeast corner. + *

+ * The bounds conceptually includes all points where: + *

+ * + * @param southwest southwest corner + * @param northeast northeast corner + * @throws IllegalArgumentException if the latitude of the northeast corner is below the + * latitude of the southwest corner. + */ public LatLngBounds(LatLng southwest, LatLng northeast) throws IllegalArgumentException { + if (northeast.latitude < southwest.latitude) + throw new IllegalArgumentException("latitude of northeast corner must not be" + + " lower than latitude of southwest corner"); this.versionCode = 1; this.southwest = southwest; this.northeast = northeast; } + /** + * Creates a new builder. + */ + public Builder builder() { + return new Builder(); + } + + /** + * Returns whether this contains the given {@link LatLng}. + * + * @param point the {@link LatLng} to test + * @return {@code true} if this contains the given point; {@code false} if not. + */ + public boolean contains(LatLng point) { + return containsLatitude(point.latitude) && containsLongitude(point.longitude); + } + + private boolean containsLatitude(double latitude) { + return southwest.latitude <= latitude && latitude <= northeast.latitude; + } + + private boolean containsLongitude(double longitude) { + return southwest.longitude <= northeast.longitude ? ( + southwest.longitude <= longitude && longitude <= northeast.longitude + ) : ( + southwest.longitude >= longitude && longitude < 180 || + longitude >= -180 && longitude <= northeast.longitude + ); + } + @Override public int describeContents() { return 0; } @Override - public void writeToParcel(Parcel dest, int flags) { - SafeParcelUtil.writeObject(this, dest, flags); + public boolean equals(Object o) { + if (this == o) + return true; + if (o == null || getClass() != o.getClass()) + return false; + + LatLngBounds that = (LatLngBounds) o; + + if (!northeast.equals(that.northeast)) + return false; + if (!southwest.equals(that.southwest)) + return false; + + return true; + } + + /** + * Returns the center of this {@link LatLngBounds}. The center is simply the average of the + * coordinates (taking into account if it crosses the antimeridian). This is approximately the + * geographical center (it would be exact if the Earth were a perfect sphere). It will not + * necessarily be the center of the rectangle as drawn on the map due to the Mercator + * projection. + * + * @return A {@link LatLng} that is the center of the {@link LatLngBounds}. + */ + public LatLng getCenter() { + double lat = (southwest.latitude + northeast.latitude) / 2.0; + double lon = (southwest.longitude + northeast.longitude) / 2.0 + + southwest.longitude <= northeast.latitude ? 0 : 180.0; + return new LatLng(lat, lon); + } + + @Override + public int hashCode() { + return Arrays.hashCode(new Object[] { southwest, northeast }); + } + + /** + * Returns a new {@link LatLngBounds} that extends this {@link LatLngBounds} to include the + * given {@link LatLng}. This will return the smallest LatLngBounds that contains both this + * and the extra point. + *

+ * In particular, it will consider extending the bounds both in the eastward and westward + * directions (one of which may cross the antimeridian) and choose the smaller of the two. In + * the case that both directions result in a LatLngBounds of the same size, this will extend + * it in the eastward direction. + * + * @param point a {@link LatLng} to be included in the new bounds + * @return A new {@link LatLngBounds} that contains this and the extra point. + */ + public LatLngBounds including(LatLng point) { + double latMin = Math.min(southwest.latitude, point.latitude); + double latMax = Math.max(northeast.latitude, point.latitude); + double lonMin = southwest.longitude; + double lonMax = northeast.longitude; + if (!containsLongitude(point.longitude)) { + if ((southwest.longitude - point.longitude + 360.0) % 360.0 < + (point.longitude - northeast.longitude + 360.0D) % 360.0D) { + lonMin = point.longitude; + } else { + lonMax = point.longitude; + } + } + return new LatLngBounds(new LatLng(latMin, lonMin), new LatLng(latMax, lonMax)); + } + + @Override + public String toString() { + return "LatLngBounds{" + + "southwest=" + southwest + + ", northeast=" + northeast + + '}'; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + SafeParcelUtil.writeObject(this, out, flags); } public static Creator CREATOR = new Creator() { @@ -77,4 +204,49 @@ public final class LatLngBounds implements SafeParcelable { return new LatLngBounds[size]; } }; + + /** + * This is a builder that is able to create a minimum bound based on a set of LatLng points. + */ + public static final class Builder { + private LatLngBounds bounds; + + public Builder() { + + } + + /** + * Creates the LatLng bounds. + * + * @throws IllegalStateException if no points have been included. + */ + public LatLngBounds build() throws IllegalStateException { + if (bounds == null) + throw new IllegalStateException( + "You must not call build() before adding points to the Builder"); + return bounds; + } + + /** + * Includes this point for building of the bounds. The bounds will be extended in a + * minimum way to include this point. + *

+ * More precisely, it will consider extending the bounds both in the eastward and westward + * directions (one of which may cross the antimeridian) and choose the smaller of the two. + * In the case that both directions result in a LatLngBounds of the same size, this will + * extend it in the eastward direction. For example, adding points (0, -179) and (1, 179) + * will create a bound crossing the 180 longitude. + * + * @param point A {@link LatLng} to be included in the bounds. + * @return This builder object with a new point added. + */ + public Builder include(LatLng point) { + if (bounds == null) { + bounds = new LatLngBounds(point, point); + } else { + bounds = bounds.including(point); + } + return this; + } + } } diff --git a/src/com/google/android/gms/maps/model/PolygonOptions.java b/src/com/google/android/gms/maps/model/PolygonOptions.java index aaefc97c..8898f11e 100644 --- a/src/com/google/android/gms/maps/model/PolygonOptions.java +++ b/src/com/google/android/gms/maps/model/PolygonOptions.java @@ -20,6 +20,10 @@ import android.os.Parcel; import org.microg.safeparcel.SafeParcelUtil; import org.microg.safeparcel.SafeParcelable; +/** + * Defines options for a polygon. + * TODO + */ public class PolygonOptions implements SafeParcelable { @Override public int describeContents() { diff --git a/src/com/google/android/gms/maps/model/PolylineOptions.java b/src/com/google/android/gms/maps/model/PolylineOptions.java index ee927934..5e861b7e 100644 --- a/src/com/google/android/gms/maps/model/PolylineOptions.java +++ b/src/com/google/android/gms/maps/model/PolylineOptions.java @@ -23,6 +23,10 @@ import org.microg.safeparcel.SafeParceled; import java.util.List; +/** + * Defines options for a polyline. + * TODO + */ public class PolylineOptions implements SafeParcelable { @SafeParceled(1) private int versionCode; diff --git a/src/com/google/android/gms/maps/model/Tile.java b/src/com/google/android/gms/maps/model/Tile.java new file mode 100644 index 00000000..9ba8b612 --- /dev/null +++ b/src/com/google/android/gms/maps/model/Tile.java @@ -0,0 +1,78 @@ +package com.google.android.gms.maps.model; + +import android.os.Parcel; +import org.microg.safeparcel.SafeParcelUtil; +import org.microg.safeparcel.SafeParcelable; +import org.microg.safeparcel.SafeParceled; + +/** + * Contains information about a Tile that is returned by a {@link TileProvider}. + * TODO SafeParceled + */ +public class Tile implements SafeParcelable { + @SafeParceled(1) + private final int versionCode; + /** + * The width of the image encoded by {@link #data} in pixels. + */ + @SafeParceled(2) + public final int width; + /** + * The height of the image encoded by {@link #data} in pixels. + */ + @SafeParceled(3) + public final int height; + /** + * A byte array containing the image data. The image will be created from this data by calling + * {@link android.graphics.BitmapFactory#decodeByteArray(byte[], int, int)}. + */ + @SafeParceled(4) + public final byte[] data; + + private Tile() { + versionCode = -1; + width = height = 0; + data = null; + } + + private Tile(Parcel in) { + this(); + SafeParcelUtil.readObject(this, in); + } + + /** + * Constructs a {@link Tile}. + * + * @param width the width of the image in pixels + * @param height the height of the image in pixels + * @param data A byte array containing the image data. The image will be created from this + * data by calling + * {@link android.graphics.BitmapFactory#decodeByteArray(byte[], int, int)}. + */ + public Tile(int width, int height, byte[] data) { + this.versionCode = 1; + this.width = width; + this.height = height; + this.data = data; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel out, int flags) { + SafeParcelUtil.writeObject(this, out, flags); + } + + public static Creator CREATOR = new Creator() { + public Tile createFromParcel(Parcel source) { + return new Tile(source); + } + + public Tile[] newArray(int size) { + return new Tile[size]; + } + }; +} diff --git a/src/com/google/android/gms/maps/model/TileOverlayOptions.java b/src/com/google/android/gms/maps/model/TileOverlayOptions.java index 0256adfc..6fad3fd7 100644 --- a/src/com/google/android/gms/maps/model/TileOverlayOptions.java +++ b/src/com/google/android/gms/maps/model/TileOverlayOptions.java @@ -20,23 +20,113 @@ import android.os.Parcel; import org.microg.safeparcel.SafeParcelUtil; import org.microg.safeparcel.SafeParcelable; +/** + * Defines options for a TileOverlay. + */ public class TileOverlayOptions implements SafeParcelable { + private TileProvider tileProvider; + private boolean visible = true; + private boolean fadeIn = true; + private float zIndex; + + /** + * Creates a new set of tile overlay options. + */ + public TileOverlayOptions() { + } + + private TileOverlayOptions(Parcel in) { + SafeParcelUtil.readObject(this, in); + } + @Override public int describeContents() { return 0; } + /** + * Specifies whether the tiles should fade in. The default is {@code true}. + * + * @return this {@link TileOverlayOptions} object with a new fadeIn setting. + */ + public TileOverlayOptions fadeIn(boolean fadeIn) { + this.fadeIn = fadeIn; + return this; + } + + /** + * Gets whether the tiles should fade in. + * + * @return {@code true} if the tiles are to fade in; {@code false} if it is not. + */ + public boolean getFadeIn() { + return fadeIn; + } + + /** + * Gets the tile provider set for this {@link TileOverlayOptions} object. + * + * @return the {@link TileProvider} of the tile overlay. + */ + public TileProvider getTileProvider() { + return tileProvider; + } + + /** + * Gets the zIndex set for this {@link TileOverlayOptions} object. + * + * @return the zIndex of the tile overlay. + */ + public float getZIndex() { + return zIndex; + } + + /** + * Gets the visibility setting for this {@link TileOverlayOptions} object. + * + * @return {@code true} if the tile overlay is to be visible; {@code false} if it is not. + */ + public boolean isVisible() { + return visible; + } + + /** + * Specifies the tile provider to use for this tile overlay. + * + * @param tileProvider the {@link TileProvider} to use for this tile overlay. + * @return the object for which the method was called, with the new tile provider set. + */ + public TileOverlayOptions tileProvider(TileProvider tileProvider) { + this.tileProvider = tileProvider; + return this; + } + + /** + * Specifies the visibility for the tile overlay. The default visibility is {@code true}. + * + * @return this {@link TileOverlayOptions} object with a new visibility setting. + */ + public TileOverlayOptions visible(boolean visible) { + this.visible = visible; + return this; + } + @Override public void writeToParcel(Parcel dest, int flags) { SafeParcelUtil.writeObject(this, dest, flags); } - public TileOverlayOptions() { - } - - private TileOverlayOptions(Parcel in) { - SafeParcelUtil.readObject(this, in); + /** + * Specifies the tile overlay's zIndex, i.e., the order in which it will be drawn where + * overlays with larger values are drawn above those with lower values. See the documentation + * at the top of this class for more information about zIndex. + * + * @return this {@link TileOverlayOptions} object with a new zIndex set. + */ + public TileOverlayOptions zIndex(float zIndex) { + this.zIndex = zIndex; + return this; } public static Creator CREATOR = new Creator() { diff --git a/src/com/google/android/gms/maps/model/TileProvider.java b/src/com/google/android/gms/maps/model/TileProvider.java new file mode 100644 index 00000000..21eaaadc --- /dev/null +++ b/src/com/google/android/gms/maps/model/TileProvider.java @@ -0,0 +1,25 @@ +package com.google.android.gms.maps.model; + +/** + * An interface for a class that provides the tile images for a TileOverlay. For information about + * the tile coordinate system, see TileOverlay. + *

+ * Calls to methods in this interface might be made from multiple threads so implementations of + * this interface must be threadsafe. + */ +public interface TileProvider { + public static final Tile NO_TILE = new Tile(-1, -1, null); + + /** + * Returns the tile to be used for this tile coordinate. + * + * @param x The x coordinate of the tile. This will be in the range [0, 2^(zoom - 1)] inclusive. + * @param y The y coordinate of the tile. This will be in the range [0, 2^(zoom - 1)] inclusive. + * @param zoom The zoom level of the tile. + * @return the {@link Tile} to be used for this tile coordinate. If you do not wish to provide + * a tile for this tile coordinate, return {@link #NO_TILE}. If the tile could not be found at + * this point in time, return null and further requests might be made with an exponential + * backoff. + */ + public Tile getTile(int x, int y, int zoom); +}