Marker supprt (without info window)

This commit is contained in:
mar-v-in 2014-06-16 13:16:08 +02:00
parent 9c16f95c2d
commit a0d1b177d7
22 changed files with 505 additions and 53 deletions

View File

@ -17,7 +17,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.google.android.gms"
android:versionCode="4323000">
android:versionCode="4452036">
<uses-sdk android:minSdkVersion="16" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -87,6 +87,17 @@ public class SafeReader {
readStart(parcel, position, 8);
return parcel.readDouble();
}
public static String readString(Parcel parcel, int position) {
int length = readStart(parcel, position);
int start = parcel.dataPosition();
if (length == 0)
return null;
String string = parcel.readString();
parcel.setDataPosition(start + length);
return string;
}
public static IBinder readBinder(Parcel parcel, int position) {
int length = readStart(parcel, position);
int start = parcel.dataPosition();

View File

@ -130,10 +130,14 @@ public class CameraUpdateFactoryImpl extends ICameraUpdateFactoryDelegate.Stub {
return new ObjectWrapper<CameraUpdate>(new CameraUpdate() {
@Override
public void update(GoogleMapImpl map) {
// TODO
}
});
}
double latSpan = bounds.northEast.latitude - bounds.southWest.latitude,
lonSpan = bounds.northEast.longitude - bounds.southWest.longitude;
map.getController().zoomToSpan((int) (latSpan * 1E6), (int) (lonSpan * 1E6));
map.getController().setCenter(new GeoPoint((int) ((bounds.southWest.latitude + latSpan/2) * 1E6),
(int) ((bounds.southWest.longitude + lonSpan/2) * 1E6)));
}
});
}
@Override
public IObjectWrapper newLatLngBoundsWithSize(LatLngBounds bounds, int i1, int i2, int i3) throws RemoteException {

View File

@ -47,11 +47,14 @@ public class GoogleMapImpl {
private final Delegate delegate = new Delegate();
private MapView mapView;
private int mapType = 1;
private Context context;
private IOnMarkerClickListener markerClickListener;
public GoogleMapImpl(LayoutInflater inflater, GoogleMapOptions options) {
this.view = new FrameLayout(inflater.getContext());
context = inflater.getContext();
this.view = new FrameLayout(context);
try {
mapView = (MapView) Class.forName("com.google.android.maps.MapView").getConstructor(Context.class, String.class).newInstance(inflater.getContext(), null);
mapView = (MapView) Class.forName("com.google.android.maps.MapView").getConstructor(Context.class, String.class).newInstance(context, null);
view.addView(mapView);
} catch (Exception e) {
Log.d(TAG, "Sorry, can't create legacy MapView");
@ -63,7 +66,15 @@ public class GoogleMapImpl {
}
MapView getMapView() {
public IOnMarkerClickListener getMarkerClickListener() {
return markerClickListener;
}
public Context getContext() {
return context;
}
MapView getMapView() {
return mapView;
}
@ -79,7 +90,20 @@ public class GoogleMapImpl {
return delegate;
}
private class Delegate extends IGoogleMapDelegate.Stub {
public void remove(MarkerImpl marker) {
mapView.getOverlays().remove(marker);
}
public void redraw() {
mapView.postInvalidate();
try {
((MapView.WrappedMapView) mapView.getWrapped()).postInvalidate();
} catch (Exception e) {
Log.w(TAG, "MapView does not support extended microg features", e);
}
}
private class Delegate extends IGoogleMapDelegate.Stub {
@Override
public CameraPosition getCameraPosition() throws RemoteException {
if (mapView == null) return null;
@ -136,7 +160,10 @@ public class GoogleMapImpl {
@Override
public IMarkerDelegate addMarker(MarkerOptions options) throws RemoteException {
return new MarkerImpl(options);
MarkerImpl marker = new MarkerImpl(options, GoogleMapImpl.this);
mapView.getOverlays().add(marker.getOverlay());
redraw();
return marker;
}
@Override
@ -151,7 +178,8 @@ public class GoogleMapImpl {
@Override
public void clear() throws RemoteException {
mapView.getOverlays().clear();
redraw();
}
@Override
@ -256,7 +284,7 @@ public class GoogleMapImpl {
@Override
public void setOnMarkerClickListener(IOnMarkerClickListener listener) throws RemoteException {
markerClickListener = listener;
}
@Override

View File

@ -1,4 +1,7 @@
package com.google.android.gms.maps.internal;
import com.google.android.gms.maps.model.internal.IMarkerDelegate;
interface IOnMarkerClickListener {
boolean onMarkerClick(IMarkerDelegate marker);
}

View File

@ -16,7 +16,11 @@
package com.google.android.gms.maps.model;
import android.content.Context;
import android.graphics.Bitmap;
import com.google.android.gms.dynamic.IObjectWrapper;
import com.google.android.gms.dynamic.ObjectWrapper;
import com.google.android.gms.maps.model.internal.AbstractBitmapDescriptor;
public class BitmapDescriptor {
private final IObjectWrapper remoteObject;
@ -28,4 +32,41 @@ public class BitmapDescriptor {
public IObjectWrapper getRemoteObject() {
return remoteObject;
}
public AbstractBitmapDescriptor getDescriptor() {
if (remoteObject == null) return null;
Object unwrap = ObjectWrapper.unwrap(remoteObject);
if (unwrap instanceof AbstractBitmapDescriptor) {
return ((AbstractBitmapDescriptor) unwrap);
} else {
return null;
}
}
public Bitmap getBitmap() {
if (getDescriptor() != null) {
return getDescriptor().getBitmap();
}
return null;
}
@Override
public String toString() {
return "BitmapDescriptor{" +
"remote=" + getDescriptor() +
'}';
}
public void loadBitmapAsync(final Context context, final Runnable after) {
if (getDescriptor() != null) {
new Thread(new Runnable() {
@Override
public void run() {
if (getDescriptor().loadBitmap(context) != null) {
after.run();
}
}
}).start();
}
}
}

View File

@ -20,6 +20,7 @@ import android.os.Parcel;
import com.google.android.gms.common.safeparcel.SafeParcelable;
import com.google.android.gms.common.safeparcel.SafeReader;
import com.google.android.gms.common.safeparcel.SafeWriter;
import com.google.android.maps.GeoPoint;
public class LatLng implements SafeParcelable {
public static Creator<LatLng> CREATOR = new Creator<LatLng>() {
@ -98,4 +99,8 @@ public class LatLng implements SafeParcelable {
SafeWriter.write(dest, 3, longitude);
SafeWriter.writeEnd(dest, start);
}
public GeoPoint toGeoPoint() {
return new GeoPoint((int) (latitude * 1E6F), (int) (longitude * 1E6F));
}
}

View File

@ -32,8 +32,8 @@ public class LatLngBounds implements SafeParcelable {
}
};
private int versionCode;
private LatLng southWest;
private LatLng northEast;
public LatLng southWest;
public LatLng northEast;
public LatLngBounds() {
}

View File

@ -16,11 +16,29 @@
package com.google.android.gms.maps.model;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import com.google.android.gms.common.safeparcel.SafeReader;
import com.google.android.gms.dynamic.ObjectWrapper;
public class MarkerOptions implements Parcelable {
private int versionCode = 1;
private LatLng position;
private String title;
private String snippet;
private BitmapDescriptor icon;
private float anchorU = 0.5F;
private float anchorV = 1F;
private boolean draggable;
private boolean visible;
private boolean flat;
private float rotation = 0F;
private float infoWindowAnchorU = 0F;
private float infoWindowAnchorV = 1F;
private float alpha = 1F;
@Override
public int describeContents() {
return 0;
@ -34,6 +52,113 @@ public class MarkerOptions implements Parcelable {
}
private MarkerOptions(Parcel in) {
int end = SafeReader.readStart(in);
while (in.dataPosition() < end) {
int position = SafeReader.readSingleInt(in);
switch (SafeReader.halfOf(position)) {
case 1:
this.versionCode = SafeReader.readInt(in, position);
break;
case 2:
this.position = SafeReader.readParcelable(in, position, LatLng.CREATOR);
break;
case 3:
this.title = SafeReader.readString(in, position);
break;
case 4:
this.snippet = SafeReader.readString(in, position);
break;
case 5:
IBinder icon = SafeReader.readBinder(in, position);
this.icon = icon == null ? null : new BitmapDescriptor(ObjectWrapper.asInterface(icon));
break;
case 6:
this.anchorU = SafeReader.readFloat(in, position);
break;
case 7:
this.anchorV = SafeReader.readFloat(in, position);
break;
case 8:
this.draggable = SafeReader.readBool(in, position);
break;
case 9:
this.visible = SafeReader.readBool(in, position);
break;
case 10:
this.flat = SafeReader.readBool(in, position);
break;
case 11:
this.rotation = SafeReader.readFloat(in, position);
break;
case 12:
this.infoWindowAnchorU = SafeReader.readFloat(in, position);
break;
case 13:
this.infoWindowAnchorV = SafeReader.readFloat(in, position);
break;
case 14:
this.rotation = SafeReader.readFloat(in, position);
break;
default:
SafeReader.skip(in, position);
break;
}
}
if (in.dataPosition() > end) {
throw new SafeReader.ReadException("Overread allowed size end=" + end, in);
}
}
public LatLng getPosition() {
return position;
}
public String getTitle() {
return title;
}
public String getSnippet() {
return snippet;
}
public BitmapDescriptor getIcon() {
return icon;
}
public float getAnchorU() {
return anchorU;
}
public float getAnchorV() {
return anchorV;
}
public boolean isDraggable() {
return draggable;
}
public boolean isVisible() {
return visible;
}
public boolean isFlat() {
return flat;
}
public float getRotation() {
return rotation;
}
public float getInfoWindowAnchorU() {
return infoWindowAnchorU;
}
public float getInfoWindowAnchorV() {
return infoWindowAnchorV;
}
public float getAlpha() {
return alpha;
}
public static Creator<MarkerOptions> CREATOR = new Creator<MarkerOptions>() {

View File

@ -0,0 +1,40 @@
/*
* Copyright (c) 2014 μg Project Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.android.gms.maps.model.internal;
import android.content.Context;
import android.graphics.Bitmap;
public abstract class AbstractBitmapDescriptor {
private Bitmap bitmap;
protected abstract Bitmap generateBitmap(Context context);
public Bitmap loadBitmap(Context context) {
if (bitmap == null) {
synchronized (this) {
if (bitmap == null) bitmap = generateBitmap(context);
}
}
return bitmap;
}
public Bitmap getBitmap() {
return bitmap;
}
}

View File

@ -16,7 +16,26 @@
package com.google.android.gms.maps.model.internal;
public class AssetBitmapDescriptor {
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.IOException;
public class AssetBitmapDescriptor extends AbstractBitmapDescriptor {
private String assetName;
public AssetBitmapDescriptor(String assetName) {
this.assetName = assetName;
}
@Override
protected Bitmap generateBitmap(Context context) {
try {
return BitmapFactory.decodeStream(context.getAssets().open(assetName));
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}

View File

@ -16,9 +16,18 @@
package com.google.android.gms.maps.model.internal;
import android.content.Context;
import android.graphics.Bitmap;
public class BitmapBitmapDescriptor {
public class BitmapBitmapDescriptor extends AbstractBitmapDescriptor {
private Bitmap bitmap;
public BitmapBitmapDescriptor(Bitmap bitmap) {
this.bitmap = bitmap;
}
@Override
public Bitmap generateBitmap(Context context) {
return bitmap;
}
}

View File

@ -116,7 +116,7 @@ public class CircleImpl extends ICircleDelegate.Stub {
@Override
public boolean equalsRemote(ICircleDelegate other) throws RemoteException {
return other.getId().equals(getId());
return other != null &&other.getId().equals(getId());
}
@Override

View File

@ -16,8 +16,33 @@
package com.google.android.gms.maps.model.internal;
public class DefaultBitmapDescriptor {
public DefaultBitmapDescriptor(float hue) {
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import com.google.android.gms.R;
import com.google.android.gms.maps.internal.ResourcesContainer;
public class DefaultBitmapDescriptor extends AbstractBitmapDescriptor {
private float hue;
public DefaultBitmapDescriptor(float hue) {
this.hue = hue;
}
@Override
public Bitmap generateBitmap(Context context) {
Bitmap source = BitmapFactory.decodeResource(ResourcesContainer.get(), R.drawable.maps_default_marker);
Bitmap bitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(), source.getConfig());
float[] hsv = new float[3];
for (int x = 0; x < bitmap.getWidth(); x++) {
for (int y = 0; y < bitmap.getHeight(); y++) {
int pixel = source.getPixel(x, y);
Color.colorToHSV(pixel, hsv);
hsv[0] = (hsv[0] + hue) % 360;
bitmap.setPixel(x, y, Color.HSVToColor(Color.alpha(pixel), hsv));
}
}
return bitmap;
}
}

View File

@ -16,7 +16,19 @@
package com.google.android.gms.maps.model.internal;
public class FileBitmapDescriptor {
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
public class FileBitmapDescriptor extends AbstractBitmapDescriptor {
private String fileName;
public FileBitmapDescriptor(String fileName) {
}
this.fileName = fileName;
}
@Override
public Bitmap generateBitmap(Context context) {
return BitmapFactory.decodeFile(fileName);
}
}

View File

@ -129,7 +129,7 @@ public class GroundOverlayImpl extends IGroundOverlayDelegate.Stub {
@Override
public boolean equalsRemote(IGroundOverlayDelegate other) throws RemoteException {
return other.getId().equals(getId());
return other != null && other.getId().equals(getId());
}
@Override

View File

@ -10,7 +10,7 @@ interface IMarkerDelegate {
LatLng getPosition();
void setTitle(String title);
String getTitle();
void setSnippet(String title);
void setSnippet(String snippet);
String getSnippet();
void setDraggable(boolean drag);
boolean isDraggable();
@ -21,7 +21,7 @@ interface IMarkerDelegate {
boolean isVisible();
boolean equalsRemote(IMarkerDelegate other);
int hashCodeRemote();
void todo(IObjectWrapper obj);
void setIcon(IObjectWrapper obj);
void setAnchor(float x, float y);
void setFlat(boolean flat);
boolean isFlat();

View File

@ -16,63 +16,165 @@
package com.google.android.gms.maps.model.internal;
import android.graphics.*;
import android.graphics.drawable.Drawable;
import android.os.RemoteException;
import android.util.Log;
import android.view.MotionEvent;
import com.google.android.gms.dynamic.IObjectWrapper;
import com.google.android.gms.dynamic.ObjectWrapper;
import com.google.android.gms.maps.internal.GoogleMapImpl;
import com.google.android.gms.maps.internal.IOnMarkerClickListener;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
public class MarkerImpl extends IMarkerDelegate.Stub {
public MarkerImpl(MarkerOptions options) {
private static final String TAG = MarkerImpl.class.getName();
private float alpha;
private boolean flat;
private boolean draggable;
private String id = Integer.toHexString(hashCode());
private LatLng position;
private float anchorU;
private float anchorV;
private float rotation;
private String snippet;
private String title;
private boolean visible;
private BitmapDescriptor icon;
private GoogleMapImpl map;
private Overlay overlay = new Overlay() {
private Point point = new Point();
@Override
public boolean onTap(GeoPoint p, MapView mapView) {
Point touchPoint = mapView.getProjection().toPixels(p, null);
Bitmap bitmap = icon.getBitmap();
if (bitmap == null) return false;
mapView.getProjection().toPixels(position.toGeoPoint(), point);
float xTest = bitmap.getWidth() * anchorU + touchPoint.x - point.x;
float yTest = bitmap.getHeight() * anchorV + touchPoint.y - point.y;
if (0 < xTest && xTest < bitmap.getWidth() && 0 < yTest && yTest < bitmap.getHeight()) {
Log.d(TAG, "touched " + title);
IOnMarkerClickListener markerClickListener = map.getMarkerClickListener();
boolean result = false;
if (markerClickListener != null) {
try {
result = markerClickListener.onMarkerClick(MarkerImpl.this);
} catch (RemoteException e) {
Log.w(TAG, e);
}
}
if (!result) {
mapView.getController().animateTo(position.toGeoPoint());
// TODO info window
}
return true;
}
return false;
}
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
if (!shadow) {
Bitmap bitmap = icon.getBitmap();
if (bitmap != null) {
mapView.getProjection().toPixels(position.toGeoPoint(), point);
float x = point.x - bitmap.getWidth() * anchorU;
float y = point.y - bitmap.getHeight() * anchorV;
Paint paint = new Paint();
paint.setAlpha((int) (alpha * 255));
Matrix matrix = new Matrix();
matrix.setRotate(rotation, bitmap.getWidth() / 2, bitmap.getHeight() / 2);
matrix.postTranslate(x, y);
canvas.drawBitmap(bitmap, matrix, paint);
} else {
icon.loadBitmapAsync(map.getContext(), new Runnable() {
@Override
public void run() {
map.redraw();
}
});
}
} else {
// TODO: shadow based on flat
}
}
};
public MarkerImpl(MarkerOptions options, GoogleMapImpl map) {
this.map = map;
this.alpha = options.getAlpha();
this.draggable = options.isDraggable();
this.position = options.getPosition();
if (position == null) position = new LatLng(0, 0);
this.rotation = options.getRotation();
this.anchorU = options.getAnchorU();
this.anchorV = options.getAnchorV();
this.snippet = options.getSnippet();
this.title = options.getTitle();
this.visible = options.isVisible();
this.icon = options.getIcon();
if (icon == null)
icon = new BitmapDescriptor(new ObjectWrapper<DefaultBitmapDescriptor>(new DefaultBitmapDescriptor(0)));
Log.d(TAG, "New: " + title + " @ " + position + ", " + icon);
}
@Override
public void remove() throws RemoteException {
map.remove(this);
}
@Override
public String getId() throws RemoteException {
return null;
return id;
}
@Override
public void setPosition(LatLng pos) throws RemoteException {
this.position = pos;
}
@Override
public LatLng getPosition() throws RemoteException {
return null;
return position;
}
@Override
public void setTitle(String title) throws RemoteException {
this.title = title;
}
@Override
public String getTitle() throws RemoteException {
return null;
return title;
}
@Override
public void setSnippet(String title) throws RemoteException {
public void setSnippet(String snippet) throws RemoteException {
this.snippet = snippet;
}
@Override
public String getSnippet() throws RemoteException {
return null;
return snippet;
}
@Override
public void setDraggable(boolean drag) throws RemoteException {
this.draggable = drag;
}
@Override
public boolean isDraggable() throws RemoteException {
return false;
return draggable;
}
@Override
@ -92,37 +194,42 @@ public class MarkerImpl extends IMarkerDelegate.Stub {
@Override
public void setVisible(boolean visible) throws RemoteException {
this.visible = visible;
}
@Override
public boolean isVisible() throws RemoteException {
return false;
return visible;
}
@Override
public boolean equalsRemote(IMarkerDelegate other) throws RemoteException {
return false;
return other != null && other.getId().equals(getId());
}
@Override
public int hashCodeRemote() throws RemoteException {
return 0;
return hashCode();
}
@Override
public void todo(IObjectWrapper obj) throws RemoteException {
public void setIcon(IObjectWrapper obj) throws RemoteException {
icon = new BitmapDescriptor(obj);
if (icon == null)
icon = new BitmapDescriptor(new ObjectWrapper<DefaultBitmapDescriptor>(new DefaultBitmapDescriptor(0)));
map.redraw();
}
@Override
public void setAnchor(float x, float y) throws RemoteException {
anchorU = x;
anchorV = y;
map.redraw();
}
@Override
public void setFlat(boolean flat) throws RemoteException {
map.redraw();
}
@Override
@ -132,12 +239,13 @@ public class MarkerImpl extends IMarkerDelegate.Stub {
@Override
public void setRotation(float rotation) throws RemoteException {
this.rotation = rotation;
map.redraw();
}
@Override
public float getRotation() throws RemoteException {
return 0;
return rotation;
}
@Override
@ -147,11 +255,16 @@ public class MarkerImpl extends IMarkerDelegate.Stub {
@Override
public void setAlpha(float alpha) throws RemoteException {
this.alpha = alpha;
map.redraw();
}
@Override
public float getAlpha() throws RemoteException {
return 0;
return alpha;
}
public Overlay getOverlay() {
return overlay;
}
}

View File

@ -129,7 +129,7 @@ public class PolygonImpl extends IPolygonDelegate.Stub {
@Override
public boolean equalsRemote(IPolygonDelegate other) throws RemoteException {
return other.getId().equals(getId());
return other != null && other.getId().equals(getId());
}
@Override

View File

@ -111,7 +111,7 @@ public class PolylineImpl extends IPolylineDelegate.Stub {
@Override
public boolean equalsRemote(IPolylineDelegate other) throws RemoteException {
return other.getId().equals(getId());
return other != null && other.getId().equals(getId());
}
@Override

View File

@ -16,8 +16,25 @@
package com.google.android.gms.maps.model.internal;
public class ResourceBitmapDescriptor {
public ResourceBitmapDescriptor(int resourceId) {
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.util.Log;
import com.google.android.gms.maps.internal.ResourcesContainer;
}
public class ResourceBitmapDescriptor extends AbstractBitmapDescriptor {
private static final String TAG = ResourceBitmapDescriptor.class.getName();
private int resourceId;
public ResourceBitmapDescriptor(int resourceId) {
this.resourceId = resourceId;
}
@Override
public Bitmap generateBitmap(Context context) {
return BitmapFactory.decodeResource(context.getResources(), resourceId);
}
}