diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Annotation.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Annotation.java
index 4f172c6e2..c4dea205e 100644
--- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Annotation.java
+++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Annotation.java
@@ -2,7 +2,6 @@ package com.mapbox.mapboxgl.annotations;
import com.mapbox.mapboxgl.views.MapView;
-
public abstract class Annotation {
/**
@@ -11,7 +10,7 @@ public abstract class Annotation {
* Internal C++ id is stored as unsigned int.
*/
protected long id = -1; // -1 unless added to a MapView
- private MapView mapView;
+ protected MapView mapView;
float alpha = 1.0f;
boolean visible = true;
diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/InfoWindow.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/InfoWindow.java
new file mode 100644
index 000000000..924012db5
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/InfoWindow.java
@@ -0,0 +1,189 @@
+package com.mapbox.mapboxgl.annotations;
+
+import android.content.Context;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+import com.mapbox.mapboxgl.geometry.LatLng;
+import com.mapbox.mapboxgl.views.MapView;
+
+/**
+ * A tooltip view
+ */
+public class InfoWindow {
+
+ private Marker boundMarker;
+ private MapView mMapView;
+ private boolean mIsVisible;
+ protected View mView;
+
+ static int mTitleId = 0;
+ static int mDescriptionId = 0;
+ static int mSubDescriptionId = 0;
+ static int mImageId = 0;
+
+ public InfoWindow(int layoutResId, MapView mapView) {
+ mMapView = mapView;
+ mIsVisible = false;
+ ViewGroup parent = (ViewGroup) mapView.getParent();
+ Context context = mapView.getContext();
+ LayoutInflater inflater =
+ (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mView = inflater.inflate(layoutResId, parent, false);
+
+ if (mTitleId == 0) {
+ setResIds(mapView.getContext());
+ }
+
+ // default behavior: close it when clicking on the tooltip:
+ setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent e) {
+ if (e.getAction() == MotionEvent.ACTION_UP) {
+ close();
+ }
+ return true;
+ }
+ });
+ }
+
+ public InfoWindow(View view, MapView mapView) {
+ mMapView = mapView;
+ mIsVisible = false;
+ ViewGroup parent = (ViewGroup) mapView.getParent();
+ Context context = mapView.getContext();
+ LayoutInflater inflater =
+ (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mView = view;
+
+ // default behavior: close it when clicking on the tooltip:
+ setOnTouchListener(new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent e) {
+ if (e.getAction() == MotionEvent.ACTION_UP) {
+ close();
+ }
+ return true;
+ }
+ });
+ }
+
+ /**
+ * open the window at the specified position.
+ *
+ * @param object the graphical object on which is hooked the view
+ * @param position to place the window on the map
+ * @param offsetX (&offsetY) the offset of the view to the position, in pixels.
+ * This allows to offset the view from the object position.
+ * @return this infowindow
+ */
+ public InfoWindow open(Marker object, LatLng position, int offsetX, int offsetY) {
+ onOpen(object);
+ MapView.LayoutParams lp = new MapView.LayoutParams(MapView.LayoutParams.WRAP_CONTENT,
+ MapView.LayoutParams.WRAP_CONTENT, Gravity.CENTER|Gravity.BOTTOM);
+ close(); //if it was already opened
+ mMapView.addView(mView, lp);
+ mIsVisible = true;
+ return this;
+ }
+
+ /**
+ * Close this InfoWindow if it is visible, otherwise don't do anything.
+ *
+ * @return this info window
+ */
+ public InfoWindow close() {
+ if (mIsVisible) {
+ mIsVisible = false;
+ ((ViewGroup) mView.getParent()).removeView(mView);
+// this.boundMarker.blur();
+ setBoundMarker(null);
+ onClose();
+ }
+ return this;
+ }
+
+ /**
+ * Returns the Android view. This allows to set its content.
+ *
+ * @return the Android view
+ */
+ public View getView() {
+ return mView;
+ }
+
+ /**
+ * Returns the mapView this InfoWindow is bound to
+ *
+ * @return the mapView
+ */
+ public MapView getMapView() {
+ return mMapView;
+ }
+
+ /**
+ * Constructs the view that is displayed when the InfoWindow opens.
+ * This retrieves data from overlayItem and shows it in the tooltip.
+ *
+ * @param overlayItem the tapped overlay item
+ */
+ public void onOpen(Marker overlayItem) {
+ String title = overlayItem.getTitle();
+ ((TextView) mView.findViewById(mTitleId /*R.id.title*/)).setText(title);
+ String snippet = overlayItem.getSnippet();
+ ((TextView) mView.findViewById(mDescriptionId /*R.id.description*/)).setText(snippet);
+
+/*
+ //handle sub-description, hiding or showing the text view:
+ TextView subDescText = (TextView) mView.findViewById(mSubDescriptionId);
+ String subDesc = overlayItem.getSubDescription();
+ if ("".equals(subDesc)) {
+ subDescText.setVisibility(View.GONE);
+ } else {
+ subDescText.setText(subDesc);
+ subDescText.setVisibility(View.VISIBLE);
+ }
+*/
+ }
+
+ public void onClose() {
+ //by default, do nothing
+ }
+
+ public InfoWindow setBoundMarker(Marker aBoundMarker) {
+ this.boundMarker = aBoundMarker;
+ return this;
+ }
+
+ public Marker getBoundMarker() {
+ return boundMarker;
+ }
+
+ /**
+ * Given a context, set the resource ids for the layout
+ * of the InfoWindow.
+ *
+ * @param context
+ */
+ private static void setResIds(Context context) {
+ String packageName = context.getPackageName(); //get application package name
+ mTitleId = context.getResources().getIdentifier("id/infowindow_title", null, packageName);
+ mDescriptionId =
+ context.getResources().getIdentifier("id/infowindow_description", null, packageName);
+ mSubDescriptionId = context.getResources()
+ .getIdentifier("id/infowindow_subdescription", null, packageName);
+ mImageId = context.getResources().getIdentifier("id/infowindow_image", null, packageName);
+ }
+
+ /**
+ * Use to override default touch events handling on InfoWindow (ie, close automatically)
+ *
+ * @param listener New View.OnTouchListener to use
+ */
+ public void setOnTouchListener(View.OnTouchListener listener) {
+ mView.setOnTouchListener(listener);
+ }
+}
diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/InfoWindowTipView.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/InfoWindowTipView.java
new file mode 100644
index 000000000..657e63a84
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/InfoWindowTipView.java
@@ -0,0 +1,40 @@
+package com.mapbox.mapboxgl.annotations;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.util.AttributeSet;
+import android.view.View;
+
+public class InfoWindowTipView extends View {
+
+ private Paint mPaint;
+ private Path mPath;
+
+ public InfoWindowTipView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ mPath = new Path();
+
+ this.mPaint = new Paint();
+ this.mPaint.setColor(Color.WHITE);
+ this.mPaint.setAntiAlias(true);
+ this.mPaint.setStrokeWidth(0.0f);
+ this.mPaint.setStyle(Paint.Style.FILL);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ int height = getMeasuredHeight();
+ int width = getMeasuredWidth();
+
+ mPath.rewind();
+ mPath.moveTo((width / 2) - height, 0);
+ mPath.lineTo((width / 2) + height, 0);
+ mPath.lineTo((width / 2), height);
+ mPath.lineTo((width / 2) - height, 0);
+ canvas.drawPath(mPath, this.mPaint);
+ }
+}
diff --git a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Marker.java b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Marker.java
index 515852ae6..4776c37bf 100644
--- a/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Marker.java
+++ b/android/java/MapboxGLAndroidSDK/src/main/java/com/mapbox/mapboxgl/annotations/Marker.java
@@ -1,7 +1,8 @@
package com.mapbox.mapboxgl.annotations;
+import android.graphics.Point;
import com.mapbox.mapboxgl.geometry.LatLng;
-
+import com.mapbox.mapboxgl.views.R;
public class Marker extends Annotation {
@@ -16,10 +17,16 @@ public class Marker extends Annotation {
String snippet;
String sprite = "default_marker";
String title;
+ private InfoWindow infoWindow = null;
private boolean infoWindowShown = false;
- public Marker() {}
+ /**
+ * Constructor
+ */
+ public Marker() {
+ super();
+ }
/**
* If two markers have the same LatLng, they are equal.
@@ -41,6 +48,10 @@ public class Marker extends Annotation {
return alpha;
}
+ public Point getAnchor() {
+ return new Point((int)anchorU, (int)anchorV);
+ }
+
public float getAnchorU() {
return anchorU;
}
@@ -66,7 +77,7 @@ public class Marker extends Annotation {
}
public void hideInfoWindow() {
- //TODO hideInfoWindow
+ infoWindow.close();
infoWindowShown = false;
}
@@ -82,33 +93,33 @@ public class Marker extends Annotation {
return infoWindowShown;
}
- void setAnchor(float u, float v) {
+ public void setAnchor(float u, float v) {
this.anchorU = u;
this.anchorV = v;
}
- void setDraggable(boolean draggable) {
+ public void setDraggable(boolean draggable) {
this.draggable = draggable;
}
- void setFlat(boolean flat) {
+ public void setFlat(boolean flat) {
this.flat = flat;
}
- void setInfoWindowAnchor(float u, float v) {
+ public void setInfoWindowAnchor(float u, float v) {
infoWindowAnchorU = u;
infoWindowAnchorV = v;
}
- void setPosition(LatLng latlng) {
+ public void setPosition(LatLng latlng) {
this.position = position;
}
- void setRotation(float rotation) {
+ public void setRotation(float rotation) {
this.rotation = rotation;
}
- void setSnippet(String snippet) {
+ public void setSnippet(String snippet) {
this.snippet = snippet;
}
@@ -120,18 +131,36 @@ public class Marker extends Annotation {
*
* @param sprite
*/
- void setSprite(String sprite) {
+ public void setSprite(String sprite) {
this.sprite = sprite;
}
- void setTitle(String title) {
+ public void setTitle(String title) {
this.title = title;
}
- void showInfoWindow() {
+ public void showInfoWindow() {
+
+ if (!isVisible() || mapView == null) {
+ return;
+ }
+
+ if (infoWindow == null) {
+ infoWindow = new InfoWindow(R.layout.infowindow, mapView);
+ }
+
+ infoWindow.open(this, getPosition(), (int)anchorU, (int)anchorV);
+ infoWindow.setBoundMarker(this);
infoWindowShown = true;
}
+ @Override
+ public void setVisible(boolean visible) {
+ super.setVisible(visible);
+ if (!visible && infoWindowShown) {
+ hideInfoWindow();
+ }
+ }
// TODO Method in Google Maps Android API
// public int hashCode()
diff --git a/android/java/MapboxGLAndroidSDK/src/main/res/layout/infowindow.xml b/android/java/MapboxGLAndroidSDK/src/main/res/layout/infowindow.xml
new file mode 100644
index 000000000..af05e2fd4
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDK/src/main/res/layout/infowindow.xml
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/android/java/MapboxGLAndroidSDK/src/main/res/values/colors.xml b/android/java/MapboxGLAndroidSDK/src/main/res/values/colors.xml
new file mode 100644
index 000000000..bf3f48431
--- /dev/null
+++ b/android/java/MapboxGLAndroidSDK/src/main/res/values/colors.xml
@@ -0,0 +1,5 @@
+
+
+ #FFFFFF
+ #000000
+
diff --git a/android/java/MapboxGLAndroidSDK/src/main/res/values/strings.xml b/android/java/MapboxGLAndroidSDK/src/main/res/values/strings.xml
index df022a467..ff91a160d 100644
--- a/android/java/MapboxGLAndroidSDK/src/main/res/values/strings.xml
+++ b/android/java/MapboxGLAndroidSDK/src/main/res/values/strings.xml
@@ -1,4 +1,7 @@
Map compass. Click to reset the map rotation to North.
+ Title
+ Description
+ Address