[google_maps_flutter] add zoom controls property (#831)

Adds an Android-only property for toggling zoom controls
diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
index 1027aff..e2cdf01 100644
--- a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
+++ b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.5.26
+
+* Adds support for toggling zoom controls (Android only)
+
 ## 0.5.25+3
 
 * Rename 'Page' in the example app to avoid type conflict with the Flutter Framework.
diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java
index c8429f7..b671d99 100644
--- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java
+++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java
@@ -320,6 +320,10 @@
     if (myLocationEnabled != null) {
       sink.setMyLocationEnabled(toBoolean(myLocationEnabled));
     }
+    final Object zoomControlsEnabled = data.get("zoomControlsEnabled");
+    if (zoomControlsEnabled != null) {
+      sink.setZoomControlsEnabled(toBoolean(zoomControlsEnabled));
+    }
     final Object myLocationButtonEnabled = data.get("myLocationButtonEnabled");
     if (myLocationButtonEnabled != null) {
       sink.setMyLocationButtonEnabled(toBoolean(myLocationButtonEnabled));
diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java
index 535e2ce..af42aa9 100644
--- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java
+++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapBuilder.java
@@ -149,6 +149,11 @@
   }
 
   @Override
+  public void setZoomControlsEnabled(boolean zoomControlsEnabled) {
+    options.zoomControlsEnabled(zoomControlsEnabled);
+  }
+
+  @Override
   public void setMyLocationButtonEnabled(boolean myLocationButtonEnabled) {
     this.myLocationButtonEnabled = myLocationButtonEnabled;
   }
diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java
index 9aea196..4232b39 100644
--- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java
+++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java
@@ -84,6 +84,7 @@
   private boolean trackCameraPosition = false;
   private boolean myLocationEnabled = false;
   private boolean myLocationButtonEnabled = false;
+  private boolean zoomControlsEnabled = true;
   private boolean indoorEnabled = true;
   private boolean trafficEnabled = false;
   private boolean buildingsEnabled = true;
@@ -400,6 +401,11 @@
           result.success(googleMap.getUiSettings().isZoomGesturesEnabled());
           break;
         }
+      case "map#isZoomControlsEnabled":
+        {
+          result.success(googleMap.getUiSettings().isZoomControlsEnabled());
+          break;
+        }
       case "map#isScrollGesturesEnabled":
         {
           result.success(googleMap.getUiSettings().isScrollGesturesEnabled());
@@ -771,6 +777,17 @@
   }
 
   @Override
+  public void setZoomControlsEnabled(boolean zoomControlsEnabled) {
+    if (this.zoomControlsEnabled == zoomControlsEnabled) {
+      return;
+    }
+    this.zoomControlsEnabled = zoomControlsEnabled;
+    if (googleMap != null) {
+      googleMap.getUiSettings().setZoomControlsEnabled(zoomControlsEnabled);
+    }
+  }
+
+  @Override
   public void setInitialMarkers(Object initialMarkers) {
     this.initialMarkers = (List<Object>) initialMarkers;
     if (googleMap != null) {
diff --git a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java
index fb88b36..efae015 100644
--- a/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java
+++ b/packages/google_maps_flutter/google_maps_flutter/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapOptionsSink.java
@@ -32,6 +32,8 @@
 
   void setMyLocationEnabled(boolean myLocationEnabled);
 
+  void setZoomControlsEnabled(boolean zoomControlsEnabled);
+
   void setMyLocationButtonEnabled(boolean myLocationButtonEnabled);
 
   void setIndoorEnabled(boolean indoorEnabled);
diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart
index b44bc68..051d658 100644
--- a/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart
+++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/map_ui.dart
@@ -50,6 +50,7 @@
   bool _rotateGesturesEnabled = true;
   bool _scrollGesturesEnabled = true;
   bool _tiltGesturesEnabled = true;
+  bool _zoomControlsEnabled = false;
   bool _zoomGesturesEnabled = true;
   bool _indoorViewEnabled = true;
   bool _myLocationEnabled = true;
@@ -179,6 +180,18 @@
     );
   }
 
+  Widget _zoomControlsToggler() {
+    return FlatButton(
+      child:
+          Text('${_zoomControlsEnabled ? 'disable' : 'enable'} zoom controls'),
+      onPressed: () {
+        setState(() {
+          _zoomControlsEnabled = !_zoomControlsEnabled;
+        });
+      },
+    );
+  }
+
   Widget _indoorViewToggler() {
     return FlatButton(
       child: Text('${_indoorViewEnabled ? 'disable' : 'enable'} indoor'),
@@ -269,6 +282,7 @@
       scrollGesturesEnabled: _scrollGesturesEnabled,
       tiltGesturesEnabled: _tiltGesturesEnabled,
       zoomGesturesEnabled: _zoomGesturesEnabled,
+      zoomControlsEnabled: _zoomControlsEnabled,
       indoorViewEnabled: _indoorViewEnabled,
       myLocationEnabled: _myLocationEnabled,
       myLocationButtonEnabled: _myLocationButtonEnabled,
@@ -310,6 +324,7 @@
               _scrollToggler(),
               _tiltToggler(),
               _zoomToggler(),
+              _zoomControlsToggler(),
               _indoorViewToggler(),
               _myLocationToggler(),
               _myLocationButtonToggler(),
diff --git a/packages/google_maps_flutter/google_maps_flutter/example/test_driver/google_map_inspector.dart b/packages/google_maps_flutter/google_maps_flutter/example/test_driver/google_map_inspector.dart
index a21e75c..3583d4f 100644
--- a/packages/google_maps_flutter/google_maps_flutter/example/test_driver/google_map_inspector.dart
+++ b/packages/google_maps_flutter/google_maps_flutter/example/test_driver/google_map_inspector.dart
@@ -41,6 +41,10 @@
     return await _channel.invokeMethod<bool>('map#isZoomGesturesEnabled');
   }
 
+  Future<bool> isZoomControlsEnabled() async {
+    return await _channel.invokeMethod<bool>('map#isZoomControlsEnabled');
+  }
+
   Future<bool> isRotateGesturesEnabled() async {
     return await _channel.invokeMethod<bool>('map#isRotateGesturesEnabled');
   }
diff --git a/packages/google_maps_flutter/google_maps_flutter/example/test_driver/google_maps_e2e.dart b/packages/google_maps_flutter/google_maps_flutter/example/test_driver/google_maps_e2e.dart
index 347dde9..3b78d2f 100644
--- a/packages/google_maps_flutter/google_maps_flutter/example/test_driver/google_maps_e2e.dart
+++ b/packages/google_maps_flutter/google_maps_flutter/example/test_driver/google_maps_e2e.dart
@@ -221,6 +221,48 @@
     expect(zoomGesturesEnabled, true);
   });
 
+  testWidgets('testZoomControlsEnabled', (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,
+        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;
+    bool zoomControlsEnabled = await inspector.isZoomControlsEnabled();
+    expect(zoomControlsEnabled, Platform.isIOS ? false : true);
+
+    /// Zoom Controls functionality is not available on iOS at the moment.
+    if (Platform.isAndroid) {
+      await tester.pumpWidget(Directionality(
+        textDirection: TextDirection.ltr,
+        child: GoogleMap(
+          key: key,
+          initialCameraPosition: _kInitialCameraPosition,
+          zoomControlsEnabled: false,
+          onMapCreated: (GoogleMapController controller) {
+            fail("OnMapCreated should get called only once.");
+          },
+        ),
+      ));
+
+      zoomControlsEnabled = await inspector.isZoomControlsEnabled();
+      expect(zoomControlsEnabled, false);
+    }
+  });
+
   testWidgets('testRotateGesturesEnabled', (WidgetTester tester) async {
     final Key key = GlobalKey();
     final Completer<GoogleMapInspector> inspectorCompleter =
diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h
index 1bc8536..23f8726 100644
--- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h
+++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.h
@@ -26,6 +26,7 @@
 - (void)setTiltGesturesEnabled:(BOOL)enabled;
 - (void)setTrackCameraPosition:(BOOL)enabled;
 - (void)setZoomGesturesEnabled:(BOOL)enabled;
+- (void)setZoomControlsEnabled:(BOOL)enabled;
 - (void)setMyLocationEnabled:(BOOL)enabled;
 - (void)setMyLocationButtonEnabled:(BOOL)enabled;
 - (nullable NSString *)setMapStyle:(NSString *)mapStyle;
diff --git a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m
index 9b19197..76e8619 100644
--- a/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m
+++ b/packages/google_maps_flutter/google_maps_flutter/ios/Classes/GoogleMapController.m
@@ -284,6 +284,9 @@
   } else if ([call.method isEqualToString:@"map#isZoomGesturesEnabled"]) {
     NSNumber* isZoomGesturesEnabled = @(_mapView.settings.zoomGestures);
     result(isZoomGesturesEnabled);
+  } else if ([call.method isEqualToString:@"map#isZoomControlsEnabled"]) {
+    NSNumber* isZoomControlsEnabled = [NSNumber numberWithBool:NO];
+    result(isZoomControlsEnabled);
   } else if ([call.method isEqualToString:@"map#isTiltGesturesEnabled"]) {
     NSNumber* isTiltGesturesEnabled = @(_mapView.settings.tiltGestures);
     result(isTiltGesturesEnabled);
diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart
index f6a413a..f2edde3 100644
--- a/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart
+++ b/packages/google_maps_flutter/google_maps_flutter/lib/src/google_map.dart
@@ -35,6 +35,7 @@
     this.minMaxZoomPreference = MinMaxZoomPreference.unbounded,
     this.rotateGesturesEnabled = true,
     this.scrollGesturesEnabled = true,
+    this.zoomControlsEnabled = true,
     this.zoomGesturesEnabled = true,
     this.tiltGesturesEnabled = true,
     this.myLocationEnabled = false,
@@ -88,6 +89,12 @@
   /// True if the map view should respond to scroll gestures.
   final bool scrollGesturesEnabled;
 
+  /// True if the map view should show zoom controls. This includes two buttons
+  /// to zoom in and zoom out. The default value is to show zoom controls.
+  ///
+  /// This is only supported on Android. And this field is silently ignored on iOS.
+  final bool zoomControlsEnabled;
+
   /// True if the map view should respond to zoom gestures.
   final bool zoomGesturesEnabled;
 
@@ -392,6 +399,7 @@
     this.scrollGesturesEnabled,
     this.tiltGesturesEnabled,
     this.trackCameraPosition,
+    this.zoomControlsEnabled,
     this.zoomGesturesEnabled,
     this.myLocationEnabled,
     this.myLocationButtonEnabled,
@@ -412,6 +420,7 @@
       scrollGesturesEnabled: map.scrollGesturesEnabled,
       tiltGesturesEnabled: map.tiltGesturesEnabled,
       trackCameraPosition: map.onCameraMove != null,
+      zoomControlsEnabled: map.zoomControlsEnabled,
       zoomGesturesEnabled: map.zoomGesturesEnabled,
       myLocationEnabled: map.myLocationEnabled,
       myLocationButtonEnabled: map.myLocationButtonEnabled,
@@ -440,6 +449,8 @@
 
   final bool trackCameraPosition;
 
+  final bool zoomControlsEnabled;
+
   final bool zoomGesturesEnabled;
 
   final bool myLocationEnabled;
@@ -471,6 +482,7 @@
     addIfNonNull('rotateGesturesEnabled', rotateGesturesEnabled);
     addIfNonNull('scrollGesturesEnabled', scrollGesturesEnabled);
     addIfNonNull('tiltGesturesEnabled', tiltGesturesEnabled);
+    addIfNonNull('zoomControlsEnabled', zoomControlsEnabled);
     addIfNonNull('zoomGesturesEnabled', zoomGesturesEnabled);
     addIfNonNull('trackCameraPosition', trackCameraPosition);
     addIfNonNull('myLocationEnabled', myLocationEnabled);
diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml
index 0f88a9a..92acb3e 100644
--- a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml
+++ b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml
@@ -1,7 +1,7 @@
 name: google_maps_flutter
 description: A Flutter plugin for integrating Google Maps in iOS and Android applications.
 homepage: https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter
-version: 0.5.25+3
+version: 0.5.26
 
 dependencies:
   flutter:
diff --git a/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart b/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart
index 57b70c4..71741c5 100644
--- a/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart
+++ b/packages/google_maps_flutter/google_maps_flutter/test/fake_maps_controllers.dart
@@ -43,6 +43,8 @@
 
   bool zoomGesturesEnabled;
 
+  bool zoomControlsEnabled;
+
   bool trackCameraPosition;
 
   bool myLocationEnabled;
@@ -351,6 +353,9 @@
     if (options.containsKey('zoomGesturesEnabled')) {
       zoomGesturesEnabled = options['zoomGesturesEnabled'];
     }
+    if (options.containsKey('zoomControlsEnabled')) {
+      zoomControlsEnabled = options['zoomControlsEnabled'];
+    }
     if (options.containsKey('myLocationEnabled')) {
       myLocationEnabled = options['myLocationEnabled'];
     }
diff --git a/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart b/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart
index 5d77ccf..3c1eadb 100644
--- a/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart
+++ b/packages/google_maps_flutter/google_maps_flutter/test/google_map_test.dart
@@ -386,6 +386,35 @@
     expect(platformGoogleMap.zoomGesturesEnabled, true);
   });
 
+  testWidgets('Can update zoomControlsEnabled', (WidgetTester tester) async {
+    await tester.pumpWidget(
+      const Directionality(
+        textDirection: TextDirection.ltr,
+        child: GoogleMap(
+          initialCameraPosition: CameraPosition(target: LatLng(10.0, 15.0)),
+          zoomControlsEnabled: false,
+        ),
+      ),
+    );
+
+    final FakePlatformGoogleMap platformGoogleMap =
+        fakePlatformViewsController.lastCreatedView;
+
+    expect(platformGoogleMap.zoomControlsEnabled, false);
+
+    await tester.pumpWidget(
+      const Directionality(
+        textDirection: TextDirection.ltr,
+        child: GoogleMap(
+          initialCameraPosition: CameraPosition(target: LatLng(10.0, 15.0)),
+          zoomControlsEnabled: true,
+        ),
+      ),
+    );
+
+    expect(platformGoogleMap.zoomControlsEnabled, true);
+  });
+
   testWidgets('Can update myLocationEnabled', (WidgetTester tester) async {
     await tester.pumpWidget(
       const Directionality(