Add InfoWindow support

This commit is contained in:
mar-v-in 2014-06-30 01:29:46 +02:00
parent 2751bdac1c
commit e77a08ece4
8 changed files with 345 additions and 67 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -1,4 +1,9 @@
package com.google.android.gms.maps.internal;
import com.google.android.gms.dynamic.IObjectWrapper;
import com.google.android.gms.maps.model.internal.IMarkerDelegate;
interface IInfoWindowAdapter {
IObjectWrapper getInfoWindow(IMarkerDelegate marker);
IObjectWrapper getInfoContents(IMarkerDelegate marker);
}

View File

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

View File

@ -25,7 +25,7 @@ import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import com.google.android.gms.dynamic.IObjectWrapper;
import com.google.android.gms.dynamic.ObjectWrapper;
import com.google.android.gms.maps.GoogleMapOptions;
@ -49,44 +49,104 @@ public class GoogleMapImpl {
private final ViewGroup view;
private final GoogleMapOptions options;
private final Delegate delegate = new Delegate();
private final UiSettings uiSettings = new UiSettings();
private final Projection projection = new Projection();
private MapView mapView;
private int mapType = 1;
private MapView mapView;
private Context context;
private InfoWindow infoWindow;
private int markerCounter = 0;
private IOnCameraChangeListener cameraChangeListener;
private IOnMapClickListener mapClickListener;
private IOnMapLoadedCallback mapLoadedCallback;
private IOnMapLongClickListener mapLongClickListener;
private IOnMarkerClickListener markerClickListener;
public GoogleMapImpl(LayoutInflater inflater, GoogleMapOptions options) {
private IOnMarkerDragListener markerDragListener;
private IOnInfoWindowClickListener infoWindowClickListener;
private int mapType = 1;
private IInfoWindowAdapter infoWindowAdapter;
public GoogleMapImpl(LayoutInflater inflater, GoogleMapOptions options) {
context = inflater.getContext();
this.view = new FrameLayout(context);
try {
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");
}
this.view = new RelativeLayout(context);
try {
mapView = (MapView) Class.forName("com.google.android.maps.MapView").getConstructor(Context.class, String.class).newInstance(context, null);
prepareMapView();
view.addView(mapView);
} catch (Exception e) {
Log.d(TAG, "Sorry, can't create legacy MapView");
}
this.options = options;
}
private void prepareMapView() {
mapView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick");
IOnMapClickListener listener = mapClickListener;
if (listener != null) {
try {
// TODO: Handle LatLng right
listener.onMapClick(new LatLng(0, 0));
} catch (RemoteException e) {
Log.w(TAG, e);
}
}
}
});
mapView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
Log.d(TAG, "onLongClick");
IOnMapLongClickListener listener = mapLongClickListener;
if (listener != null) {
try {
// TODO: Handle LatLng right
listener.onMapLongClick(new LatLng(0, 0));
} catch (RemoteException e) {
Log.w(TAG, e);
}
return true;
}
return false;
}
});
}
public void onCreate(Bundle savedInstanceState) {
try {
delegate.animateCamera(new CameraUpdateFactoryImpl().newCameraPosition(options.getCamera()));
delegate.setMapType(options.getMapType());
uiSettings.setCompassEnabled(options.isCompassEnabled());
uiSettings.setZoomControlsEnabled(options.isZoomControlsEnabled());
uiSettings.setRotateGesturesEnabled(options.isRotateGesturesEnabled());
uiSettings.setScrollGesturesEnabled(options.isScrollGesturesEnabled());
uiSettings.setTiltGesturesEnabled(options.isTiltGesturesEnabled());
uiSettings.setZoomGesturesEnabled(options.isZoomGesturesEnabled());
} catch (RemoteException ignored) {
// It's not remote...
if (options != null) {
try {
delegate.animateCamera(new CameraUpdateFactoryImpl().newCameraPosition(options.getCamera()));
delegate.setMapType(options.getMapType());
uiSettings.setCompassEnabled(options.isCompassEnabled());
uiSettings.setZoomControlsEnabled(options.isZoomControlsEnabled());
uiSettings.setRotateGesturesEnabled(options.isRotateGesturesEnabled());
uiSettings.setScrollGesturesEnabled(options.isScrollGesturesEnabled());
uiSettings.setTiltGesturesEnabled(options.isTiltGesturesEnabled());
uiSettings.setZoomGesturesEnabled(options.isZoomGesturesEnabled());
} catch (RemoteException ignored) {
// It's not remote...
}
}
}
if (savedInstanceState != null) {
savedInstanceState.setClassLoader(GoogleMapImpl.class.getClassLoader());
mapView.onRestoreInstanceState(savedInstanceState);
}
}
public IOnMarkerClickListener getMarkerClickListener() {
return markerClickListener;
}
public IOnInfoWindowClickListener getInfoWindowClickListener() {
return infoWindowClickListener;
}
public Context getContext() {
return context;
}
@ -108,8 +168,15 @@ public class GoogleMapImpl {
}
public void remove(MarkerImpl marker) {
mapView.getOverlays().remove(marker);
}
mapView.getOverlays().remove(marker.getOverlay());
try {
if (infoWindow != null && infoWindow.getMarker().getId().equals(marker.getId())) {
hideInfoWindow();
}
} catch (RemoteException e) {
// It's not remote...
}
}
public void redraw() {
mapView.postInvalidate();
@ -120,6 +187,49 @@ public class GoogleMapImpl {
}
}
public void onSaveInstanceState(Bundle outState) {
mapView.onSaveInstanceState(outState);
}
public void hideInfoWindow() {
if (infoWindow != null) {
mapView.getOverlays().remove(infoWindow);
infoWindow.destroy();
}
infoWindow = null;
}
public void showInfoWindow(final MarkerImpl marker) {
hideInfoWindow();
InfoWindow window = new InfoWindow(context, this, marker);
if (infoWindowAdapter != null) {
try {
IObjectWrapper infoWindow = infoWindowAdapter.getInfoWindow(marker);
window.setWindow((View) ObjectWrapper.unwrap(infoWindow));
} catch (RemoteException e) {
Log.w(TAG, e);
}
}
if (!window.isComplete()) {
if (infoWindowAdapter != null) {
try {
IObjectWrapper contents = infoWindowAdapter.getInfoContents(marker);
window.setContent((View) ObjectWrapper.unwrap(contents));
} catch (RemoteException e) {
Log.w(TAG, e);
}
}
}
if (!window.isComplete()) {
window.buildDefault();
}
if (window.isComplete()) {
infoWindow = window;
Log.d(TAG, "Showing info window " + infoWindow + " for marker " + marker);
mapView.getOverlays().add(infoWindow);
}
}
private class Delegate extends IGoogleMapDelegate.Stub {
@Override
public CameraPosition getCameraPosition() throws RemoteException {
@ -176,8 +286,10 @@ public class GoogleMapImpl {
@Override
public IMarkerDelegate addMarker(MarkerOptions options) throws RemoteException {
MarkerImpl marker = new MarkerImpl(options, GoogleMapImpl.this);
mapView.getOverlays().add(marker.getOverlay());
MarkerImpl marker = new MarkerImpl("m" + markerCounter++, options, GoogleMapImpl.this);
if (infoWindow != null) mapView.getOverlays().remove(infoWindow);
mapView.getOverlays().add(marker.getOverlay());
if (infoWindow != null) mapView.getOverlays().add(infoWindow);
redraw();
return marker;
}
@ -195,6 +307,7 @@ public class GoogleMapImpl {
@Override
public void clear() throws RemoteException {
mapView.getOverlays().clear();
hideInfoWindow();
redraw();
}
@ -265,38 +378,18 @@ public class GoogleMapImpl {
@Override
public void setOnCameraChangeListener(IOnCameraChangeListener listener) throws RemoteException {
}
cameraChangeListener = listener;
}
@Override
public void setOnMapClickListener(final IOnMapClickListener listener) throws RemoteException {
mapView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
Log.d(TAG, "onMapClick:");
listener.onMapClick(new LatLng(0, 0));
} catch (RemoteException ignored) {
}
}
});
}
mapClickListener = listener;
}
@Override
public void setOnMapLongClickListener(final IOnMapLongClickListener listener) throws RemoteException {
mapView.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
try {
Log.d(TAG, "onMapLongClick:");
listener.onMapLongClick(new LatLng(0, 0));
} catch (RemoteException e) {
return false;
}
return true;
}
});
}
mapLongClickListener = listener;
}
@Override
public void setOnMarkerClickListener(IOnMarkerClickListener listener) throws RemoteException {
@ -305,18 +398,18 @@ public class GoogleMapImpl {
@Override
public void setOnMarkerDragListener(IOnMarkerDragListener listener) throws RemoteException {
}
markerDragListener = listener;
}
@Override
public void setOnInfoWindowClickListener(IOnInfoWindowClickListener listener) throws RemoteException {
}
infoWindowClickListener = listener;
}
@Override
public void setInfoWindowAdapter(IInfoWindowAdapter adapter) throws RemoteException {
}
infoWindowAdapter = adapter;
}
@Override
public IObjectWrapper getTestingHelper() throws RemoteException {
@ -360,9 +453,9 @@ public class GoogleMapImpl {
@Override
public void setOnMapLoadedCallback(IOnMapLoadedCallback callback) throws RemoteException {
}
}
mapLoadedCallback = callback;
}
}
private class UiSettings extends IUiSettingsDelegate.Stub {

View File

@ -104,7 +104,7 @@ public class MapFragmentImpl extends IMapFragmentDelegate.Stub {
@Override
public void onSaveInstanceState(Bundle outState) throws RemoteException {
myMap().onSaveInstanceState(outState);
}
@Override

View File

@ -100,6 +100,14 @@ public class CameraUpdateFactoryImpl extends ICameraUpdateFactoryDelegate.Stub {
@Override
public IObjectWrapper newCameraPosition(final CameraPosition cameraPosition) throws RemoteException {
Log.d(TAG, "newCameraPosition");
if (cameraPosition == null) {
return new ObjectWrapper<CameraUpdate>(new CameraUpdate() {
@Override
public void update(GoogleMapImpl map) {
// Nothing
}
});
}
return newLatLngZoom(cameraPosition.target, cameraPosition.zoom);
}

View File

@ -0,0 +1,161 @@
/*
* 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 org.microg.gms.maps.markup;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.google.android.gms.R;
import com.google.android.gms.maps.internal.IOnInfoWindowClickListener;
import com.google.android.gms.maps.model.internal.IMarkerDelegate;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import org.microg.gms.maps.GoogleMapImpl;
import org.microg.gms.maps.ResourcesContainer;
public class InfoWindow extends Overlay {
private static final String TAG = InfoWindow.class.getName();
private Context context;
private View window;
private GoogleMapImpl map;
private MarkerImpl marker;
public InfoWindow(Context context, final GoogleMapImpl map, final MarkerImpl marker) {
super();
this.context = context;
this.map = map;
this.marker = marker;
}
public void setWindow(View view) {
window = view;
if (window != null) {
window.measure(0, 0);
}
}
public boolean isComplete() {
return window != null;
}
public void setContent(View view) {
if (view == null) return;
setWindow(new DefaultWindow(view));
}
public void buildDefault() {
try {
if (marker.getTitle() != null)
setContent(new DefaultContent());
} catch (RemoteException e) {
// Not remote...
}
}
public void destroy() {
if (window instanceof DefaultWindow) {
((DefaultWindow) window).removeAllViews();
}
}
public IMarkerDelegate getMarker() {
return marker;
}
@Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
if (window != null && marker.getHeight() != -1) {
try {
Point zero = mapView.getProjection().toPixels(new GeoPoint(0, 0), null);
Point point = mapView.getProjection().toPixels(marker.getPosition().toGeoPoint(), null);
point.offset(-zero.x, -zero.y);
point.offset(-window.getMeasuredWidth() / 2, -window.getMeasuredHeight() - marker.getHeight());
Log.d(TAG, point.toString());
window.layout(0, 0, window.getMeasuredWidth(), window.getMeasuredHeight());
canvas.save();
canvas.translate(point.x, point.y);
window.draw(canvas);
canvas.restore();
} catch (RemoteException e) {
// This is not remote...
}
}
}
@Override
public boolean onTap(GeoPoint p, MapView mapView) {
try {
IOnInfoWindowClickListener listener = map.getInfoWindowClickListener();
if (listener != null) {
Point clickPoint = mapView.getProjection().toPixels(p, null);
Point markerPoint = mapView.getProjection().toPixels(marker.getPosition().toGeoPoint(), null);
Rect rect = new Rect(markerPoint.x - (window.getMeasuredWidth() / 2),
markerPoint.y - marker.getHeight() - window.getMeasuredHeight(),
markerPoint.x + (window.getMeasuredWidth() / 2),
markerPoint.y - marker.getHeight());
if (rect.contains(clickPoint.x, clickPoint.y)) {
try {
listener.onInfoWindowClick(marker);
} catch (RemoteException e) {
Log.w(TAG, e);
}
return true;
}
}
} catch (RemoteException e) {
// This is not remote...
}
return false;
}
private class DefaultWindow extends FrameLayout {
public DefaultWindow(View view) {
super(context);
addView(view);
setBackground(ResourcesContainer.get().getDrawable(R.drawable.maps_default_window));
}
}
private class DefaultContent extends LinearLayout {
public DefaultContent() {
super(context);
setOrientation(LinearLayout.VERTICAL);
try {
TextView title = new TextView(context);
title.setTextAppearance(context, android.R.style.TextAppearance_DeviceDefault_Medium_Inverse);
title.setText(marker.getTitle());
addView(title);
if (marker.getSnippet() != null) {
TextView snippet = new TextView(context);
snippet.setTextAppearance(context, android.R.style.TextAppearance_DeviceDefault_Inverse);
snippet.setText(marker.getSnippet());
addView(snippet);
}
} catch (RemoteException e) {
// ...
}
}
}
}

View File

@ -35,10 +35,11 @@ import org.microg.gms.maps.GoogleMapImpl;
public class MarkerImpl extends IMarkerDelegate.Stub {
private static final String TAG = MarkerImpl.class.getName();
private final String id;
private float alpha;
private boolean flat;
private boolean draggable;
private String id = Integer.toHexString(hashCode());
private LatLng position;
private float anchorU;
private float anchorV;
@ -74,7 +75,7 @@ public class MarkerImpl extends IMarkerDelegate.Stub {
}
if (!result) {
mapView.getController().animateTo(position.toGeoPoint());
// TODO info window
map.showInfoWindow(MarkerImpl.this);
}
return true;
}
@ -109,7 +110,8 @@ public class MarkerImpl extends IMarkerDelegate.Stub {
}
};
public MarkerImpl(MarkerOptions options, GoogleMapImpl map) {
public MarkerImpl(String id, MarkerOptions options, GoogleMapImpl map) {
this.id = id;
this.map = map;
this.alpha = options.getAlpha();
this.draggable = options.isDraggable();
@ -124,7 +126,7 @@ public class MarkerImpl extends IMarkerDelegate.Stub {
this.icon = options.getIcon();
if (icon == null)
icon = new BitmapDescriptor(new ObjectWrapper<DefaultBitmapDescriptor>(new DefaultBitmapDescriptor(0)));
Log.d(TAG, "New: " + title + " @ " + position + ", " + icon);
Log.d(TAG, "New: " + id + " with title " + title + " @ " + position);
}
@Override
@ -267,4 +269,10 @@ public class MarkerImpl extends IMarkerDelegate.Stub {
public Overlay getOverlay() {
return overlay;
}
public int getHeight() {
Bitmap bitmap = icon.getBitmap();
if (bitmap == null) return -1;
return bitmap.getHeight();
}
}