[google_maps_flutter] Add liteModeEnabled option (#2449)

diff --git a/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter/CHANGELOG.md
index df4d916..66ca6fe 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.28
+
+* Android: Add liteModeEnabled option.
+
 ## 0.5.27+3
 
 * iOS: Update the gesture recognizer blocking policy to "WaitUntilTouchesEnded", which fixes the camera idle callback not triggered issue.
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 b671d99..5ef7b26 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
@@ -316,6 +316,10 @@
     if (zoomGesturesEnabled != null) {
       sink.setZoomGesturesEnabled(toBoolean(zoomGesturesEnabled));
     }
+    final Object liteModeEnabled = data.get("liteModeEnabled");
+    if (liteModeEnabled != null) {
+      sink.setLiteModeEnabled(toBoolean(liteModeEnabled));
+    }
     final Object myLocationEnabled = data.get("myLocationEnabled");
     if (myLocationEnabled != null) {
       sink.setMyLocationEnabled(toBoolean(myLocationEnabled));
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 af42aa9..97af63c 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
@@ -129,6 +129,11 @@
   }
 
   @Override
+  public void setLiteModeEnabled(boolean liteModeEnabled) {
+    options.liteMode(liteModeEnabled);
+  }
+
+  @Override
   public void setIndoorEnabled(boolean indoorEnabled) {
     this.indoorEnabled = indoorEnabled;
   }
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 6f59aa6..40cce49 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
@@ -70,6 +70,7 @@
   private final int id;
   private final AtomicInteger activityState;
   private final MethodChannel methodChannel;
+  private final GoogleMapOptions options;
   private final MapView mapView;
   private GoogleMap googleMap;
   private boolean trackCameraPosition = false;
@@ -111,6 +112,7 @@
     this.id = id;
     this.context = context;
     this.activityState = activityState;
+    this.options = options;
     this.mapView = new MapView(context, options);
     this.density = context.getResources().getDisplayMetrics().density;
     methodChannel = new MethodChannel(binaryMessenger, "plugins.flutter.io/google_maps_" + id);
@@ -383,6 +385,11 @@
           result.success(googleMap.getUiSettings().isZoomGesturesEnabled());
           break;
         }
+      case "map#isLiteModeEnabled":
+        {
+          result.success(options.getLiteMode());
+          break;
+        }
       case "map#isZoomControlsEnabled":
         {
           result.success(googleMap.getUiSettings().isZoomControlsEnabled());
@@ -749,6 +756,12 @@
     googleMap.getUiSettings().setZoomGesturesEnabled(zoomGesturesEnabled);
   }
 
+  /** This call will have no effect on already created map */
+  @Override
+  public void setLiteModeEnabled(boolean liteModeEnabled) {
+    options.liteMode(liteModeEnabled);
+  }
+
   @Override
   public void setMyLocationEnabled(boolean myLocationEnabled) {
     if (this.myLocationEnabled == myLocationEnabled) {
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 efae015..9e6fa2a 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
@@ -30,6 +30,8 @@
 
   void setZoomGesturesEnabled(boolean zoomGesturesEnabled);
 
+  void setLiteModeEnabled(boolean liteModeEnabled);
+
   void setMyLocationEnabled(boolean myLocationEnabled);
 
   void setZoomControlsEnabled(boolean zoomControlsEnabled);
diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/lite_mode.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/lite_mode.dart
new file mode 100644
index 0000000..7c814f3
--- /dev/null
+++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/lite_mode.dart
@@ -0,0 +1,45 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// ignore_for_file: public_member_api_docs
+
+import 'package:flutter/material.dart';
+import 'package:flutter/widgets.dart';
+import 'package:google_maps_flutter/google_maps_flutter.dart';
+import 'page.dart';
+
+const CameraPosition _kInitialPosition =
+    CameraPosition(target: LatLng(-33.852, 151.211), zoom: 11.0);
+
+class LiteModePage extends GoogleMapExampleAppPage {
+  LiteModePage() : super(const Icon(Icons.map), 'Lite mode');
+
+  @override
+  Widget build(BuildContext context) {
+    return const _LiteModeBody();
+  }
+}
+
+class _LiteModeBody extends StatelessWidget {
+  const _LiteModeBody();
+
+  @override
+  Widget build(BuildContext context) {
+    return Card(
+      child: Padding(
+        padding: const EdgeInsets.symmetric(vertical: 30.0),
+        child: Center(
+          child: SizedBox(
+            width: 300.0,
+            height: 300.0,
+            child: GoogleMap(
+              initialCameraPosition: _kInitialPosition,
+              liteModeEnabled: true,
+            ),
+          ),
+        ),
+      ),
+    );
+  }
+}
diff --git a/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart b/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart
index 95d8c45..13763ed 100644
--- a/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart
+++ b/packages/google_maps_flutter/google_maps_flutter/example/lib/main.dart
@@ -5,6 +5,7 @@
 // ignore_for_file: public_member_api_docs
 
 import 'package:flutter/material.dart';
+import 'package:google_maps_flutter_example/lite_mode.dart';
 import 'animate_camera.dart';
 import 'map_click.dart';
 import 'map_coordinates.dart';
@@ -34,6 +35,7 @@
   PlaceCirclePage(),
   PaddingPage(),
   SnapshotPage(),
+  LiteModePage(),
 ];
 
 class MapsDemo extends StatelessWidget {
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 3583d4f..2fcfec1 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
@@ -45,6 +45,10 @@
     return await _channel.invokeMethod<bool>('map#isZoomControlsEnabled');
   }
 
+  Future<bool> isLiteModeEnabled() async {
+    return await _channel.invokeMethod<bool>('map#isLiteModeEnabled');
+  }
+
   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 9620d60..c47862b 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
@@ -263,6 +263,46 @@
     }
   });
 
+  testWidgets('testLiteModeEnabled', (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,
+        liteModeEnabled: false,
+        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 liteModeEnabled = await inspector.isLiteModeEnabled();
+    expect(liteModeEnabled, false);
+
+    await tester.pumpWidget(Directionality(
+      textDirection: TextDirection.ltr,
+      child: GoogleMap(
+        key: key,
+        initialCameraPosition: _kInitialCameraPosition,
+        liteModeEnabled: true,
+        onMapCreated: (GoogleMapController controller) {
+          fail("OnMapCreated should get called only once.");
+        },
+      ),
+    ));
+
+    liteModeEnabled = await inspector.isLiteModeEnabled();
+    expect(liteModeEnabled, true);
+  }, skip: !Platform.isAndroid);
+
   testWidgets('testRotateGesturesEnabled', (WidgetTester tester) async {
     final Key key = GlobalKey();
     final Completer<GoogleMapInspector> inspectorCompleter =
diff --git a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart
index a17b30c..b879f3d 100644
--- a/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart
+++ b/packages/google_maps_flutter/google_maps_flutter/lib/google_maps_flutter.dart
@@ -5,6 +5,7 @@
 library google_maps_flutter;
 
 import 'dart:async';
+import 'dart:io';
 import 'dart:typed_data';
 import 'dart:ui';
 
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 ecd1a70..a45a1c8 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
@@ -29,6 +29,7 @@
     this.scrollGesturesEnabled = true,
     this.zoomControlsEnabled = true,
     this.zoomGesturesEnabled = true,
+    this.liteModeEnabled = false,
     this.tiltGesturesEnabled = true,
     this.myLocationEnabled = false,
     this.myLocationButtonEnabled = true,
@@ -90,6 +91,11 @@
   /// True if the map view should respond to zoom gestures.
   final bool zoomGesturesEnabled;
 
+  /// True if the map view should be in lite mode. Android only.
+  ///
+  /// See https://developers.google.com/maps/documentation/android-sdk/lite#overview_of_lite_mode for more details.
+  final bool liteModeEnabled;
+
   /// True if the map view should respond to tilt gestures.
   final bool tiltGesturesEnabled;
 
@@ -372,13 +378,18 @@
     this.trackCameraPosition,
     this.zoomControlsEnabled,
     this.zoomGesturesEnabled,
+    this.liteModeEnabled,
     this.myLocationEnabled,
     this.myLocationButtonEnabled,
     this.padding,
     this.indoorViewEnabled,
     this.trafficEnabled,
     this.buildingsEnabled,
-  });
+  }) {
+    assert(liteModeEnabled == null ||
+        !liteModeEnabled ||
+        (liteModeEnabled && Platform.isAndroid));
+  }
 
   static _GoogleMapOptions fromWidget(GoogleMap map) {
     return _GoogleMapOptions(
@@ -393,6 +404,7 @@
       trackCameraPosition: map.onCameraMove != null,
       zoomControlsEnabled: map.zoomControlsEnabled,
       zoomGesturesEnabled: map.zoomGesturesEnabled,
+      liteModeEnabled: map.liteModeEnabled,
       myLocationEnabled: map.myLocationEnabled,
       myLocationButtonEnabled: map.myLocationButtonEnabled,
       padding: map.padding,
@@ -424,6 +436,8 @@
 
   final bool zoomGesturesEnabled;
 
+  final bool liteModeEnabled;
+
   final bool myLocationEnabled;
 
   final bool myLocationButtonEnabled;
@@ -455,6 +469,7 @@
     addIfNonNull('tiltGesturesEnabled', tiltGesturesEnabled);
     addIfNonNull('zoomControlsEnabled', zoomControlsEnabled);
     addIfNonNull('zoomGesturesEnabled', zoomGesturesEnabled);
+    addIfNonNull('liteModeEnabled', liteModeEnabled);
     addIfNonNull('trackCameraPosition', trackCameraPosition);
     addIfNonNull('myLocationEnabled', myLocationEnabled);
     addIfNonNull('myLocationButtonEnabled', myLocationButtonEnabled);
diff --git a/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter/pubspec.yaml
index cf4b869..4b30226 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.27+3
+version: 0.5.28
 
 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 71741c5..adca8b4 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
@@ -45,6 +45,8 @@
 
   bool zoomControlsEnabled;
 
+  bool liteModeEnabled;
+
   bool trackCameraPosition;
 
   bool myLocationEnabled;
@@ -356,6 +358,9 @@
     if (options.containsKey('zoomControlsEnabled')) {
       zoomControlsEnabled = options['zoomControlsEnabled'];
     }
+    if (options.containsKey('liteModeEnabled')) {
+      liteModeEnabled = options['liteModeEnabled'];
+    }
     if (options.containsKey('myLocationEnabled')) {
       myLocationEnabled = options['myLocationEnabled'];
     }
diff --git a/packages/google_maps_flutter/test/android_google_map_test.dart b/packages/google_maps_flutter/test/android_google_map_test.dart
new file mode 100644
index 0000000..194efe9
--- /dev/null
+++ b/packages/google_maps_flutter/test/android_google_map_test.dart
@@ -0,0 +1,56 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+@TestOn('android')
+import 'package:flutter/services.dart';
+import 'package:flutter/widgets.dart';
+import 'package:flutter_test/flutter_test.dart';
+import 'package:google_maps_flutter/google_maps_flutter.dart';
+
+import 'fake_maps_controllers.dart';
+
+void main() {
+  TestWidgetsFlutterBinding.ensureInitialized();
+
+  final FakePlatformViewsController fakePlatformViewsController =
+      FakePlatformViewsController();
+
+  setUpAll(() {
+    SystemChannels.platform_views.setMockMethodCallHandler(
+        fakePlatformViewsController.fakePlatformViewsMethodHandler);
+  });
+
+  setUp(() {
+    fakePlatformViewsController.reset();
+  });
+
+  testWidgets('Can update liteModeEnabled', (WidgetTester tester) async {
+    await tester.pumpWidget(
+      const Directionality(
+        textDirection: TextDirection.ltr,
+        child: GoogleMap(
+          initialCameraPosition: CameraPosition(target: LatLng(10.0, 15.0)),
+          liteModeEnabled: false,
+        ),
+      ),
+    );
+
+    final FakePlatformGoogleMap platformGoogleMap =
+        fakePlatformViewsController.lastCreatedView;
+
+    expect(platformGoogleMap.liteModeEnabled, false);
+
+    await tester.pumpWidget(
+      const Directionality(
+        textDirection: TextDirection.ltr,
+        child: GoogleMap(
+          initialCameraPosition: CameraPosition(target: LatLng(10.0, 15.0)),
+          liteModeEnabled: true,
+        ),
+      ),
+    );
+
+    expect(platformGoogleMap.liteModeEnabled, true);
+  });
+}