[google_maps_flutter] Adds support for buildingsEnabled property (#2264)

diff --git a/packages/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/CHANGELOG.md
index 18becc1..d68693b 100644
--- a/packages/google_maps_flutter/CHANGELOG.md
+++ b/packages/google_maps_flutter/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.5.21+14
+
+* Adds support for toggling 3D buildings.
+
 ## 0.5.21+13
 
 * Add documentation.
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 6ca3f1f..c8429f7 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
@@ -332,6 +332,10 @@
     if (trafficEnabled != null) {
       sink.setTrafficEnabled(toBoolean(trafficEnabled));
     }
+    final Object buildingsEnabled = data.get("buildingsEnabled");
+    if (buildingsEnabled != null) {
+      sink.setBuildingsEnabled(toBoolean(buildingsEnabled));
+    }
   }
 
   /** Returns the dartMarkerId of the interpreted marker. */
diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java
index 651dd3e..e78908d 100644
--- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java
+++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java
@@ -19,6 +19,7 @@
   private boolean myLocationButtonEnabled = false;
   private boolean indoorEnabled = true;
   private boolean trafficEnabled = false;
+  private boolean buildingsEnabled = true;
   private Object initialMarkers;
   private Object initialPolygons;
   private Object initialPolylines;
@@ -34,6 +35,7 @@
     controller.setMyLocationButtonEnabled(myLocationButtonEnabled);
     controller.setIndoorEnabled(indoorEnabled);
     controller.setTrafficEnabled(trafficEnabled);
+    controller.setBuildingsEnabled(buildingsEnabled);
     controller.setTrackCameraPosition(trackCameraPosition);
     controller.setInitialMarkers(initialMarkers);
     controller.setInitialPolygons(initialPolygons);
@@ -118,6 +120,11 @@
   }
 
   @Override
+  public void setBuildingsEnabled(boolean buildingsEnabled) {
+    this.buildingsEnabled = buildingsEnabled;
+  }
+
+  @Override
   public void setMyLocationEnabled(boolean myLocationEnabled) {
     this.myLocationEnabled = myLocationEnabled;
   }
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 1c70909..5c7d094 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
@@ -76,6 +76,7 @@
   private boolean myLocationButtonEnabled = false;
   private boolean indoorEnabled = true;
   private boolean trafficEnabled = false;
+  private boolean buildingsEnabled = true;
   private boolean disposed = false;
   private final float density;
   private MethodChannel.Result mapReadyResult;
@@ -172,6 +173,7 @@
     this.googleMap = googleMap;
     this.googleMap.setIndoorEnabled(this.indoorEnabled);
     this.googleMap.setTrafficEnabled(this.trafficEnabled);
+    this.googleMap.setBuildingsEnabled(this.buildingsEnabled);
     googleMap.setOnInfoWindowClickListener(this);
     if (mapReadyResult != null) {
       mapReadyResult.success(null);
@@ -361,6 +363,11 @@
           result.success(googleMap.isTrafficEnabled());
           break;
         }
+      case "map#isBuildingsEnabled":
+        {
+          result.success(googleMap.isBuildingsEnabled());
+          break;
+        }
       case "map#setStyle":
         {
           String mapStyle = (String) call.arguments;
@@ -716,4 +723,8 @@
   public void setTrafficEnabled(boolean trafficEnabled) {
     this.trafficEnabled = trafficEnabled;
   }
+
+  public void setBuildingsEnabled(boolean buildingsEnabled) {
+    this.buildingsEnabled = buildingsEnabled;
+  }
 }
diff --git a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java
index 1f01298..fb88b36 100644
--- a/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java
+++ b/packages/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java
@@ -38,6 +38,8 @@
 
   void setTrafficEnabled(boolean trafficEnabled);
 
+  void setBuildingsEnabled(boolean buildingsEnabled);
+
   void setInitialMarkers(Object initialMarkers);
 
   void setInitialPolygons(Object initialPolygons);
diff --git a/packages/google_maps_flutter/example/test_driver/google_map_inspector.dart b/packages/google_maps_flutter/example/test_driver/google_map_inspector.dart
index 157076b..ab0f82a 100644
--- a/packages/google_maps_flutter/example/test_driver/google_map_inspector.dart
+++ b/packages/google_maps_flutter/example/test_driver/google_map_inspector.dart
@@ -53,4 +53,8 @@
   Future<bool> isTrafficEnabled() async {
     return await _channel.invokeMethod<bool>('map#isTrafficEnabled');
   }
+
+  Future<bool> isBuildingsEnabled() async {
+    return await _channel.invokeMethod<bool>('map#isBuildingsEnabled');
+  }
 }
diff --git a/packages/google_maps_flutter/example/test_driver/google_maps_e2e.dart b/packages/google_maps_flutter/example/test_driver/google_maps_e2e.dart
index 53d0c90..0c1f33c 100644
--- a/packages/google_maps_flutter/example/test_driver/google_maps_e2e.dart
+++ b/packages/google_maps_flutter/example/test_driver/google_maps_e2e.dart
@@ -401,6 +401,31 @@
     expect(isTrafficEnabled, true);
   });
 
+  testWidgets('testBuildings', (WidgetTester tester) async {
+    final Key key = GlobalKey();
+    final Completer<GoogleMapInspector> inspectorCompleter =
+        Completer<GoogleMapInspector>();
+
+    await tester.pumpWidget(Directionality(
+      textDirection: TextDirection.ltr,
+      child: GoogleMap(
+        key: key,
+        initialCameraPosition: _kInitialCameraPosition,
+        buildingsEnabled: true,
+        onMapCreated: (GoogleMapController controller) {
+          final GoogleMapInspector inspector =
+              // ignore: invalid_use_of_visible_for_testing_member
+              GoogleMapInspector(controller.channel);
+          inspectorCompleter.complete(inspector);
+        },
+      ),
+    ));
+
+    final GoogleMapInspector inspector = await inspectorCompleter.future;
+    final bool isBuildingsEnabled = await inspector.isBuildingsEnabled();
+    expect(isBuildingsEnabled, true);
+  });
+
   testWidgets('testMyLocationButtonToggle', (WidgetTester tester) async {
     final Key key = GlobalKey();
     final Completer<GoogleMapInspector> inspectorCompleter =
diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapController.h b/packages/google_maps_flutter/ios/Classes/GoogleMapController.h
index a94a248..1bc8536 100644
--- a/packages/google_maps_flutter/ios/Classes/GoogleMapController.h
+++ b/packages/google_maps_flutter/ios/Classes/GoogleMapController.h
@@ -17,6 +17,7 @@
 - (void)setCompassEnabled:(BOOL)enabled;
 - (void)setIndoorEnabled:(BOOL)enabled;
 - (void)setTrafficEnabled:(BOOL)enabled;
+- (void)setBuildingsEnabled:(BOOL)enabled;
 - (void)setMapType:(GMSMapViewType)type;
 - (void)setMinZoom:(float)minZoom maxZoom:(float)maxZoom;
 - (void)setPaddingTop:(float)top left:(float)left bottom:(float)bottom right:(float)right;
diff --git a/packages/google_maps_flutter/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/ios/Classes/GoogleMapController.m
index ce85887..da20706 100644
--- a/packages/google_maps_flutter/ios/Classes/GoogleMapController.m
+++ b/packages/google_maps_flutter/ios/Classes/GoogleMapController.m
@@ -254,6 +254,9 @@
   } else if ([call.method isEqualToString:@"map#isTrafficEnabled"]) {
     NSNumber* isTrafficEnabled = @(_mapView.trafficEnabled);
     result(isTrafficEnabled);
+  } else if ([call.method isEqualToString:@"map#isBuildingsEnabled"]) {
+    NSNumber* isBuildingsEnabled = @(_mapView.buildingsEnabled);
+    result(isBuildingsEnabled);
   } else if ([call.method isEqualToString:@"map#setStyle"]) {
     NSString* mapStyle = [call arguments];
     NSString* error = [self setMapStyle:mapStyle];
@@ -315,6 +318,10 @@
   _mapView.trafficEnabled = enabled;
 }
 
+- (void)setBuildingsEnabled:(BOOL)enabled {
+  _mapView.buildingsEnabled = enabled;
+}
+
 - (void)setMapType:(GMSMapViewType)mapType {
   _mapView.mapType = mapType;
 }
@@ -554,6 +561,10 @@
   if (trafficEnabled) {
     [sink setTrafficEnabled:ToBool(trafficEnabled)];
   }
+  id buildingsEnabled = data[@"buildingsEnabled"];
+  if (buildingsEnabled) {
+    [sink setBuildingsEnabled:ToBool(buildingsEnabled)];
+  }
   id mapType = data[@"mapType"];
   if (mapType) {
     [sink setMapType:ToMapViewType(mapType)];
diff --git a/packages/google_maps_flutter/lib/src/google_map.dart b/packages/google_maps_flutter/lib/src/google_map.dart
index d1f85a0..f6a413a 100644
--- a/packages/google_maps_flutter/lib/src/google_map.dart
+++ b/packages/google_maps_flutter/lib/src/google_map.dart
@@ -44,6 +44,7 @@
     this.padding = const EdgeInsets.all(0),
     this.indoorViewEnabled = false,
     this.trafficEnabled = false,
+    this.buildingsEnabled = true,
     this.markers,
     this.polygons,
     this.polylines,
@@ -179,6 +180,9 @@
   /// Enables or disables the traffic layer of the map
   final bool trafficEnabled;
 
+  /// Enables or disables showing 3D buildings where available
+  final bool buildingsEnabled;
+
   /// Which gestures should be consumed by the map.
   ///
   /// It is possible for other gesture recognizers to be competing with the map on pointer
@@ -394,6 +398,7 @@
     this.padding,
     this.indoorViewEnabled,
     this.trafficEnabled,
+    this.buildingsEnabled,
   });
 
   static _GoogleMapOptions fromWidget(GoogleMap map) {
@@ -413,6 +418,7 @@
       padding: map.padding,
       indoorViewEnabled: map.indoorViewEnabled,
       trafficEnabled: map.trafficEnabled,
+      buildingsEnabled: map.buildingsEnabled,
     );
   }
 
@@ -446,6 +452,8 @@
 
   final bool trafficEnabled;
 
+  final bool buildingsEnabled;
+
   Map<String, dynamic> toMap() {
     final Map<String, dynamic> optionsMap = <String, dynamic>{};
 
@@ -475,6 +483,7 @@
     ]);
     addIfNonNull('indoorEnabled', indoorViewEnabled);
     addIfNonNull('trafficEnabled', trafficEnabled);
+    addIfNonNull('buildingsEnabled', buildingsEnabled);
     return optionsMap;
   }
 
diff --git a/packages/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/pubspec.yaml
index 1a95ba6..caab61f 100644
--- a/packages/google_maps_flutter/pubspec.yaml
+++ b/packages/google_maps_flutter/pubspec.yaml
@@ -2,7 +2,7 @@
 description: A Flutter plugin for integrating Google Maps in iOS and Android applications.
 author: Flutter Team <flutter-dev@googlegroups.com>
 homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter
-version: 0.5.21+13
+version: 0.5.21+14
 
 dependencies:
   flutter:
diff --git a/packages/google_maps_flutter/test/fake_maps_controllers.dart b/packages/google_maps_flutter/test/fake_maps_controllers.dart
index b92b841..57b70c4 100644
--- a/packages/google_maps_flutter/test/fake_maps_controllers.dart
+++ b/packages/google_maps_flutter/test/fake_maps_controllers.dart
@@ -49,6 +49,8 @@
 
   bool trafficEnabled;
 
+  bool buildingsEnabled;
+
   bool myLocationButtonEnabled;
 
   List<dynamic> padding;
@@ -358,6 +360,9 @@
     if (options.containsKey('trafficEnabled')) {
       trafficEnabled = options['trafficEnabled'];
     }
+    if (options.containsKey('buildingsEnabled')) {
+      buildingsEnabled = options['buildingsEnabled'];
+    }
     if (options.containsKey('padding')) {
       padding = options['padding'];
     }
diff --git a/packages/google_maps_flutter/test/google_map_test.dart b/packages/google_maps_flutter/test/google_map_test.dart
index e14c70c..5d77ccf 100644
--- a/packages/google_maps_flutter/test/google_map_test.dart
+++ b/packages/google_maps_flutter/test/google_map_test.dart
@@ -529,4 +529,33 @@
 
     expect(platformGoogleMap.trafficEnabled, true);
   });
+
+  testWidgets('Can update buildings', (WidgetTester tester) async {
+    await tester.pumpWidget(
+      const Directionality(
+        textDirection: TextDirection.ltr,
+        child: GoogleMap(
+          initialCameraPosition: CameraPosition(target: LatLng(10.0, 15.0)),
+          buildingsEnabled: false,
+        ),
+      ),
+    );
+
+    final FakePlatformGoogleMap platformGoogleMap =
+        fakePlatformViewsController.lastCreatedView;
+
+    expect(platformGoogleMap.buildingsEnabled, false);
+
+    await tester.pumpWidget(
+      const Directionality(
+        textDirection: TextDirection.ltr,
+        child: GoogleMap(
+          initialCameraPosition: CameraPosition(target: LatLng(10.0, 15.0)),
+          buildingsEnabled: true,
+        ),
+      ),
+    );
+
+    expect(platformGoogleMap.buildingsEnabled, true);
+  });
 }