Add support for map tapping (#985)

diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java
index 34551e9..db430fe 100644
--- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java
+++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java
@@ -127,7 +127,7 @@
     return data;
   }
 
-  private static Object toJson(LatLng latLng) {
+  static Object toJson(LatLng latLng) {
     return Arrays.asList(latLng.latitude, latLng.longitude);
   }
 
diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java
index 63f3cb2..20a19cd 100644
--- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java
+++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java
@@ -26,6 +26,7 @@
 import com.google.android.gms.maps.MapView;
 import com.google.android.gms.maps.OnMapReadyCallback;
 import com.google.android.gms.maps.model.CameraPosition;
+import com.google.android.gms.maps.model.LatLng;
 import com.google.android.gms.maps.model.LatLngBounds;
 import com.google.android.gms.maps.model.Marker;
 import io.flutter.plugin.common.MethodCall;
@@ -50,6 +51,7 @@
         GoogleMapOptionsSink,
         MethodChannel.MethodCallHandler,
         OnMapReadyCallback,
+        GoogleMap.OnMapClickListener,
         PlatformView {
 
   private static final String TAG = "GoogleMapController";
@@ -155,6 +157,7 @@
     googleMap.setOnCameraMoveListener(this);
     googleMap.setOnCameraIdleListener(this);
     googleMap.setOnMarkerClickListener(this);
+    googleMap.setOnMapClickListener(this);
     updateMyLocationEnabled();
     markersController.setGoogleMap(googleMap);
     updateInitialMarkers();
@@ -242,6 +245,13 @@
   }
 
   @Override
+  public void onMapClick(LatLng latLng) {
+    final Map<String, Object> arguments = new HashMap<>(2);
+    arguments.put("position", Convert.toJson(latLng));
+    methodChannel.invokeMethod("map#onTap", arguments);
+  }
+
+  @Override
   public void onCameraMoveStarted(int reason) {
     final Map<String, Object> arguments = new HashMap<>(2);
     boolean isGesture = reason == GoogleMap.OnCameraMoveStartedListener.REASON_GESTURE;
diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/ios/Classes/GoogleMapController.m
index c5de740..788ba6a 100644
--- a/packages/google_maps_flutter/ios/Classes/GoogleMapController.m
+++ b/packages/google_maps_flutter/ios/Classes/GoogleMapController.m
@@ -8,6 +8,7 @@
 #pragma mark - Conversion of JSON-like values sent via platform channels. Forward declarations.
 
 static NSDictionary* PositionToJson(GMSCameraPosition* position);
+static NSArray* LocationToJson(CLLocationCoordinate2D position);
 static GMSCameraPosition* ToOptionalCameraPosition(NSDictionary* json);
 static GMSCoordinateBounds* ToOptionalBounds(NSArray* json);
 static GMSCameraUpdate* ToCameraUpdate(NSArray* data);
@@ -257,6 +258,10 @@
   [_markersController onInfoWindowTap:markerId];
 }
 
+- (void)mapView:(GMSMapView*)mapView didTapAtCoordinate:(CLLocationCoordinate2D)coordinate {
+  [_channel invokeMethod:@"map#onTap" arguments:@{@"position" : LocationToJson(coordinate)}];
+}
+
 @end
 
 #pragma mark - Implementations of JSON conversion functions.
diff --git a/packages/google_maps_flutter/lib/src/controller.dart b/packages/google_maps_flutter/lib/src/controller.dart
index bb8b488..c16c838 100644
--- a/packages/google_maps_flutter/lib/src/controller.dart
+++ b/packages/google_maps_flutter/lib/src/controller.dart
@@ -63,6 +63,9 @@
       case 'infoWindow#onTap':
         _googleMapState.onInfoWindowTap(call.arguments['markerId']);
         break;
+      case 'map#onTap':
+        _googleMapState.onTap(LatLng._fromJson(call.arguments['position']));
+        break;
       default:
         throw MissingPluginException();
     }
diff --git a/packages/google_maps_flutter/lib/src/google_map.dart b/packages/google_maps_flutter/lib/src/google_map.dart
index 794935c..a75424b 100644
--- a/packages/google_maps_flutter/lib/src/google_map.dart
+++ b/packages/google_maps_flutter/lib/src/google_map.dart
@@ -33,6 +33,7 @@
     this.onCameraMoveStarted,
     this.onCameraMove,
     this.onCameraIdle,
+    this.onTap,
   })  : assert(initialCameraPosition != null),
         super(key: key);
 
@@ -91,6 +92,9 @@
   /// animations and the user has stopped interacting with the map.
   final VoidCallback onCameraIdle;
 
+  /// Called every time a [GoogleMap] is tapped.
+  final ArgumentCallback<LatLng> onTap;
+
   /// True if a "My Location" layer should be shown on the map.
   ///
   /// This layer includes a location indicator at the current device location,
@@ -223,6 +227,11 @@
     final MarkerId markerId = MarkerId(markerIdParam);
     _markers[markerId].infoWindow.onTap();
   }
+
+  void onTap(LatLng position) {
+    assert(position != null);
+    widget.onTap(position);
+  }
 }
 
 /// Configuration options for the GoogleMaps user interface.