From e50f45013a2a481c287e67ac7466a0a6f3206ab8 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jun 2024 15:15:23 -0400 Subject: [PATCH 01/13] Manual roll Flutter from e726eb401c2c to 15f95ce0c38e (48 revisions) (#7002) Manual roll Flutter from e726eb401c2c to 15f95ce0c38e (48 revisions) Manual roll requested by dit@google.com https://github.com/flutter/flutter/compare/e726eb401c2c...15f95ce0c38e 2024-06-28 engine-flutter-autoroll@skia.org Roll Flutter Engine from ddd4814b9d40 to 94591ffb20df (5 revisions) (flutter/flutter#150968) 2024-06-27 34871572+gmackall@users.noreply.github.com Manual engine roll to ddd4814 (flutter/flutter#150952) 2024-06-27 reidbaker@google.com local lint copy gradle task config (flutter/flutter#150957) 2024-06-27 engine-flutter-autoroll@skia.org Roll Flutter Engine from b42c80460538 to d1506c12808e (3 revisions) (flutter/flutter#150951) 2024-06-27 andrewrkolos@gmail.com [tool] make the `systemTempDirectory` getter on `ErrorHandlingFileSystem` wrap the underlying filesystem's temp directory in a`ErrorHandlingDirectory` (flutter/flutter#150876) 2024-06-27 jacksongardner@google.com Have flutter.js load local canvaskit instead of the CDN when appropriate (flutter/flutter#150806) 2024-06-27 engine-flutter-autoroll@skia.org Roll Flutter Engine from a9194f0f01f4 to b42c80460538 (10 revisions) (flutter/flutter#150940) 2024-06-27 jhy03261997@gmail.com [a11y] Reland [#149375 ] Update semantics in dropdown.dart (flutter/flutter#150578) 2024-06-27 goderbauer@google.com Bump dartdoc to 8.0.9+1 (flutter/flutter#150935) 2024-06-27 yjbanov@google.com add onFocus to text fields (flutter/flutter#150648) 2024-06-27 louisehsu@google.com Fixes `flutter build ipa` failure: Command line name "app-store" is deprecated. Use "app-store-connect" (flutter/flutter#150407) 2024-06-27 github@ricardoboss.de Copy any previous `IconThemeData` instead of overwriting it in CupertinoButton (flutter/flutter#149777) 2024-06-27 hans.muller@gmail.com Improve the behavior of scrollbar drag-scrolls triggered by the trackpad (flutter/flutter#150275) 2024-06-27 15272073+Fernthedev@users.noreply.github.com feat: Add autofocus for `MenuItemButton` (flutter/flutter#139396) 2024-06-27 engine-flutter-autoroll@skia.org Roll Flutter Engine from 1d5e3cc55a75 to a9194f0f01f4 (7 revisions) (flutter/flutter#150888) 2024-06-26 34871572+gmackall@users.noreply.github.com Reland "Remove dual_screen from new_gallery integration test" (flutter/flutter#150873) 2024-06-26 parlough@gmail.com Switch to more reliable flutter.dev link destinations in the tool (flutter/flutter#150587) 2024-06-26 goderbauer@google.com Adding `@docImport`s to the `animation` library (flutter/flutter#150798) 2024-06-26 magder@google.com Remove CODEOWNERS trailing whitespace (flutter/flutter#150882) 2024-06-26 engine-flutter-autoroll@skia.org Roll Flutter Engine from e03cf86c4170 to 1d5e3cc55a75 (3 revisions) (flutter/flutter#150875) 2024-06-26 matanlurey@users.noreply.github.com Remind folks we are moving. (flutter/flutter#150872) 2024-06-26 jacksongardner@google.com Remove `bringup: true` from web test shard. (flutter/flutter#150785) 2024-06-26 engine-flutter-autoroll@skia.org Roll Flutter Engine from c0017bed42c2 to e03cf86c4170 (1 revision) (flutter/flutter#150867) 2024-06-26 98614782+auto-submit[bot]@users.noreply.github.com Reverts "Remove `dual_screen` from `new_gallery` integration test (#150808)" (flutter/flutter#150871) 2024-06-26 34871572+gmackall@users.noreply.github.com Remove `dual_screen` from `new_gallery` integration test (flutter/flutter#150808) 2024-06-26 engine-flutter-autoroll@skia.org Roll Flutter Engine from d4624a36712b to c0017bed42c2 (4 revisions) (flutter/flutter#150865) 2024-06-26 swrenn@gmail.com Fixes for Style Guide for Flutter Repo (flutter/flutter#150167) 2024-06-26 engine-flutter-autoroll@skia.org Roll Flutter Engine from da62c629ed5c to d4624a36712b (3 revisions) (flutter/flutter#150852) 2024-06-26 sigurdm@google.com Use `Isolate.packageConfigSync! to locate the packageconfig of flutter tools (flutter/flutter#150340) 2024-06-26 engine-flutter-autoroll@skia.org Roll Flutter Engine from 25af762ffbb3 to da62c629ed5c (2 revisions) (flutter/flutter#150829) 2024-06-26 polinach@google.com Fix leaky tests. (flutter/flutter#150817) 2024-06-26 engine-flutter-autoroll@skia.org Roll Flutter Engine from 94023d711db3 to 25af762ffbb3 (4 revisions) (flutter/flutter#150818) 2024-06-26 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#150810) 2024-06-25 dkwingsmt@users.noreply.github.com Remove reference to `MaterialApp` and `showCupertinoModalPopup` from `CupertinoAlertDialog` (flutter/flutter#150725) 2024-06-25 matanlurey@users.noreply.github.com Read `AndroidManifest.xml` and emit `manifest-impeller-(enabled|disabled)` analytics (flutter/flutter#150791) 2024-06-25 jason-simmons@users.noreply.github.com [flutter_tools] Shut down Chromium cleanly using a command sent through the debug protocol (flutter/flutter#150645) 2024-06-25 bruno.leroux@gmail.com Reland fix inputDecorator hint color on M3 (flutter/flutter#150278) 2024-06-25 engine-flutter-autoroll@skia.org Roll Flutter Engine from 62e0b5f9c340 to 94023d711db3 (7 revisions) (flutter/flutter#150797) 2024-06-25 bruno.leroux@gmail.com Fix collapsed InputDecorator minimum height (flutter/flutter#150770) 2024-06-25 737941+loic-sharma@users.noreply.github.com Add more warm up frame docs (flutter/flutter#150464) 2024-06-25 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#150739) 2024-06-25 victorsanniay@gmail.com Add `focusNode`, `focusColor`, `onFocusChange`, `autofocus` to `CupertinoButton` (flutter/flutter#150721) 2024-06-25 greg@zulip.com Document RenderObject._relayoutBoundary and its invariant; small refactors (flutter/flutter#150527) 2024-06-25 engine-flutter-autoroll@skia.org Roll Flutter Engine from 6313b1e5afd7 to 62e0b5f9c340 (1 revision) (flutter/flutter#150790) ... --- .ci/flutter_master.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/flutter_master.version b/.ci/flutter_master.version index 40760d7272d..c49803e9f26 100644 --- a/.ci/flutter_master.version +++ b/.ci/flutter_master.version @@ -1 +1 @@ -e726eb401c2c1c882aa393071d5bb8bfb45e1dc3 +15f95ce0c38ee62545ce630e62c348a824bda50d From 90a5444449a950f81812bd6ce035f854ebf9b3bc Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Fri, 28 Jun 2024 15:34:14 -0400 Subject: [PATCH 02/13] [google_maps_flutter] Fix Obj-C type handling (#7010) Eliminates the remaining google_maps_flutter cases of the once-common-in-this-repo type abuse of getting a value from a method channel arguments dictionary that may either be type `T` or `NSNull`, but assigning directly to a variable of type `T`, and then later comparing that variable to `NSNull` with a cast to silence the (correct) warning from the compiler. Longer term this will be eliminated entirely when the Pigeon conversion is complete, but currently I expect that in the short term we will only do a "shallow" Pigeon conversion (see https://github.com/flutter/packages/pull/6980 for an Android example), meaning this code will likely stay around for a while. --- .../google_maps_flutter_ios/CHANGELOG.md | 4 + ...TGoogleMapJSONConversionsConversionTests.m | 22 ++++++ .../ios/Classes/FLTGoogleMapJSONConversions.h | 3 + .../ios/Classes/FLTGoogleMapJSONConversions.m | 6 ++ .../FLTGoogleMapTileOverlayController.m | 20 ++--- .../ios/Classes/GoogleMapCircleController.m | 32 ++++---- .../ios/Classes/GoogleMapController.m | 60 +++++++-------- .../ios/Classes/GoogleMapMarkerController.m | 74 ++++++++++--------- .../ios/Classes/GoogleMapPolygonController.m | 32 ++++---- .../ios/Classes/GoogleMapPolylineController.m | 22 ++---- .../google_maps_flutter_ios/pubspec.yaml | 2 +- 11 files changed, 154 insertions(+), 123 deletions(-) diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md index 6fc61e8eefc..4802eb9d144 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_ios/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.8.1 + +* Improves Objective-C type handling. + ## 2.8.0 * Adds compatibility with SDK version 9.x for apps targetting iOS 15+. diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios14/ios/RunnerTests/FLTGoogleMapJSONConversionsConversionTests.m b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios14/ios/RunnerTests/FLTGoogleMapJSONConversionsConversionTests.m index cc654606d8c..e75fc046912 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/example/ios14/ios/RunnerTests/FLTGoogleMapJSONConversionsConversionTests.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/example/ios14/ios/RunnerTests/FLTGoogleMapJSONConversionsConversionTests.m @@ -16,6 +16,28 @@ @interface FLTGoogleMapJSONConversionsTests : XCTestCase @implementation FLTGoogleMapJSONConversionsTests +- (void)testGetValueOrNilWithValue { + NSString *key = @"key"; + NSString *value = @"value"; + NSDictionary *dict = @{key : value}; + + XCTAssertEqual(FGMGetValueOrNilFromDict(dict, key), value); +} + +- (void)testGetValueOrNilWithNoEntry { + NSString *key = @"key"; + NSDictionary *dict = @{}; + + XCTAssertNil(FGMGetValueOrNilFromDict(dict, key)); +} + +- (void)testGetValueOrNilWithNSNull { + NSString *key = @"key"; + NSDictionary *dict = @{key : [NSNull null]}; + + XCTAssertNil(FGMGetValueOrNilFromDict(dict, key)); +} + - (void)testLocationFromLatLong { NSArray *latlong = @[ @1, @2 ]; CLLocationCoordinate2D location = [FLTGoogleMapJSONConversions locationFromLatLong:latlong]; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapJSONConversions.h b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapJSONConversions.h index 1fc8d003d91..c6f9fc76eba 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapJSONConversions.h +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapJSONConversions.h @@ -7,6 +7,9 @@ NS_ASSUME_NONNULL_BEGIN +/// Returns dict[key], or nil if dict[key] is NSNull. +extern id _Nullable FGMGetValueOrNilFromDict(NSDictionary *dict, NSString *key); + @interface FLTGoogleMapJSONConversions : NSObject + (CLLocationCoordinate2D)locationFromLatLong:(NSArray *)latlong; diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapJSONConversions.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapJSONConversions.m index 28307182f2c..f6ea7690222 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapJSONConversions.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapJSONConversions.m @@ -4,6 +4,12 @@ #import "FLTGoogleMapJSONConversions.h" +/// Returns dict[key], or nil if dict[key] is NSNull. +id FGMGetValueOrNilFromDict(NSDictionary *dict, NSString *key) { + id value = dict[key]; + return value == [NSNull null] ? nil : value; +} + @implementation FLTGoogleMapJSONConversions + (CLLocationCoordinate2D)locationFromLatLong:(NSArray *)latlong { diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapTileOverlayController.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapTileOverlayController.m index 73eab6c1ead..bc56671f5cd 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapTileOverlayController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FLTGoogleMapTileOverlayController.m @@ -70,28 +70,28 @@ - (void)interpretTileOverlayOptions:(NSDictionary *)data { if (!data) { return; } - NSNumber *visible = data[@"visible"]; - if (visible != nil && visible != (id)[NSNull null]) { + NSNumber *visible = FGMGetValueOrNilFromDict(data, @"visible"); + if (visible) { [self setVisible:visible.boolValue]; } - NSNumber *transparency = data[@"transparency"]; - if (transparency != nil && transparency != (id)[NSNull null]) { + NSNumber *transparency = FGMGetValueOrNilFromDict(data, @"transparency"); + if (transparency) { [self setTransparency:transparency.floatValue]; } - NSNumber *zIndex = data[@"zIndex"]; - if (zIndex != nil && zIndex != (id)[NSNull null]) { + NSNumber *zIndex = FGMGetValueOrNilFromDict(data, @"zIndex"); + if (zIndex) { [self setZIndex:zIndex.intValue]; } - NSNumber *fadeIn = data[@"fadeIn"]; - if (fadeIn != nil && fadeIn != (id)[NSNull null]) { + NSNumber *fadeIn = FGMGetValueOrNilFromDict(data, @"fadeIn"); + if (fadeIn) { [self setFadeIn:fadeIn.boolValue]; } - NSNumber *tileSize = data[@"tileSize"]; - if (tileSize != nil && tileSize != (id)[NSNull null]) { + NSNumber *tileSize = FGMGetValueOrNilFromDict(data, @"tileSize"); + if (tileSize) { [self setTileSize:tileSize.integerValue]; } } diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapCircleController.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapCircleController.m index 53bf69075c9..1eb74a19559 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapCircleController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapCircleController.m @@ -60,43 +60,43 @@ - (void)setFillColor:(UIColor *)color { } - (void)interpretCircleOptions:(NSDictionary *)data { - NSNumber *consumeTapEvents = data[@"consumeTapEvents"]; - if (consumeTapEvents && consumeTapEvents != (id)[NSNull null]) { + NSNumber *consumeTapEvents = FGMGetValueOrNilFromDict(data, @"consumeTapEvents"); + if (consumeTapEvents) { [self setConsumeTapEvents:consumeTapEvents.boolValue]; } - NSNumber *visible = data[@"visible"]; - if (visible && visible != (id)[NSNull null]) { + NSNumber *visible = FGMGetValueOrNilFromDict(data, @"visible"); + if (visible) { [self setVisible:[visible boolValue]]; } - NSNumber *zIndex = data[@"zIndex"]; - if (zIndex && zIndex != (id)[NSNull null]) { + NSNumber *zIndex = FGMGetValueOrNilFromDict(data, @"zIndex"); + if (zIndex) { [self setZIndex:[zIndex intValue]]; } - NSArray *center = data[@"center"]; - if (center && center != (id)[NSNull null]) { + NSArray *center = FGMGetValueOrNilFromDict(data, @"center"); + if (center) { [self setCenter:[FLTGoogleMapJSONConversions locationFromLatLong:center]]; } - NSNumber *radius = data[@"radius"]; - if (radius && radius != (id)[NSNull null]) { + NSNumber *radius = FGMGetValueOrNilFromDict(data, @"radius"); + if (radius) { [self setRadius:[radius floatValue]]; } - NSNumber *strokeColor = data[@"strokeColor"]; - if (strokeColor && strokeColor != (id)[NSNull null]) { + NSNumber *strokeColor = FGMGetValueOrNilFromDict(data, @"strokeColor"); + if (strokeColor) { [self setStrokeColor:[FLTGoogleMapJSONConversions colorFromRGBA:strokeColor]]; } - NSNumber *strokeWidth = data[@"strokeWidth"]; - if (strokeWidth && strokeWidth != (id)[NSNull null]) { + NSNumber *strokeWidth = FGMGetValueOrNilFromDict(data, @"strokeWidth"); + if (strokeWidth) { [self setStrokeWidth:[strokeWidth intValue]]; } - NSNumber *fillColor = data[@"fillColor"]; - if (fillColor && fillColor != (id)[NSNull null]) { + NSNumber *fillColor = FGMGetValueOrNilFromDict(data, @"fillColor"); + if (fillColor) { [self setFillColor:[FLTGoogleMapJSONConversions colorFromRGBA:fillColor]]; } } diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m index 4c747f3eeba..08fdf8cc7f4 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapController.m @@ -581,41 +581,41 @@ - (void)mapView:(GMSMapView *)mapView didLongPressAtCoordinate:(CLLocationCoordi } - (void)interpretMapOptions:(NSDictionary *)data { - NSArray *cameraTargetBounds = data[@"cameraTargetBounds"]; - if (cameraTargetBounds && cameraTargetBounds != (id)[NSNull null]) { + NSArray *cameraTargetBounds = FGMGetValueOrNilFromDict(data, @"cameraTargetBounds"); + if (cameraTargetBounds) { [self setCameraTargetBounds:cameraTargetBounds.count > 0 && cameraTargetBounds[0] != [NSNull null] ? [FLTGoogleMapJSONConversions coordinateBoundsFromLatLongs:cameraTargetBounds.firstObject] : nil]; } - NSNumber *compassEnabled = data[@"compassEnabled"]; - if (compassEnabled && compassEnabled != (id)[NSNull null]) { + NSNumber *compassEnabled = FGMGetValueOrNilFromDict(data, @"compassEnabled"); + if (compassEnabled) { [self setCompassEnabled:[compassEnabled boolValue]]; } - id indoorEnabled = data[@"indoorEnabled"]; - if (indoorEnabled && indoorEnabled != [NSNull null]) { + id indoorEnabled = FGMGetValueOrNilFromDict(data, @"indoorEnabled"); + if (indoorEnabled) { [self setIndoorEnabled:[indoorEnabled boolValue]]; } - id trafficEnabled = data[@"trafficEnabled"]; - if (trafficEnabled && trafficEnabled != [NSNull null]) { + id trafficEnabled = FGMGetValueOrNilFromDict(data, @"trafficEnabled"); + if (trafficEnabled) { [self setTrafficEnabled:[trafficEnabled boolValue]]; } - id buildingsEnabled = data[@"buildingsEnabled"]; - if (buildingsEnabled && buildingsEnabled != [NSNull null]) { + id buildingsEnabled = FGMGetValueOrNilFromDict(data, @"buildingsEnabled"); + if (buildingsEnabled) { [self setBuildingsEnabled:[buildingsEnabled boolValue]]; } - id mapType = data[@"mapType"]; - if (mapType && mapType != [NSNull null]) { + id mapType = FGMGetValueOrNilFromDict(data, @"mapType"); + if (mapType) { [self setMapType:[FLTGoogleMapJSONConversions mapViewTypeFromTypeValue:mapType]]; } - NSArray *zoomData = data[@"minMaxZoomPreference"]; - if (zoomData && zoomData != (id)[NSNull null]) { + NSArray *zoomData = FGMGetValueOrNilFromDict(data, @"minMaxZoomPreference"); + if (zoomData) { float minZoom = (zoomData[0] == [NSNull null]) ? kGMSMinZoomLevel : [zoomData[0] floatValue]; float maxZoom = (zoomData[1] == [NSNull null]) ? kGMSMaxZoomLevel : [zoomData[1] floatValue]; [self setMinZoom:minZoom maxZoom:maxZoom]; } - NSArray *paddingData = data[@"padding"]; + NSArray *paddingData = FGMGetValueOrNilFromDict(data, @"padding"); if (paddingData) { float top = (paddingData[0] == [NSNull null]) ? 0 : [paddingData[0] floatValue]; float left = (paddingData[1] == [NSNull null]) ? 0 : [paddingData[1] floatValue]; @@ -624,35 +624,35 @@ - (void)interpretMapOptions:(NSDictionary *)data { [self setPaddingTop:top left:left bottom:bottom right:right]; } - NSNumber *rotateGesturesEnabled = data[@"rotateGesturesEnabled"]; - if (rotateGesturesEnabled && rotateGesturesEnabled != (id)[NSNull null]) { + NSNumber *rotateGesturesEnabled = FGMGetValueOrNilFromDict(data, @"rotateGesturesEnabled"); + if (rotateGesturesEnabled) { [self setRotateGesturesEnabled:[rotateGesturesEnabled boolValue]]; } - NSNumber *scrollGesturesEnabled = data[@"scrollGesturesEnabled"]; - if (scrollGesturesEnabled && scrollGesturesEnabled != (id)[NSNull null]) { + NSNumber *scrollGesturesEnabled = FGMGetValueOrNilFromDict(data, @"scrollGesturesEnabled"); + if (scrollGesturesEnabled) { [self setScrollGesturesEnabled:[scrollGesturesEnabled boolValue]]; } - NSNumber *tiltGesturesEnabled = data[@"tiltGesturesEnabled"]; - if (tiltGesturesEnabled && tiltGesturesEnabled != (id)[NSNull null]) { + NSNumber *tiltGesturesEnabled = FGMGetValueOrNilFromDict(data, @"tiltGesturesEnabled"); + if (tiltGesturesEnabled) { [self setTiltGesturesEnabled:[tiltGesturesEnabled boolValue]]; } - NSNumber *trackCameraPosition = data[@"trackCameraPosition"]; - if (trackCameraPosition && trackCameraPosition != (id)[NSNull null]) { + NSNumber *trackCameraPosition = FGMGetValueOrNilFromDict(data, @"trackCameraPosition"); + if (trackCameraPosition) { [self setTrackCameraPosition:[trackCameraPosition boolValue]]; } - NSNumber *zoomGesturesEnabled = data[@"zoomGesturesEnabled"]; - if (zoomGesturesEnabled && zoomGesturesEnabled != (id)[NSNull null]) { + NSNumber *zoomGesturesEnabled = FGMGetValueOrNilFromDict(data, @"zoomGesturesEnabled"); + if (zoomGesturesEnabled) { [self setZoomGesturesEnabled:[zoomGesturesEnabled boolValue]]; } - NSNumber *myLocationEnabled = data[@"myLocationEnabled"]; - if (myLocationEnabled && myLocationEnabled != (id)[NSNull null]) { + NSNumber *myLocationEnabled = FGMGetValueOrNilFromDict(data, @"myLocationEnabled"); + if (myLocationEnabled) { [self setMyLocationEnabled:[myLocationEnabled boolValue]]; } - NSNumber *myLocationButtonEnabled = data[@"myLocationButtonEnabled"]; - if (myLocationButtonEnabled && myLocationButtonEnabled != (id)[NSNull null]) { + NSNumber *myLocationButtonEnabled = FGMGetValueOrNilFromDict(data, @"myLocationButtonEnabled"); + if (myLocationButtonEnabled) { [self setMyLocationButtonEnabled:[myLocationButtonEnabled boolValue]]; } - NSString *style = data[@"style"]; + NSString *style = FGMGetValueOrNilFromDict(data, @"style"); if (style) { self.styleError = [self setMapStyle:style]; } diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapMarkerController.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapMarkerController.m index b816e7ee914..1bc7d2a8db8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapMarkerController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapMarkerController.m @@ -93,60 +93,60 @@ - (void)setZIndex:(int)zIndex { - (void)interpretMarkerOptions:(NSDictionary *)data registrar:(NSObject *)registrar screenScale:(CGFloat)screenScale { - NSNumber *alpha = data[@"alpha"]; - if (alpha && alpha != (id)[NSNull null]) { + NSNumber *alpha = FGMGetValueOrNilFromDict(data, @"alpha"); + if (alpha) { [self setAlpha:[alpha floatValue]]; } - NSArray *anchor = data[@"anchor"]; - if (anchor && anchor != (id)[NSNull null]) { + NSArray *anchor = FGMGetValueOrNilFromDict(data, @"anchor"); + if (anchor) { [self setAnchor:[FLTGoogleMapJSONConversions pointFromArray:anchor]]; } - NSNumber *draggable = data[@"draggable"]; - if (draggable && draggable != (id)[NSNull null]) { + NSNumber *draggable = FGMGetValueOrNilFromDict(data, @"draggable"); + if (draggable) { [self setDraggable:[draggable boolValue]]; } - NSArray *icon = data[@"icon"]; - if (icon && icon != (id)[NSNull null]) { + NSArray *icon = FGMGetValueOrNilFromDict(data, @"icon"); + if (icon) { UIImage *image = [self extractIconFromData:icon registrar:registrar screenScale:screenScale]; [self setIcon:image]; } - NSNumber *flat = data[@"flat"]; - if (flat && flat != (id)[NSNull null]) { + NSNumber *flat = FGMGetValueOrNilFromDict(data, @"flat"); + if (flat) { [self setFlat:[flat boolValue]]; } - NSNumber *consumeTapEvents = data[@"consumeTapEvents"]; - if (consumeTapEvents && consumeTapEvents != (id)[NSNull null]) { + NSNumber *consumeTapEvents = FGMGetValueOrNilFromDict(data, @"consumeTapEvents"); + if (consumeTapEvents) { [self setConsumeTapEvents:[consumeTapEvents boolValue]]; } [self interpretInfoWindow:data]; - NSArray *position = data[@"position"]; - if (position && position != (id)[NSNull null]) { + NSArray *position = FGMGetValueOrNilFromDict(data, @"position"); + if (position) { [self setPosition:[FLTGoogleMapJSONConversions locationFromLatLong:position]]; } - NSNumber *rotation = data[@"rotation"]; - if (rotation && rotation != (id)[NSNull null]) { + NSNumber *rotation = FGMGetValueOrNilFromDict(data, @"rotation"); + if (rotation) { [self setRotation:[rotation doubleValue]]; } - NSNumber *visible = data[@"visible"]; - if (visible && visible != (id)[NSNull null]) { + NSNumber *visible = FGMGetValueOrNilFromDict(data, @"visible"); + if (visible) { [self setVisible:[visible boolValue]]; } - NSNumber *zIndex = data[@"zIndex"]; - if (zIndex && zIndex != (id)[NSNull null]) { + NSNumber *zIndex = FGMGetValueOrNilFromDict(data, @"zIndex"); + if (zIndex) { [self setZIndex:[zIndex intValue]]; } } - (void)interpretInfoWindow:(NSDictionary *)data { - NSDictionary *infoWindow = data[@"infoWindow"]; - if (infoWindow && infoWindow != (id)[NSNull null]) { - NSString *title = infoWindow[@"title"]; - NSString *snippet = infoWindow[@"snippet"]; - if (title && title != (id)[NSNull null]) { + NSDictionary *infoWindow = FGMGetValueOrNilFromDict(data, @"infoWindow"); + if (infoWindow) { + NSString *title = FGMGetValueOrNilFromDict(infoWindow, @"title"); + NSString *snippet = FGMGetValueOrNilFromDict(infoWindow, @"snippet"); + if (title) { [self setInfoWindowTitle:title snippet:snippet]; } NSArray *infoWindowAnchor = infoWindow[@"infoWindowAnchor"]; - if (infoWindowAnchor && infoWindowAnchor != (id)[NSNull null]) { + if (infoWindowAnchor) { [self setInfoWindowAnchor:[FLTGoogleMapJSONConversions pointFromArray:infoWindowAnchor]]; } } @@ -221,15 +221,16 @@ - (UIImage *)extractIconFromData:(NSArray *)iconData @throw exception; } - NSString *assetName = assetData[@"assetName"]; - NSString *scalingMode = assetData[@"bitmapScaling"]; + NSString *assetName = FGMGetValueOrNilFromDict(assetData, @"assetName"); + NSString *scalingMode = FGMGetValueOrNilFromDict(assetData, @"bitmapScaling"); image = [UIImage imageNamed:[registrar lookupKeyForAsset:assetName]]; if ([scalingMode isEqualToString:@"auto"]) { - NSNumber *width = assetData[@"width"]; - NSNumber *height = assetData[@"height"]; - CGFloat imagePixelRatio = [assetData[@"imagePixelRatio"] doubleValue]; + NSNumber *width = FGMGetValueOrNilFromDict(assetData, @"width"); + NSNumber *height = FGMGetValueOrNilFromDict(assetData, @"height"); + CGFloat imagePixelRatio = + [FGMGetValueOrNilFromDict(assetData, @"imagePixelRatio") doubleValue]; if (width || height) { image = [FLTGoogleMapMarkerController scaledImage:image withScale:screenScale]; @@ -252,15 +253,16 @@ - (UIImage *)extractIconFromData:(NSArray *)iconData @throw exception; } - FlutterStandardTypedData *bytes = byteData[@"byteData"]; - NSString *scalingMode = byteData[@"bitmapScaling"]; + FlutterStandardTypedData *bytes = FGMGetValueOrNilFromDict(byteData, @"byteData"); + NSString *scalingMode = FGMGetValueOrNilFromDict(byteData, @"bitmapScaling"); @try { image = [UIImage imageWithData:[bytes data] scale:screenScale]; if ([scalingMode isEqualToString:@"auto"]) { - NSNumber *width = byteData[@"width"]; - NSNumber *height = byteData[@"height"]; - CGFloat imagePixelRatio = [byteData[@"imagePixelRatio"] doubleValue]; + NSNumber *width = FGMGetValueOrNilFromDict(byteData, @"width"); + NSNumber *height = FGMGetValueOrNilFromDict(byteData, @"height"); + CGFloat imagePixelRatio = + [FGMGetValueOrNilFromDict(byteData, @"imagePixelRatio") doubleValue]; if (width || height) { // Before scaling the image, image must be in screenScale diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapPolygonController.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapPolygonController.m index 398adfcacec..d8dc47def60 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapPolygonController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapPolygonController.m @@ -73,43 +73,43 @@ - (void)setStrokeWidth:(CGFloat)width { - (void)interpretPolygonOptions:(NSDictionary *)data registrar:(NSObject *)registrar { - NSNumber *consumeTapEvents = data[@"consumeTapEvents"]; - if (consumeTapEvents && consumeTapEvents != (id)[NSNull null]) { + NSNumber *consumeTapEvents = FGMGetValueOrNilFromDict(data, @"consumeTapEvents"); + if (consumeTapEvents) { [self setConsumeTapEvents:[consumeTapEvents boolValue]]; } - NSNumber *visible = data[@"visible"]; - if (visible && visible != (id)[NSNull null]) { + NSNumber *visible = FGMGetValueOrNilFromDict(data, @"visible"); + if (visible) { [self setVisible:[visible boolValue]]; } - NSNumber *zIndex = data[@"zIndex"]; - if (zIndex && zIndex != (id)[NSNull null]) { + NSNumber *zIndex = FGMGetValueOrNilFromDict(data, @"zIndex"); + if (zIndex) { [self setZIndex:[zIndex intValue]]; } - NSArray *points = data[@"points"]; - if (points && points != (id)[NSNull null]) { + NSArray *points = FGMGetValueOrNilFromDict(data, @"points"); + if (points) { [self setPoints:[FLTGoogleMapJSONConversions pointsFromLatLongs:points]]; } - NSArray *holes = data[@"holes"]; - if (holes && holes != (id)[NSNull null]) { + NSArray *holes = FGMGetValueOrNilFromDict(data, @"holes"); + if (holes) { [self setHoles:[FLTGoogleMapJSONConversions holesFromPointsArray:holes]]; } - NSNumber *fillColor = data[@"fillColor"]; - if (fillColor && fillColor != (id)[NSNull null]) { + NSNumber *fillColor = FGMGetValueOrNilFromDict(data, @"fillColor"); + if (fillColor) { [self setFillColor:[FLTGoogleMapJSONConversions colorFromRGBA:fillColor]]; } - NSNumber *strokeColor = data[@"strokeColor"]; - if (strokeColor && strokeColor != (id)[NSNull null]) { + NSNumber *strokeColor = FGMGetValueOrNilFromDict(data, @"strokeColor"); + if (strokeColor) { [self setStrokeColor:[FLTGoogleMapJSONConversions colorFromRGBA:strokeColor]]; } - NSNumber *strokeWidth = data[@"strokeWidth"]; - if (strokeWidth && strokeWidth != (id)[NSNull null]) { + NSNumber *strokeWidth = FGMGetValueOrNilFromDict(data, @"strokeWidth"); + if (strokeWidth) { [self setStrokeWidth:[strokeWidth intValue]]; } } diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapPolylineController.m b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapPolylineController.m index 47334576b1c..a97f372d6fd 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapPolylineController.m +++ b/packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/GoogleMapPolylineController.m @@ -12,12 +12,6 @@ @interface FLTGoogleMapPolylineController () @end -/// Returns dict[key], or nil if dict[key] is NSNull. -static id GetValueOrNilFromDict(NSDictionary *dict, NSString *key) { - id value = dict[key]; - return value == [NSNull null] ? nil : value; -} - @implementation FLTGoogleMapPolylineController - (instancetype)initPolylineWithPath:(GMSMutablePath *)path @@ -71,42 +65,42 @@ - (void)setPattern:(NSArray *)styles lengths:(NSArray *)registrar { - NSNumber *consumeTapEvents = GetValueOrNilFromDict(data, @"consumeTapEvents"); + NSNumber *consumeTapEvents = FGMGetValueOrNilFromDict(data, @"consumeTapEvents"); if (consumeTapEvents) { [self setConsumeTapEvents:[consumeTapEvents boolValue]]; } - NSNumber *visible = GetValueOrNilFromDict(data, @"visible"); + NSNumber *visible = FGMGetValueOrNilFromDict(data, @"visible"); if (visible) { [self setVisible:[visible boolValue]]; } - NSNumber *zIndex = GetValueOrNilFromDict(data, @"zIndex"); + NSNumber *zIndex = FGMGetValueOrNilFromDict(data, @"zIndex"); if (zIndex) { [self setZIndex:[zIndex intValue]]; } - NSArray *points = GetValueOrNilFromDict(data, @"points"); + NSArray *points = FGMGetValueOrNilFromDict(data, @"points"); if (points) { [self setPoints:[FLTGoogleMapJSONConversions pointsFromLatLongs:points]]; } - NSNumber *strokeColor = GetValueOrNilFromDict(data, @"color"); + NSNumber *strokeColor = FGMGetValueOrNilFromDict(data, @"color"); if (strokeColor) { [self setColor:[FLTGoogleMapJSONConversions colorFromRGBA:strokeColor]]; } - NSNumber *strokeWidth = GetValueOrNilFromDict(data, @"width"); + NSNumber *strokeWidth = FGMGetValueOrNilFromDict(data, @"width"); if (strokeWidth) { [self setStrokeWidth:[strokeWidth intValue]]; } - NSNumber *geodesic = GetValueOrNilFromDict(data, @"geodesic"); + NSNumber *geodesic = FGMGetValueOrNilFromDict(data, @"geodesic"); if (geodesic) { [self setGeodesic:geodesic.boolValue]; } - NSArray *patterns = GetValueOrNilFromDict(data, @"pattern"); + NSArray *patterns = FGMGetValueOrNilFromDict(data, @"pattern"); if (patterns) { [self setPattern:[FLTGoogleMapJSONConversions strokeStylesFromPatterns:patterns diff --git a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml index e2dc69dd1bb..0314d44e46f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_ios/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_ios description: iOS implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_ios issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.8.0 +version: 2.8.1 environment: sdk: ^3.2.3 From d43a827c3b57a7ff548c38f2b9687f561f18d51b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 28 Jun 2024 21:12:23 +0000 Subject: [PATCH 03/13] Bump ossf/scorecard-action from 2.3.1 to 2.3.3 (#6709) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [ossf/scorecard-action](https://github.com/ossf/scorecard-action) from 2.3.1 to 2.3.3.
Release notes

Sourced from ossf/scorecard-action's releases.

v2.3.3

[!NOTE]
There is no v2.3.2 release as a step was skipped in the release process. This was fixed and re-released under the v2.3.3 tag

What's Changed

For a full changelist of what these include, see the v5.0.0-rc1 and v5.0.0-rc2 release notes.

Documentation

Full Changelog: https://github.com/ossf/scorecard-action/compare/v2.3.1...v2.3.3

Commits
  • dc50aa9 :seedling: Bump docker tag for v2.3.3 release (#1368)
  • 8ff5700 :seedling: Bump github.com/ossf/scorecard/v5 from v5.0.0-rc2 to v5.0.0-rc2.0....
  • 8ba5e73 update api links to new scorecard.dev site (#1376)
  • 92ddde3 Bump github.com/ossf/scorecard/v5 from v5.0.0-rc1 to v5.0.0-rc2 (#1374)
  • 6c55905 :seedling: Bump golang.org/x/net from 0.24.0 to 0.25.0 (#1373)
  • 09bb953 :seedling: Bump distroless/base in the docker-images group (#1372)
  • 1511e13 :seedling: Bump the github-actions group across 1 directory with 6 updates (#...
  • df66cd8 :seedling: Bump the docker-images group with 2 updates (#1370)
  • fad9a3c :seedling: Bump distroless/base in the docker-images group (#1364)
  • 1e01a30 :seedling: Bump the github-actions group with 3 updates (#1365)
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ossf/scorecard-action&package-manager=github_actions&previous-version=2.3.1&new-version=2.3.3)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) You can trigger a rebase of this PR by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
> **Note** > Automatic rebases have been disabled on this pull request as it has been open for over 30 days. --- .github/workflows/scorecards-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/scorecards-analysis.yml b/.github/workflows/scorecards-analysis.yml index 9a922769fbc..395418d7e52 100644 --- a/.github/workflows/scorecards-analysis.yml +++ b/.github/workflows/scorecards-analysis.yml @@ -26,7 +26,7 @@ jobs: persist-credentials: false - name: "Run analysis" - uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.0.3 + uses: ossf/scorecard-action@dc50aa9510b46c811795eb24b2f1ba02a914e534 # v2.0.3 with: results_file: results.sarif results_format: sarif From 9fc86273b3be40443b1fc8578638127cf15460b0 Mon Sep 17 00:00:00 2001 From: Phong_NguyenGia <36687028+phong010198@users.noreply.github.com> Date: Sat, 29 Jun 2024 06:57:08 +0700 Subject: [PATCH 04/13] [flutter_markdown] Add horizontal scroll for markdown table (#6983) Add horizontal scroll for markdown table when using `tableColumnWidth: FixedColumnWidth(width)` Fix [flutter/flutter#129052](https://github.com/flutter/flutter/issues/129052) --- packages/flutter_markdown/CHANGELOG.md | 4 ++ .../flutter_markdown/lib/src/builder.dart | 29 +++++++-- .../flutter_markdown/lib/src/style_sheet.dart | 12 ++++ packages/flutter_markdown/pubspec.yaml | 2 +- .../test/scrollable_test.dart | 64 +++++++++++++++++++ 5 files changed, 104 insertions(+), 7 deletions(-) diff --git a/packages/flutter_markdown/CHANGELOG.md b/packages/flutter_markdown/CHANGELOG.md index f787fabbc05..2b42efadc5f 100644 --- a/packages/flutter_markdown/CHANGELOG.md +++ b/packages/flutter_markdown/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.7.3 + +* Adds horizontal scrolling for table when using `tableColumnWidth: FixedColumnWidth(width)`. + ## 0.7.2+1 * Fixes a crash caused by text selection when `selectable` is true and `onSelectionChanged` is null. diff --git a/packages/flutter_markdown/lib/src/builder.dart b/packages/flutter_markdown/lib/src/builder.dart index 8e7c98abdc2..0706453a01d 100644 --- a/packages/flutter_markdown/lib/src/builder.dart +++ b/packages/flutter_markdown/lib/src/builder.dart @@ -438,12 +438,20 @@ class MarkdownBuilder implements md.NodeVisitor { ); } } else if (tag == 'table') { - child = Table( - defaultColumnWidth: styleSheet.tableColumnWidth!, - defaultVerticalAlignment: styleSheet.tableVerticalAlignment, - border: styleSheet.tableBorder, - children: _tables.removeLast().rows, - ); + if (styleSheet.tableColumnWidth is FixedColumnWidth) { + final ScrollController tableScrollController = ScrollController(); + child = Scrollbar( + controller: tableScrollController, + child: SingleChildScrollView( + controller: tableScrollController, + scrollDirection: Axis.horizontal, + padding: styleSheet.tablePadding, + child: _buildTable(), + ), + ); + } else { + child = _buildTable(); + } } else if (tag == 'blockquote') { _isInBlockquote = false; child = DecoratedBox( @@ -558,6 +566,15 @@ class MarkdownBuilder implements md.NodeVisitor { _lastVisitedTag = tag; } + Table _buildTable() { + return Table( + defaultColumnWidth: styleSheet.tableColumnWidth!, + defaultVerticalAlignment: styleSheet.tableVerticalAlignment, + border: styleSheet.tableBorder, + children: _tables.removeLast().rows, + ); + } + Widget _buildImage(String src, String? title, String? alt) { final List parts = src.split('#'); if (parts.isEmpty) { diff --git a/packages/flutter_markdown/lib/src/style_sheet.dart b/packages/flutter_markdown/lib/src/style_sheet.dart index f3b570aeb91..3923e618ff3 100644 --- a/packages/flutter_markdown/lib/src/style_sheet.dart +++ b/packages/flutter_markdown/lib/src/style_sheet.dart @@ -38,6 +38,7 @@ class MarkdownStyleSheet { this.tableHead, this.tableBody, this.tableHeadAlign, + this.tablePadding, this.tableBorder, this.tableColumnWidth, this.tableCellsPadding, @@ -134,6 +135,7 @@ class MarkdownStyleSheet { tableHead: const TextStyle(fontWeight: FontWeight.w600), tableBody: theme.textTheme.bodyMedium, tableHeadAlign: TextAlign.center, + tablePadding: const EdgeInsets.only(bottom: 4.0), tableBorder: TableBorder.all( color: theme.dividerColor, ), @@ -231,6 +233,7 @@ class MarkdownStyleSheet { ), tableBody: theme.textTheme.textStyle, tableHeadAlign: TextAlign.center, + tablePadding: const EdgeInsets.only(bottom: 8), tableBorder: TableBorder.all(color: CupertinoColors.separator, width: 0), tableColumnWidth: const FlexColumnWidth(), tableCellsPadding: const EdgeInsets.fromLTRB(16, 8, 16, 8), @@ -312,6 +315,7 @@ class MarkdownStyleSheet { tableHead: const TextStyle(fontWeight: FontWeight.w600), tableBody: theme.textTheme.bodyMedium, tableHeadAlign: TextAlign.center, + tablePadding: const EdgeInsets.only(bottom: 4.0), tableBorder: TableBorder.all( color: theme.dividerColor, ), @@ -371,6 +375,7 @@ class MarkdownStyleSheet { TextStyle? tableHead, TextStyle? tableBody, TextAlign? tableHeadAlign, + EdgeInsets? tablePadding, TableBorder? tableBorder, TableColumnWidth? tableColumnWidth, EdgeInsets? tableCellsPadding, @@ -436,6 +441,7 @@ class MarkdownStyleSheet { tableHead: tableHead ?? this.tableHead, tableBody: tableBody ?? this.tableBody, tableHeadAlign: tableHeadAlign ?? this.tableHeadAlign, + tablePadding: tablePadding ?? this.tablePadding, tableBorder: tableBorder ?? this.tableBorder, tableColumnWidth: tableColumnWidth ?? this.tableColumnWidth, tableCellsPadding: tableCellsPadding ?? this.tableCellsPadding, @@ -502,6 +508,7 @@ class MarkdownStyleSheet { tableHead: tableHead!.merge(other.tableHead), tableBody: tableBody!.merge(other.tableBody), tableHeadAlign: other.tableHeadAlign, + tablePadding: other.tablePadding, tableBorder: other.tableBorder, tableColumnWidth: other.tableColumnWidth, tableCellsPadding: other.tableCellsPadding, @@ -620,6 +627,9 @@ class MarkdownStyleSheet { /// The [TextAlign] to use for `th` elements. final TextAlign? tableHeadAlign; + /// The padding to use for `table` elements. + final EdgeInsets? tablePadding; + /// The [TableBorder] to use for `table` elements. final TableBorder? tableBorder; @@ -740,6 +750,7 @@ class MarkdownStyleSheet { other.tableHead == tableHead && other.tableBody == tableBody && other.tableHeadAlign == tableHeadAlign && + other.tablePadding == tablePadding && other.tableBorder == tableBorder && other.tableColumnWidth == tableColumnWidth && other.tableCellsPadding == tableCellsPadding && @@ -798,6 +809,7 @@ class MarkdownStyleSheet { tableHead, tableBody, tableHeadAlign, + tablePadding, tableBorder, tableColumnWidth, tableCellsPadding, diff --git a/packages/flutter_markdown/pubspec.yaml b/packages/flutter_markdown/pubspec.yaml index f7b58ed2888..ecfd21ea000 100644 --- a/packages/flutter_markdown/pubspec.yaml +++ b/packages/flutter_markdown/pubspec.yaml @@ -4,7 +4,7 @@ description: A Markdown renderer for Flutter. Create rich text output, formatted with simple Markdown tags. repository: https://github.com/flutter/packages/tree/main/packages/flutter_markdown issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+flutter_markdown%22 -version: 0.7.2+1 +version: 0.7.3 environment: sdk: ^3.3.0 diff --git a/packages/flutter_markdown/test/scrollable_test.dart b/packages/flutter_markdown/test/scrollable_test.dart index 23092328f00..1042a6fa98a 100644 --- a/packages/flutter_markdown/test/scrollable_test.dart +++ b/packages/flutter_markdown/test/scrollable_test.dart @@ -110,5 +110,69 @@ void defineTests() { ]); }, ); + + testWidgets( + 'table', + (WidgetTester tester) async { + const String data = '|Header 1|Header 2|Header 3|' + '\n|-----|-----|-----|' + '\n|Col 1|Col 2|Col 3|'; + await tester.pumpWidget( + boilerplate( + MediaQuery( + data: const MediaQueryData(), + child: MarkdownBody( + data: data, + styleSheet: MarkdownStyleSheet( + tableColumnWidth: const FixedColumnWidth(150), + ), + ), + ), + ), + ); + + final Iterable widgets = tester.allWidgets; + final Iterable scrollViews = + widgets.whereType(); + expect(scrollViews, isNotEmpty); + expect(scrollViews.first.controller, isNotNull); + }, + ); + + testWidgets( + 'two tables use different scroll controllers', + (WidgetTester tester) async { + const String data = '|Header 1|Header 2|Header 3|' + '\n|-----|-----|-----|' + '\n|Col 1|Col 2|Col 3|' + '\n' + '\n|Header 1|Header 2|Header 3|' + '\n|-----|-----|-----|' + '\n|Col 1|Col 2|Col 3|'; + + await tester.pumpWidget( + boilerplate( + MediaQuery( + data: const MediaQueryData(), + child: MarkdownBody( + data: data, + styleSheet: MarkdownStyleSheet( + tableColumnWidth: const FixedColumnWidth(150), + ), + ), + ), + ), + ); + + final Iterable widgets = tester.allWidgets; + final Iterable scrollViews = + widgets.whereType(); + expect(scrollViews, hasLength(2)); + expect(scrollViews.first.controller, isNotNull); + expect(scrollViews.last.controller, isNotNull); + expect(scrollViews.first.controller, + isNot(equals(scrollViews.last.controller))); + }, + ); }); } From b63626c31b919a97baa7c6ac542e8a9fa93dc3e6 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Fri, 28 Jun 2024 21:44:07 -0400 Subject: [PATCH 05/13] Manual roll Flutter from 15f95ce0c38e to 651a17db5427 (7 revisions) (#7013) Manual roll requested by dit@google.com https://github.com/flutter/flutter/compare/15f95ce0c38e...651a17db5427 2024-06-28 engine-flutter-autoroll@skia.org Roll Flutter Engine from a78f5ce743ce to 2f7e9ab27493 (11 revisions) (flutter/flutter#151002) 2024-06-28 hi@timcreated.it Draggable feedback positioning (flutter/flutter#149040) 2024-06-28 dr@schlau.bi Add support for type-safe plugin apply (flutter/flutter#150958) 2024-06-28 dev@alestiago.com Use caret syntax with flutter create command (flutter/flutter#150920) 2024-06-28 engine-flutter-autoroll@skia.org Roll Packages from 03f5f6d5660c to 412ec4615aa4 (12 revisions) (flutter/flutter#150985) 2024-06-28 danny@tuppeny.com [flutter_tools] Include more details in structured errors sent to a DAP client (flutter/flutter#150698) 2024-06-28 engine-flutter-autoroll@skia.org Roll Flutter Engine from 94591ffb20df to a78f5ce743ce (1 revision) (flutter/flutter#150972) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC dit@google.com,rmistry@google.com,stuartmorgan@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- .ci/flutter_master.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/flutter_master.version b/.ci/flutter_master.version index c49803e9f26..de12310d68a 100644 --- a/.ci/flutter_master.version +++ b/.ci/flutter_master.version @@ -1 +1 @@ -15f95ce0c38ee62545ce630e62c348a824bda50d +651a17db5427edd1d0bd849f4bad9e3f33952412 From 0e3460cba24784314d1374603856b9629e75aec5 Mon Sep 17 00:00:00 2001 From: David Iglesias Date: Sat, 29 Jun 2024 02:52:27 -0700 Subject: [PATCH 06/13] [video_player] Bumps web implementation dependency. (#7015) Updates minimum web implementation version to ensure support for the new `webOptions` exposed in the previous release. ## Issues: * Described here: https://github.com/flutter/flutter/issues/150327#issuecomment-2197399790 --- packages/video_player/video_player/CHANGELOG.md | 5 +++++ packages/video_player/video_player/pubspec.yaml | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/video_player/video_player/CHANGELOG.md b/packages/video_player/video_player/CHANGELOG.md index 91b9f02c057..48b5e0b7eac 100644 --- a/packages/video_player/video_player/CHANGELOG.md +++ b/packages/video_player/video_player/CHANGELOG.md @@ -1,3 +1,8 @@ +## 2.9.1 + +* Updates minimum web implementation version to ensure support for + the new `webOptions` exposed in `2.9.0`. + ## 2.9.0 * Exports types: `VideoPlayerWebOptions` and `VideoPlayerWebOptionsControls` to diff --git a/packages/video_player/video_player/pubspec.yaml b/packages/video_player/video_player/pubspec.yaml index aff4a9700c7..ecc85cfa25e 100644 --- a/packages/video_player/video_player/pubspec.yaml +++ b/packages/video_player/video_player/pubspec.yaml @@ -3,10 +3,10 @@ description: Flutter plugin for displaying inline video with other Flutter widgets on Android, iOS, and web. repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22 -version: 2.9.0 +version: 2.9.1 environment: - sdk: ">=3.2.3 <4.0.0" + sdk: ^3.2.3 flutter: ">=3.16.6" flutter: @@ -28,7 +28,7 @@ dependencies: video_player_android: ^2.3.5 video_player_avfoundation: ^2.5.6 video_player_platform_interface: ^6.2.0 - video_player_web: ^2.0.0 + video_player_web: ^2.1.0 dev_dependencies: flutter_test: From c0b4cda19d8014c98fb07fe83c908c379198513c Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Mon, 1 Jul 2024 08:19:19 -0700 Subject: [PATCH 07/13] [ci] Adds @matanlurey to some Android CODEOWNERS until Impeller is enabled. (#7014) I.e. until https://github.com/flutter/flutter/issues/151018 is completed. I know this is not foolproof, but I'm hoping it at least keeps me on top of whatever needs to change in the meantime. --- CODEOWNERS | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index cb9966fa3ae..d7c37efa2fb 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -62,8 +62,9 @@ packages/video_player/video_player_web/** @ditman packages/webview_flutter/webview_flutter_web/** @ditman # - Android -packages/camera/camera_android/** @camsim99 -packages/camera/camera_android_camerax/** @camsim99 +# TODO(matanlurey): Remove @matanlurey after https://github.com/flutter/flutter/issues/151018. +packages/camera/camera_android/** @camsim99 @matanlurey +packages/camera/camera_android_camerax/** @camsim99 @matanlurey packages/espresso/** @reidbaker packages/file_selector/file_selector_android/** @gmackall packages/flutter_plugin_android_lifecycle/** @reidbaker @@ -76,7 +77,7 @@ packages/path_provider/path_provider_android/** @camsim99 packages/quick_actions/quick_actions_android/** @camsim99 packages/shared_preferences/shared_preferences_android/** @reidbaker packages/url_launcher/url_launcher_android/** @gmackall -packages/video_player/video_player_android/** @camsim99 +packages/video_player/video_player_android/** @camsim99 @matanlurey # Owned by ecosystem team for now during the wrapper evaluation. packages/webview_flutter/webview_flutter_android/** @bparrishMines From d7a7dfaae9c4b4f303d3ef26856905aaa5066e96 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 16:04:58 +0000 Subject: [PATCH 08/13] [camera]: Bump com.android.tools.build:gradle from 7.3.0 to 8.5.0 in /packages/camera/camera_android/android (#6928) Bumps com.android.tools.build:gradle from 7.3.0 to 8.5.0. [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=com.android.tools.build:gradle&package-manager=gradle&previous-version=7.3.0&new-version=8.5.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- packages/camera/camera_android/CHANGELOG.md | 4 ++++ packages/camera/camera_android/android/build.gradle | 2 +- packages/camera/camera_android/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/camera/camera_android/CHANGELOG.md b/packages/camera/camera_android/CHANGELOG.md index 1e46c7c96e6..777f4913eeb 100644 --- a/packages/camera/camera_android/CHANGELOG.md +++ b/packages/camera/camera_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.10.9+7 + +* Updates Android Gradle plugin to 8.5.0. + ## 0.10.9+6 * Reverts changes to support Impeller. diff --git a/packages/camera/camera_android/android/build.gradle b/packages/camera/camera_android/android/build.gradle index 2caee412af1..005d5d00985 100644 --- a/packages/camera/camera_android/android/build.gradle +++ b/packages/camera/camera_android/android/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.3.0' + classpath 'com.android.tools.build:gradle:8.5.0' } } diff --git a/packages/camera/camera_android/pubspec.yaml b/packages/camera/camera_android/pubspec.yaml index 178c15de795..0dc0371c0e4 100644 --- a/packages/camera/camera_android/pubspec.yaml +++ b/packages/camera/camera_android/pubspec.yaml @@ -3,7 +3,7 @@ description: Android implementation of the camera plugin. repository: https://github.com/flutter/packages/tree/main/packages/camera/camera_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+camera%22 -version: 0.10.9+6 +version: 0.10.9+7 environment: sdk: ^3.4.0 From 6b7f7324a3887ac86902f36aaeefe1896fafc385 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 16:07:57 +0000 Subject: [PATCH 09/13] [video_player]: Bump com.android.tools.build:gradle from 7.2.1 to 8.5.0 in /packages/video_player/video_player_android/android (#6931) Bumps com.android.tools.build:gradle from 7.2.1 to 8.5.0. [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=com.android.tools.build:gradle&package-manager=gradle&previous-version=7.2.1&new-version=8.5.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- packages/video_player/video_player_android/CHANGELOG.md | 4 ++++ .../video_player/video_player_android/android/build.gradle | 2 +- packages/video_player/video_player_android/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/video_player/video_player_android/CHANGELOG.md b/packages/video_player/video_player_android/CHANGELOG.md index d3c63dae9d8..863fcf80513 100644 --- a/packages/video_player/video_player_android/CHANGELOG.md +++ b/packages/video_player/video_player_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.5.2 + +* Updates Android Gradle plugin to 8.5.0. + ## 2.5.1 * Removes additional references to the v1 Android embedding. diff --git a/packages/video_player/video_player_android/android/build.gradle b/packages/video_player/video_player_android/android/build.gradle index 789d0949572..5675d385de3 100644 --- a/packages/video_player/video_player_android/android/build.gradle +++ b/packages/video_player/video_player_android/android/build.gradle @@ -9,7 +9,7 @@ buildscript { } dependencies { - classpath 'com.android.tools.build:gradle:7.2.1' + classpath 'com.android.tools.build:gradle:8.5.0' } } diff --git a/packages/video_player/video_player_android/pubspec.yaml b/packages/video_player/video_player_android/pubspec.yaml index 2d234734d71..b57f24d100c 100644 --- a/packages/video_player/video_player_android/pubspec.yaml +++ b/packages/video_player/video_player_android/pubspec.yaml @@ -2,7 +2,7 @@ name: video_player_android description: Android implementation of the video_player plugin. repository: https://github.com/flutter/packages/tree/main/packages/video_player/video_player_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+video_player%22 -version: 2.5.1 +version: 2.5.2 environment: sdk: ^3.4.0 From 4ea5948b3ea3e3e788b4838e2f0f74865eff723a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 16:12:48 +0000 Subject: [PATCH 10/13] [local_auth]: Bump androidx.test.espresso:espresso-core from 3.5.1 to 3.6.1 in /packages/local_auth/local_auth_android/android (#7022) Bumps androidx.test.espresso:espresso-core from 3.5.1 to 3.6.1. [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=androidx.test.espresso:espresso-core&package-manager=gradle&previous-version=3.5.1&new-version=3.6.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- packages/local_auth/local_auth_android/CHANGELOG.md | 4 ++++ packages/local_auth/local_auth_android/android/build.gradle | 2 +- packages/local_auth/local_auth_android/pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/local_auth/local_auth_android/CHANGELOG.md b/packages/local_auth/local_auth_android/CHANGELOG.md index 5f74d5c8e6b..435e2ed98ab 100644 --- a/packages/local_auth/local_auth_android/CHANGELOG.md +++ b/packages/local_auth/local_auth_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.0.41 + +* Updates espresso to 3.6.1. + ## 1.0.40 * Updates androidx.core version to 1.13.1. diff --git a/packages/local_auth/local_auth_android/android/build.gradle b/packages/local_auth/local_auth_android/android/build.gradle index b2326e4b212..57059c3dc56 100644 --- a/packages/local_auth/local_auth_android/android/build.gradle +++ b/packages/local_auth/local_auth_android/android/build.gradle @@ -67,7 +67,7 @@ dependencies { testImplementation 'org.robolectric:robolectric:4.10.3' androidTestImplementation 'androidx.test:runner:1.2.0' androidTestImplementation 'androidx.test:rules:1.2.0' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' // TODO(camsim99): org.jetbrains.kotlin:kotlin-bom artifact purpose is to align kotlin stdlib and related code versions. // This should be removed when https://github.com/flutter/flutter/issues/125062 is fixed. implementation(platform("org.jetbrains.kotlin:kotlin-bom:1.8.10")) diff --git a/packages/local_auth/local_auth_android/pubspec.yaml b/packages/local_auth/local_auth_android/pubspec.yaml index 4352b3b8299..30c542ff3de 100644 --- a/packages/local_auth/local_auth_android/pubspec.yaml +++ b/packages/local_auth/local_auth_android/pubspec.yaml @@ -2,7 +2,7 @@ name: local_auth_android description: Android implementation of the local_auth plugin. repository: https://github.com/flutter/packages/tree/main/packages/local_auth/local_auth_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+local_auth%22 -version: 1.0.40 +version: 1.0.41 environment: sdk: ^3.4.0 From eff249d7289675f83893aacfb8ddf9ccd4a1a10b Mon Sep 17 00:00:00 2001 From: stuartmorgan Date: Mon, 1 Jul 2024 13:48:21 -0400 Subject: [PATCH 11/13] [google_maps_flutter] Semi-convert remaining Android host API calls to Pigeon (#6980) Does a "shallow" Pigeon conversion of the remaining host API calls in the Android implementation. All of the actual method calls are now Pigeon, but for the most part the data structures are not yet converted, and the Pigeon representations of the map objects are instead placeholders that currently just wrap the existing JSON serialization. This is done for a few reasons: - Keeps the incremental PR relatively small and easy to understand. - Quickly gets us to a state where any new APIs added will automatically use Pigeon, reducing further accumulation of technical debt. - Avoids duplication of handling code until https://github.com/flutter/flutter/issues/150631 is resolved. As noted in a TODO added in this PR, almost all of the data structures that are passed in these methods are also passed through the PlatformView factory constructor, and Pigeon doesn't yet support using the Pigeon codec in non-Pigeon-generated code, so we would need to have both the structured *and* JSON handler for all of these objects if we converted them now. Future PRs will be able to incrementally convert each map object to a structured form. Converting the Flutter APIs (Java->Dart) will also be done in a follow-up, to limit the scope of this PR. Adds Dart unit tests for each method call, as they were previously not unit tested. Part of https://github.com/flutter/flutter/issues/117907 --- .../google_maps_flutter_android/CHANGELOG.md | 4 + .../plugins/googlemaps/CirclesController.java | 30 +- .../googlemaps/ClusterManagersController.java | 29 +- .../flutter/plugins/googlemaps/Convert.java | 16 + .../googlemaps/GoogleMapController.java | 203 ++-- .../googlemaps/GoogleMapInitializer.java | 74 +- .../plugins/googlemaps/MarkersController.java | 34 +- .../flutter/plugins/googlemaps/Messages.java | 891 +++++++++++++++++- .../googlemaps/PolygonsController.java | 32 +- .../googlemaps/PolylinesController.java | 32 +- .../googlemaps/TileOverlaysController.java | 26 +- .../ClusterManagersControllerTest.java | 63 +- .../googlemaps/GoogleMapControllerTest.java | 2 +- .../googlemaps/GoogleMapInitializerTest.java | 60 +- .../googlemaps/MarkersControllerTest.java | 21 +- .../lib/src/google_maps_flutter_android.dart | 161 ++-- .../lib/src/messages.g.dart | 559 ++++++++++- .../lib/src/utils/cluster_manager_utils.dart | 15 - .../pigeons/messages.dart | 166 ++++ .../google_maps_flutter_android/pubspec.yaml | 2 +- .../test/cluster_manager_utils_test.dart | 59 -- .../google_maps_flutter_android_test.dart | 281 ++++++ ...oogle_maps_flutter_android_test.mocks.dart | 146 +++ 23 files changed, 2429 insertions(+), 477 deletions(-) delete mode 100644 packages/google_maps_flutter/google_maps_flutter_android/test/cluster_manager_utils_test.dart diff --git a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md index 2291ed28c47..7a1833338bf 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md +++ b/packages/google_maps_flutter/google_maps_flutter_android/CHANGELOG.md @@ -1,3 +1,7 @@ +## 2.11.0 + +* Converts additional platform calls to Pigeon. + ## 2.10.0 * Converts some platform calls to Pigeon. diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java index d128d9544b1..2b52641caa0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/CirclesController.java @@ -4,6 +4,7 @@ package io.flutter.plugins.googlemaps; +import androidx.annotation.NonNull; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.Circle; import com.google.android.gms.maps.model.CircleOptions; @@ -31,31 +32,28 @@ void setGoogleMap(GoogleMap googleMap) { this.googleMap = googleMap; } - void addCircles(List circlesToAdd) { + void addJsonCircles(List circlesToAdd) { if (circlesToAdd != null) { for (Object circleToAdd : circlesToAdd) { - addCircle(circleToAdd); + addJsonCircle(circleToAdd); } } } - void changeCircles(List circlesToChange) { - if (circlesToChange != null) { - for (Object circleToChange : circlesToChange) { - changeCircle(circleToChange); - } + void addCircles(@NonNull List circlesToAdd) { + for (Messages.PlatformCircle circleToAdd : circlesToAdd) { + addJsonCircle(circleToAdd.getJson()); } } - void removeCircles(List circleIdsToRemove) { - if (circleIdsToRemove == null) { - return; + void changeCircles(@NonNull List circlesToChange) { + for (Object circleToChange : circlesToChange) { + changeCircle(circleToChange); } - for (Object rawCircleId : circleIdsToRemove) { - if (rawCircleId == null) { - continue; - } - String circleId = (String) rawCircleId; + } + + void removeCircles(@NonNull List circleIdsToRemove) { + for (String circleId : circleIdsToRemove) { final CircleController circleController = circleIdToController.remove(circleId); if (circleController != null) { circleController.remove(); @@ -77,7 +75,7 @@ boolean onCircleTap(String googleCircleId) { return false; } - private void addCircle(Object circle) { + private void addJsonCircle(Object circle) { if (circle == null) { return; } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/ClusterManagersController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/ClusterManagersController.java index 09ee5d2416f..16666ac0dc3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/ClusterManagersController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/ClusterManagersController.java @@ -79,18 +79,25 @@ private void initListenersForClusterManager( } /** Adds new ClusterManagers to the controller. */ - void addClusterManagers(@NonNull List clusterManagersToAdd) { + void addJsonClusterManagers(@NonNull List clusterManagersToAdd) { for (Object clusterToAdd : clusterManagersToAdd) { - addClusterManager(clusterToAdd); + String clusterManagerId = getClusterManagerId(clusterToAdd); + if (clusterManagerId == null) { + throw new IllegalArgumentException("clusterManagerId was null"); + } + addClusterManager(clusterManagerId); } } - /** Adds new ClusterManager to the controller. */ - void addClusterManager(Object clusterManagerData) { - String clusterManagerId = getClusterManagerId(clusterManagerData); - if (clusterManagerId == null) { - throw new IllegalArgumentException("clusterManagerId was null"); + /** Adds new ClusterManagers to the controller. */ + void addClusterManagers(@NonNull List clusterManagersToAdd) { + for (Messages.PlatformClusterManager clusterToAdd : clusterManagersToAdd) { + addClusterManager(clusterToAdd.getIdentifier()); } + } + + /** Adds new ClusterManager to the controller. */ + void addClusterManager(String clusterManagerId) { ClusterManager clusterManager = new ClusterManager(context, googleMap, markerManager); ClusterRenderer clusterRenderer = @@ -101,12 +108,8 @@ void addClusterManager(Object clusterManagerData) { } /** Removes ClusterManagers by given cluster manager IDs from the controller. */ - public void removeClusterManagers(@NonNull List clusterManagerIdsToRemove) { - for (Object rawClusterManagerId : clusterManagerIdsToRemove) { - if (rawClusterManagerId == null) { - continue; - } - String clusterManagerId = (String) rawClusterManagerId; + public void removeClusterManagers(@NonNull List clusterManagerIdsToRemove) { + for (String clusterManagerId : clusterManagerIdsToRemove) { removeClusterManager(clusterManagerId); } } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java index e1817597f16..71455b668e8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Convert.java @@ -9,9 +9,11 @@ import android.graphics.BitmapFactory; import android.graphics.Point; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.google.android.gms.maps.CameraUpdate; import com.google.android.gms.maps.CameraUpdateFactory; +import com.google.android.gms.maps.MapsInitializer; import com.google.android.gms.maps.model.BitmapDescriptor; import com.google.android.gms.maps.model.BitmapDescriptorFactory; import com.google.android.gms.maps.model.ButtCap; @@ -357,6 +359,20 @@ private static int toInt(Object o) { return ((Number) o).intValue(); } + static @Nullable MapsInitializer.Renderer toMapRendererType( + @Nullable Messages.PlatformRendererType type) { + if (type == null) { + return null; + } + switch (type) { + case LATEST: + return MapsInitializer.Renderer.LATEST; + case LEGACY: + return MapsInitializer.Renderer.LEGACY; + } + return null; + } + static Object cameraPositionToJson(CameraPosition position) { if (position == null) { return null; diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java index e3eee3bc1a7..d2b6b082a27 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapController.java @@ -26,7 +26,6 @@ import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.Lifecycle; import androidx.lifecycle.LifecycleOwner; -import com.google.android.gms.maps.CameraUpdate; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.GoogleMapOptions; import com.google.android.gms.maps.MapView; @@ -45,7 +44,6 @@ import com.google.maps.android.collections.MarkerManager; import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding; import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.platform.PlatformView; import io.flutter.plugins.googlemaps.Messages.FlutterError; @@ -70,7 +68,6 @@ class GoogleMapController GoogleMapOptionsSink, MapsApi, MapsInspectorApi, - MethodChannel.MethodCallHandler, OnMapReadyCallback, PlatformView { @@ -126,7 +123,6 @@ class GoogleMapController this.binaryMessenger = binaryMessenger; methodChannel = new MethodChannel(binaryMessenger, "plugins.flutter.dev/google_maps_android_" + id); - methodChannel.setMethodCallHandler(this); MapsApi.setUp(binaryMessenger, Integer.toString(id), this); MapsInspectorApi.setUp(binaryMessenger, Integer.toString(id), this); AssetManager assetManager = context.getAssets(); @@ -186,14 +182,6 @@ void init() { mapView.getMapAsync(this); } - private void moveCamera(CameraUpdate cameraUpdate) { - googleMap.moveCamera(cameraUpdate); - } - - private void animateCamera(CameraUpdate cameraUpdate) { - googleMap.animateCamera(cameraUpdate); - } - private CameraPosition getCameraPosition() { return trackCameraPosition ? googleMap.getCameraPosition() : null; } @@ -308,104 +296,6 @@ public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) { }); } - @Override - public void onMethodCall(MethodCall call, @NonNull MethodChannel.Result result) { - switch (call.method) { - case "map#update": - { - Convert.interpretGoogleMapOptions(call.argument("options"), this); - result.success(Convert.cameraPositionToJson(getCameraPosition())); - break; - } - case "camera#move": - { - final CameraUpdate cameraUpdate = - Convert.toCameraUpdate(call.argument("cameraUpdate"), density); - moveCamera(cameraUpdate); - result.success(null); - break; - } - case "camera#animate": - { - final CameraUpdate cameraUpdate = - Convert.toCameraUpdate(call.argument("cameraUpdate"), density); - animateCamera(cameraUpdate); - result.success(null); - break; - } - case "markers#update": - { - List markersToAdd = call.argument("markersToAdd"); - markersController.addMarkers(markersToAdd); - List markersToChange = call.argument("markersToChange"); - markersController.changeMarkers(markersToChange); - List markerIdsToRemove = call.argument("markerIdsToRemove"); - markersController.removeMarkers(markerIdsToRemove); - result.success(null); - break; - } - case "clusterManagers#update": - { - List clusterManagersToAdd = call.argument("clusterManagersToAdd"); - if (clusterManagersToAdd != null) { - clusterManagersController.addClusterManagers(clusterManagersToAdd); - } - List clusterManagerIdsToRemove = call.argument("clusterManagerIdsToRemove"); - if (clusterManagerIdsToRemove != null) { - clusterManagersController.removeClusterManagers(clusterManagerIdsToRemove); - } - result.success(null); - break; - } - case "polygons#update": - { - List polygonsToAdd = call.argument("polygonsToAdd"); - polygonsController.addPolygons(polygonsToAdd); - List polygonsToChange = call.argument("polygonsToChange"); - polygonsController.changePolygons(polygonsToChange); - List polygonIdsToRemove = call.argument("polygonIdsToRemove"); - polygonsController.removePolygons(polygonIdsToRemove); - result.success(null); - break; - } - case "polylines#update": - { - List polylinesToAdd = call.argument("polylinesToAdd"); - polylinesController.addPolylines(polylinesToAdd); - List polylinesToChange = call.argument("polylinesToChange"); - polylinesController.changePolylines(polylinesToChange); - List polylineIdsToRemove = call.argument("polylineIdsToRemove"); - polylinesController.removePolylines(polylineIdsToRemove); - result.success(null); - break; - } - case "circles#update": - { - List circlesToAdd = call.argument("circlesToAdd"); - circlesController.addCircles(circlesToAdd); - List circlesToChange = call.argument("circlesToChange"); - circlesController.changeCircles(circlesToChange); - List circleIdsToRemove = call.argument("circleIdsToRemove"); - circlesController.removeCircles(circleIdsToRemove); - result.success(null); - break; - } - case "tileOverlays#update": - { - List> tileOverlaysToAdd = call.argument("tileOverlaysToAdd"); - tileOverlaysController.addTileOverlays(tileOverlaysToAdd); - List> tileOverlaysToChange = call.argument("tileOverlaysToChange"); - tileOverlaysController.changeTileOverlays(tileOverlaysToChange); - List tileOverlaysToRemove = call.argument("tileOverlayIdsToRemove"); - tileOverlaysController.removeTileOverlays(tileOverlaysToRemove); - result.success(null); - break; - } - default: - result.notImplemented(); - } - } - @Override public void onMapClick(@NonNull LatLng latLng) { final Map arguments = new HashMap<>(2); @@ -490,7 +380,6 @@ public void dispose() { return; } disposed = true; - methodChannel.setMethodCallHandler(null); MapsApi.setUp(binaryMessenger, Integer.toString(id), null); MapsInspectorApi.setUp(binaryMessenger, Integer.toString(id), null); setGoogleMapListener(null); @@ -753,7 +642,7 @@ public void setInitialMarkers(Object initialMarkers) { } private void updateInitialMarkers() { - markersController.addMarkers(initialMarkers); + markersController.addJsonMarkers(initialMarkers); } @Override @@ -767,7 +656,7 @@ public void setInitialClusterManagers(Object initialClusterManagers) { private void updateInitialClusterManagers() { if (initialClusterManagers != null) { - clusterManagersController.addClusterManagers(initialClusterManagers); + clusterManagersController.addJsonClusterManagers(initialClusterManagers); } } @@ -781,7 +670,7 @@ public void setInitialPolygons(Object initialPolygons) { } private void updateInitialPolygons() { - polygonsController.addPolygons(initialPolygons); + polygonsController.addJsonPolygons(initialPolygons); } @Override @@ -794,7 +683,7 @@ public void setInitialPolylines(Object initialPolylines) { } private void updateInitialPolylines() { - polylinesController.addPolylines(initialPolylines); + polylinesController.addJsonPolylines(initialPolylines); } @Override @@ -807,7 +696,7 @@ public void setInitialCircles(Object initialCircles) { } private void updateInitialCircles() { - circlesController.addCircles(initialCircles); + circlesController.addJsonCircles(initialCircles); } @Override @@ -819,7 +708,7 @@ public void setInitialTileOverlays(List> initialTileOverlays) { } private void updateInitialTileOverlays() { - tileOverlaysController.addTileOverlays(initialTileOverlays); + tileOverlaysController.addJsonTileOverlays(initialTileOverlays); } @SuppressLint("MissingPermission") @@ -914,6 +803,68 @@ public void waitForMap(@NonNull Messages.VoidResult result) { } } + @Override + public void updateMapConfiguration(@NonNull Messages.PlatformMapConfiguration configuration) { + Convert.interpretGoogleMapOptions(configuration.getJson(), this); + } + + @Override + public void updateCircles( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove) { + circlesController.addCircles(toAdd); + circlesController.changeCircles(toChange); + circlesController.removeCircles(idsToRemove); + } + + @Override + public void updateClusterManagers( + @NonNull List toAdd, @NonNull List idsToRemove) { + clusterManagersController.addClusterManagers(toAdd); + clusterManagersController.removeClusterManagers(idsToRemove); + } + + @Override + public void updateMarkers( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove) { + markersController.addMarkers(toAdd); + markersController.changeMarkers(toChange); + markersController.removeMarkers(idsToRemove); + } + + @Override + public void updatePolygons( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove) { + polygonsController.addPolygons(toAdd); + polygonsController.changePolygons(toChange); + polygonsController.removePolygons(idsToRemove); + } + + @Override + public void updatePolylines( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove) { + polylinesController.addPolylines(toAdd); + polylinesController.changePolylines(toChange); + polylinesController.removePolylines(idsToRemove); + } + + @Override + public void updateTileOverlays( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove) { + tileOverlaysController.addTileOverlays(toAdd); + tileOverlaysController.changeTileOverlays(toChange); + tileOverlaysController.removeTileOverlays(idsToRemove); + } + @Override public @NonNull Messages.PlatformPoint getScreenCoordinate( @NonNull Messages.PlatformLatLng latLng) { @@ -950,6 +901,24 @@ public void waitForMap(@NonNull Messages.VoidResult result) { return Convert.latLngBoundsToPigeon(latLngBounds); } + @Override + public void moveCamera(@NonNull Messages.PlatformCameraUpdate cameraUpdate) { + if (googleMap == null) { + throw new FlutterError( + "GoogleMap uninitialized", "moveCamera called prior to map initialization", null); + } + googleMap.moveCamera(Convert.toCameraUpdate(cameraUpdate.getJson(), density)); + } + + @Override + public void animateCamera(@NonNull Messages.PlatformCameraUpdate cameraUpdate) { + if (googleMap == null) { + throw new FlutterError( + "GoogleMap uninitialized", "animateCamera called prior to map initialization", null); + } + googleMap.animateCamera(Convert.toCameraUpdate(cameraUpdate.getJson(), density)); + } + @Override public @NonNull Double getZoomLevel() { if (googleMap == null) { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java index a113c0a1c4c..e4bea6b8ffa 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/GoogleMapInitializer.java @@ -5,74 +5,39 @@ package io.flutter.plugins.googlemaps; import android.content.Context; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.google.android.gms.maps.MapsInitializer; -import com.google.android.gms.maps.MapsInitializer.Renderer; import com.google.android.gms.maps.OnMapsSdkInitializedCallback; import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; /** GoogleMaps initializer used to initialize the Google Maps SDK with preferred settings. */ final class GoogleMapInitializer - implements OnMapsSdkInitializedCallback, MethodChannel.MethodCallHandler { - private final MethodChannel methodChannel; + implements OnMapsSdkInitializedCallback, Messages.MapsInitializerApi { private final Context context; - private static MethodChannel.Result initializationResult; + private static Messages.Result initializationResult; private boolean rendererInitialized = false; GoogleMapInitializer(Context context, BinaryMessenger binaryMessenger) { this.context = context; - methodChannel = - new MethodChannel(binaryMessenger, "plugins.flutter.dev/google_maps_android_initializer"); - methodChannel.setMethodCallHandler(this); + Messages.MapsInitializerApi.setUp(binaryMessenger, this); } @Override - public void onMethodCall(MethodCall call, MethodChannel.Result result) { - switch (call.method) { - case "initializer#preferRenderer": - { - String preferredRenderer = (String) call.argument("value"); - initializeWithPreferredRenderer(preferredRenderer, result); - break; - } - default: - result.notImplemented(); - } - } - - /** - * Initializes map renderer to with preferred renderer type. Renderer can be initialized only once - * per application context. - * - *

Supported renderer types are "latest", "legacy" and "default". - */ - private void initializeWithPreferredRenderer( - String preferredRenderer, MethodChannel.Result result) { + public void initializeWithPreferredRenderer( + @Nullable Messages.PlatformRendererType type, + @NonNull Messages.Result result) { if (rendererInitialized || initializationResult != null) { result.error( - "Renderer already initialized", "Renderer initialization called multiple times", null); + new Messages.FlutterError( + "Renderer already initialized", + "Renderer initialization called multiple times", + null)); } else { initializationResult = result; - switch (preferredRenderer) { - case "latest": - initializeWithRendererRequest(Renderer.LATEST); - break; - case "legacy": - initializeWithRendererRequest(Renderer.LEGACY); - break; - case "default": - initializeWithRendererRequest(null); - break; - default: - initializationResult.error( - "Invalid renderer type", - "Renderer initialization called with invalid renderer type", - null); - initializationResult = null; - } + initializeWithRendererRequest(Convert.toMapRendererType(type)); } } @@ -83,25 +48,28 @@ private void initializeWithPreferredRenderer( * class. */ @VisibleForTesting - public void initializeWithRendererRequest(MapsInitializer.Renderer renderer) { + public void initializeWithRendererRequest(@Nullable MapsInitializer.Renderer renderer) { MapsInitializer.initialize(context, renderer, this); } /** Is called by Google Maps SDK to determine which version of the renderer was initialized. */ @Override - public void onMapsSdkInitialized(MapsInitializer.Renderer renderer) { + public void onMapsSdkInitialized(@NonNull MapsInitializer.Renderer renderer) { rendererInitialized = true; if (initializationResult != null) { switch (renderer) { case LATEST: - initializationResult.success("latest"); + initializationResult.success(Messages.PlatformRendererType.LATEST); break; case LEGACY: - initializationResult.success("legacy"); + initializationResult.success(Messages.PlatformRendererType.LEGACY); break; default: initializationResult.error( - "Unknown renderer type", "Initialized with unknown renderer type", null); + new Messages.FlutterError( + "Unknown renderer type", + "Initialized with unknown renderer type", + renderer.name())); } initializationResult = null; } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java index 0f47fecaa50..5d870e88081 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/MarkersController.java @@ -5,6 +5,7 @@ package io.flutter.plugins.googlemaps; import android.content.res.AssetManager; +import androidx.annotation.NonNull; import com.google.android.gms.maps.model.LatLng; import com.google.android.gms.maps.model.Marker; import com.google.android.gms.maps.model.MarkerOptions; @@ -43,31 +44,28 @@ void setCollection(MarkerManager.Collection markerCollection) { this.markerCollection = markerCollection; } - void addMarkers(List markersToAdd) { + void addJsonMarkers(List markersToAdd) { if (markersToAdd != null) { for (Object markerToAdd : markersToAdd) { - addMarker(markerToAdd); + addJsonMarker(markerToAdd); } } } - void changeMarkers(List markersToChange) { - if (markersToChange != null) { - for (Object markerToChange : markersToChange) { - changeMarker(markerToChange); - } + void addMarkers(@NonNull List markersToAdd) { + for (Messages.PlatformMarker markerToAdd : markersToAdd) { + addJsonMarker(markerToAdd.getJson()); } } - void removeMarkers(List markerIdsToRemove) { - if (markerIdsToRemove == null) { - return; + void changeMarkers(@NonNull List markersToChange) { + for (Messages.PlatformMarker markerToChange : markersToChange) { + changeJsonMarker(markerToChange.getJson()); } - for (Object rawMarkerId : markerIdsToRemove) { - if (rawMarkerId == null) { - continue; - } - String markerId = (String) rawMarkerId; + } + + void removeMarkers(@NonNull List markerIdsToRemove) { + for (String markerId : markerIdsToRemove) { removeMarker(markerId); } } @@ -188,7 +186,7 @@ public void onClusterItemRendered(MarkerBuilder markerBuilder, Marker marker) { } } - private void addMarker(Object marker) { + private void addJsonMarker(Object marker) { if (marker == null) { return; } @@ -234,7 +232,7 @@ private void createControllerForMarker(String markerId, Marker marker, boolean c googleMapsMarkerIdToDartMarkerId.put(marker.getId(), markerId); } - private void changeMarker(Object marker) { + private void changeJsonMarker(Object marker) { if (marker == null) { return; } @@ -252,7 +250,7 @@ private void changeMarker(Object marker) { // be removed and re-added to update its cluster manager state. if (!(Objects.equals(clusterManagerId, oldClusterManagerId))) { removeMarker(markerId); - addMarker(marker); + addJsonMarker(marker); return; } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java index 5c537c9c3bf..ba47fa72d2c 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/Messages.java @@ -64,6 +64,420 @@ protected static ArrayList wrapError(@NonNull Throwable exception) { @Retention(CLASS) @interface CanIgnoreReturnValue {} + public enum PlatformRendererType { + LEGACY(0), + LATEST(1); + + final int index; + + private PlatformRendererType(final int index) { + this.index = index; + } + } + + /** + * Pigeon representation of a CameraUpdate. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformCameraUpdate { + /** + * The update data, as JSON. This should only be set from CameraUpdate.toJson, and the native + * code must intepret it according to the internal implementation details of the CameraUpdate + * class. + */ + private @NonNull Object json; + + public @NonNull Object getJson() { + return json; + } + + public void setJson(@NonNull Object setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"json\" is null."); + } + this.json = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformCameraUpdate() {} + + public static final class Builder { + + private @Nullable Object json; + + @CanIgnoreReturnValue + public @NonNull Builder setJson(@NonNull Object setterArg) { + this.json = setterArg; + return this; + } + + public @NonNull PlatformCameraUpdate build() { + PlatformCameraUpdate pigeonReturn = new PlatformCameraUpdate(); + pigeonReturn.setJson(json); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(json); + return toListResult; + } + + static @NonNull PlatformCameraUpdate fromList(@NonNull ArrayList __pigeon_list) { + PlatformCameraUpdate pigeonResult = new PlatformCameraUpdate(); + Object json = __pigeon_list.get(0); + pigeonResult.setJson(json); + return pigeonResult; + } + } + + /** + * Pigeon equivalent of the Circle class. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformCircle { + /** + * The circle data, as JSON. This should only be set from Circle.toJson, and the native code + * must intepret it according to the internal implementation details of that method. + */ + private @NonNull Object json; + + public @NonNull Object getJson() { + return json; + } + + public void setJson(@NonNull Object setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"json\" is null."); + } + this.json = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformCircle() {} + + public static final class Builder { + + private @Nullable Object json; + + @CanIgnoreReturnValue + public @NonNull Builder setJson(@NonNull Object setterArg) { + this.json = setterArg; + return this; + } + + public @NonNull PlatformCircle build() { + PlatformCircle pigeonReturn = new PlatformCircle(); + pigeonReturn.setJson(json); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(json); + return toListResult; + } + + static @NonNull PlatformCircle fromList(@NonNull ArrayList __pigeon_list) { + PlatformCircle pigeonResult = new PlatformCircle(); + Object json = __pigeon_list.get(0); + pigeonResult.setJson(json); + return pigeonResult; + } + } + + /** + * Pigeon equivalent of the ClusterManager class. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformClusterManager { + private @NonNull String identifier; + + public @NonNull String getIdentifier() { + return identifier; + } + + public void setIdentifier(@NonNull String setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"identifier\" is null."); + } + this.identifier = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformClusterManager() {} + + public static final class Builder { + + private @Nullable String identifier; + + @CanIgnoreReturnValue + public @NonNull Builder setIdentifier(@NonNull String setterArg) { + this.identifier = setterArg; + return this; + } + + public @NonNull PlatformClusterManager build() { + PlatformClusterManager pigeonReturn = new PlatformClusterManager(); + pigeonReturn.setIdentifier(identifier); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(identifier); + return toListResult; + } + + static @NonNull PlatformClusterManager fromList(@NonNull ArrayList __pigeon_list) { + PlatformClusterManager pigeonResult = new PlatformClusterManager(); + Object identifier = __pigeon_list.get(0); + pigeonResult.setIdentifier((String) identifier); + return pigeonResult; + } + } + + /** + * Pigeon equivalent of the Marker class. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformMarker { + /** + * The marker data, as JSON. This should only be set from Marker.toJson, and the native code + * must intepret it according to the internal implementation details of that method. + */ + private @NonNull Object json; + + public @NonNull Object getJson() { + return json; + } + + public void setJson(@NonNull Object setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"json\" is null."); + } + this.json = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformMarker() {} + + public static final class Builder { + + private @Nullable Object json; + + @CanIgnoreReturnValue + public @NonNull Builder setJson(@NonNull Object setterArg) { + this.json = setterArg; + return this; + } + + public @NonNull PlatformMarker build() { + PlatformMarker pigeonReturn = new PlatformMarker(); + pigeonReturn.setJson(json); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(json); + return toListResult; + } + + static @NonNull PlatformMarker fromList(@NonNull ArrayList __pigeon_list) { + PlatformMarker pigeonResult = new PlatformMarker(); + Object json = __pigeon_list.get(0); + pigeonResult.setJson(json); + return pigeonResult; + } + } + + /** + * Pigeon equivalent of the Polygon class. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformPolygon { + /** + * The polygon data, as JSON. This should only be set from Polygon.toJson, and the native code + * must intepret it according to the internal implementation details of that method. + */ + private @NonNull Object json; + + public @NonNull Object getJson() { + return json; + } + + public void setJson(@NonNull Object setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"json\" is null."); + } + this.json = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformPolygon() {} + + public static final class Builder { + + private @Nullable Object json; + + @CanIgnoreReturnValue + public @NonNull Builder setJson(@NonNull Object setterArg) { + this.json = setterArg; + return this; + } + + public @NonNull PlatformPolygon build() { + PlatformPolygon pigeonReturn = new PlatformPolygon(); + pigeonReturn.setJson(json); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(json); + return toListResult; + } + + static @NonNull PlatformPolygon fromList(@NonNull ArrayList __pigeon_list) { + PlatformPolygon pigeonResult = new PlatformPolygon(); + Object json = __pigeon_list.get(0); + pigeonResult.setJson(json); + return pigeonResult; + } + } + + /** + * Pigeon equivalent of the Polyline class. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformPolyline { + /** + * The polyline data, as JSON. This should only be set from Polyline.toJson, and the native code + * must intepret it according to the internal implementation details of that method. + */ + private @NonNull Object json; + + public @NonNull Object getJson() { + return json; + } + + public void setJson(@NonNull Object setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"json\" is null."); + } + this.json = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformPolyline() {} + + public static final class Builder { + + private @Nullable Object json; + + @CanIgnoreReturnValue + public @NonNull Builder setJson(@NonNull Object setterArg) { + this.json = setterArg; + return this; + } + + public @NonNull PlatformPolyline build() { + PlatformPolyline pigeonReturn = new PlatformPolyline(); + pigeonReturn.setJson(json); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(json); + return toListResult; + } + + static @NonNull PlatformPolyline fromList(@NonNull ArrayList __pigeon_list) { + PlatformPolyline pigeonResult = new PlatformPolyline(); + Object json = __pigeon_list.get(0); + pigeonResult.setJson(json); + return pigeonResult; + } + } + + /** + * Pigeon equivalent of the TileOverlay class. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformTileOverlay { + /** + * The tile overlay data, as JSON. This should only be set from TileOverlay.toJson, and the + * native code must intepret it according to the internal implementation details of that method. + */ + private @NonNull Object json; + + public @NonNull Object getJson() { + return json; + } + + public void setJson(@NonNull Object setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"json\" is null."); + } + this.json = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformTileOverlay() {} + + public static final class Builder { + + private @Nullable Object json; + + @CanIgnoreReturnValue + public @NonNull Builder setJson(@NonNull Object setterArg) { + this.json = setterArg; + return this; + } + + public @NonNull PlatformTileOverlay build() { + PlatformTileOverlay pigeonReturn = new PlatformTileOverlay(); + pigeonReturn.setJson(json); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(json); + return toListResult; + } + + static @NonNull PlatformTileOverlay fromList(@NonNull ArrayList __pigeon_list) { + PlatformTileOverlay pigeonResult = new PlatformTileOverlay(); + Object json = __pigeon_list.get(0); + pigeonResult.setJson(json); + return pigeonResult; + } + } + /** * Pigeon equivalent of LatLng. * @@ -351,6 +765,65 @@ ArrayList toList() { } } + /** + * Pigeon equivalent of MapConfiguration. + * + *

Generated class from Pigeon that represents data sent in messages. + */ + public static final class PlatformMapConfiguration { + /** + * The configuration options, as JSON. This should only be set from _jsonForMapConfiguration, + * and the native code must intepret it according to the internal implementation details of that + * method. + */ + private @NonNull Object json; + + public @NonNull Object getJson() { + return json; + } + + public void setJson(@NonNull Object setterArg) { + if (setterArg == null) { + throw new IllegalStateException("Nonnull field \"json\" is null."); + } + this.json = setterArg; + } + + /** Constructor is non-public to enforce null safety; use Builder. */ + PlatformMapConfiguration() {} + + public static final class Builder { + + private @Nullable Object json; + + @CanIgnoreReturnValue + public @NonNull Builder setJson(@NonNull Object setterArg) { + this.json = setterArg; + return this; + } + + public @NonNull PlatformMapConfiguration build() { + PlatformMapConfiguration pigeonReturn = new PlatformMapConfiguration(); + pigeonReturn.setJson(json); + return pigeonReturn; + } + } + + @NonNull + ArrayList toList() { + ArrayList toListResult = new ArrayList(1); + toListResult.add(json); + return toListResult; + } + + static @NonNull PlatformMapConfiguration fromList(@NonNull ArrayList __pigeon_list) { + PlatformMapConfiguration pigeonResult = new PlatformMapConfiguration(); + Object json = __pigeon_list.get(0); + pigeonResult.setJson(json); + return pigeonResult; + } + } + /** * Pigeon representation of an x,y coordinate. * @@ -647,17 +1120,36 @@ private PigeonCodec() {} protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { switch (type) { case (byte) 129: - return PlatformLatLng.fromList((ArrayList) readValue(buffer)); + return PlatformCameraUpdate.fromList((ArrayList) readValue(buffer)); case (byte) 130: - return PlatformLatLngBounds.fromList((ArrayList) readValue(buffer)); + return PlatformCircle.fromList((ArrayList) readValue(buffer)); case (byte) 131: - return PlatformCluster.fromList((ArrayList) readValue(buffer)); + return PlatformClusterManager.fromList((ArrayList) readValue(buffer)); case (byte) 132: - return PlatformPoint.fromList((ArrayList) readValue(buffer)); + return PlatformMarker.fromList((ArrayList) readValue(buffer)); case (byte) 133: - return PlatformTileLayer.fromList((ArrayList) readValue(buffer)); + return PlatformPolygon.fromList((ArrayList) readValue(buffer)); case (byte) 134: + return PlatformPolyline.fromList((ArrayList) readValue(buffer)); + case (byte) 135: + return PlatformTileOverlay.fromList((ArrayList) readValue(buffer)); + case (byte) 136: + return PlatformLatLng.fromList((ArrayList) readValue(buffer)); + case (byte) 137: + return PlatformLatLngBounds.fromList((ArrayList) readValue(buffer)); + case (byte) 138: + return PlatformCluster.fromList((ArrayList) readValue(buffer)); + case (byte) 139: + return PlatformMapConfiguration.fromList((ArrayList) readValue(buffer)); + case (byte) 140: + return PlatformPoint.fromList((ArrayList) readValue(buffer)); + case (byte) 141: + return PlatformTileLayer.fromList((ArrayList) readValue(buffer)); + case (byte) 142: return PlatformZoomRange.fromList((ArrayList) readValue(buffer)); + case (byte) 143: + Object value = readValue(buffer); + return value == null ? null : PlatformRendererType.values()[(int) value]; default: return super.readValueOfType(type, buffer); } @@ -665,24 +1157,51 @@ protected Object readValueOfType(byte type, @NonNull ByteBuffer buffer) { @Override protected void writeValue(@NonNull ByteArrayOutputStream stream, Object value) { - if (value instanceof PlatformLatLng) { + if (value instanceof PlatformCameraUpdate) { stream.write(129); + writeValue(stream, ((PlatformCameraUpdate) value).toList()); + } else if (value instanceof PlatformCircle) { + stream.write(130); + writeValue(stream, ((PlatformCircle) value).toList()); + } else if (value instanceof PlatformClusterManager) { + stream.write(131); + writeValue(stream, ((PlatformClusterManager) value).toList()); + } else if (value instanceof PlatformMarker) { + stream.write(132); + writeValue(stream, ((PlatformMarker) value).toList()); + } else if (value instanceof PlatformPolygon) { + stream.write(133); + writeValue(stream, ((PlatformPolygon) value).toList()); + } else if (value instanceof PlatformPolyline) { + stream.write(134); + writeValue(stream, ((PlatformPolyline) value).toList()); + } else if (value instanceof PlatformTileOverlay) { + stream.write(135); + writeValue(stream, ((PlatformTileOverlay) value).toList()); + } else if (value instanceof PlatformLatLng) { + stream.write(136); writeValue(stream, ((PlatformLatLng) value).toList()); } else if (value instanceof PlatformLatLngBounds) { - stream.write(130); + stream.write(137); writeValue(stream, ((PlatformLatLngBounds) value).toList()); } else if (value instanceof PlatformCluster) { - stream.write(131); + stream.write(138); writeValue(stream, ((PlatformCluster) value).toList()); + } else if (value instanceof PlatformMapConfiguration) { + stream.write(139); + writeValue(stream, ((PlatformMapConfiguration) value).toList()); } else if (value instanceof PlatformPoint) { - stream.write(132); + stream.write(140); writeValue(stream, ((PlatformPoint) value).toList()); } else if (value instanceof PlatformTileLayer) { - stream.write(133); + stream.write(141); writeValue(stream, ((PlatformTileLayer) value).toList()); } else if (value instanceof PlatformZoomRange) { - stream.write(134); + stream.write(142); writeValue(stream, ((PlatformZoomRange) value).toList()); + } else if (value instanceof PlatformRendererType) { + stream.write(143); + writeValue(stream, value == null ? null : ((PlatformRendererType) value).index); } else { super.writeValue(stream, value); } @@ -723,6 +1242,41 @@ public interface VoidResult { public interface MapsApi { /** Returns once the map instance is available. */ void waitForMap(@NonNull VoidResult result); + /** + * Updates the map's configuration options. + * + *

Only non-null configuration values will result in updates; options with null values will + * remain unchanged. + */ + void updateMapConfiguration(@NonNull PlatformMapConfiguration configuration); + /** Updates the set of circles on the map. */ + void updateCircles( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove); + /** Updates the set of custer managers for clusters on the map. */ + void updateClusterManagers( + @NonNull List toAdd, @NonNull List idsToRemove); + /** Updates the set of markers on the map. */ + void updateMarkers( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove); + /** Updates the set of polygonss on the map. */ + void updatePolygons( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove); + /** Updates the set of polylines on the map. */ + void updatePolylines( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove); + /** Updates the set of tile overlays on the map. */ + void updateTileOverlays( + @NonNull List toAdd, + @NonNull List toChange, + @NonNull List idsToRemove); /** Gets the screen coordinate for the given map location. */ @NonNull PlatformPoint getScreenCoordinate(@NonNull PlatformLatLng latLng); @@ -732,6 +1286,10 @@ public interface MapsApi { /** Gets the map region currently displayed on the map. */ @NonNull PlatformLatLngBounds getVisibleRegion(); + /** Moves the camera according to [cameraUpdate] immediately, with no animation. */ + void moveCamera(@NonNull PlatformCameraUpdate cameraUpdate); + /** Moves the camera according to [cameraUpdate], animating the update. */ + void animateCamera(@NonNull PlatformCameraUpdate cameraUpdate); /** Gets the current map zoom level. */ @NonNull Double getZoomLevel(); @@ -808,6 +1366,199 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateMapConfiguration" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PlatformMapConfiguration configurationArg = (PlatformMapConfiguration) args.get(0); + try { + api.updateMapConfiguration(configurationArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateCircles" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + List toAddArg = (List) args.get(0); + List toChangeArg = (List) args.get(1); + List idsToRemoveArg = (List) args.get(2); + try { + api.updateCircles(toAddArg, toChangeArg, idsToRemoveArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateClusterManagers" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + List toAddArg = (List) args.get(0); + List idsToRemoveArg = (List) args.get(1); + try { + api.updateClusterManagers(toAddArg, idsToRemoveArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateMarkers" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + List toAddArg = (List) args.get(0); + List toChangeArg = (List) args.get(1); + List idsToRemoveArg = (List) args.get(2); + try { + api.updateMarkers(toAddArg, toChangeArg, idsToRemoveArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updatePolygons" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + List toAddArg = (List) args.get(0); + List toChangeArg = (List) args.get(1); + List idsToRemoveArg = (List) args.get(2); + try { + api.updatePolygons(toAddArg, toChangeArg, idsToRemoveArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updatePolylines" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + List toAddArg = (List) args.get(0); + List toChangeArg = (List) args.get(1); + List idsToRemoveArg = (List) args.get(2); + try { + api.updatePolylines(toAddArg, toChangeArg, idsToRemoveArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateTileOverlays" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + List toAddArg = (List) args.get(0); + List toChangeArg = (List) args.get(1); + List idsToRemoveArg = (List) args.get(2); + try { + api.updateTileOverlays(toAddArg, toChangeArg, idsToRemoveArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( @@ -884,6 +1635,58 @@ public void error(Throwable error) { channel.setMessageHandler(null); } } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.moveCamera" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PlatformCameraUpdate cameraUpdateArg = (PlatformCameraUpdate) args.get(0); + try { + api.moveCamera(cameraUpdateArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsApi.animateCamera" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PlatformCameraUpdate cameraUpdateArg = (PlatformCameraUpdate) args.get(0); + try { + api.animateCamera(cameraUpdateArg); + wrapped.add(0, null); + } catch (Throwable exception) { + ArrayList wrappedError = wrapError(exception); + wrapped = wrappedError; + } + reply.reply(wrapped); + }); + } else { + channel.setMessageHandler(null); + } + } { BasicMessageChannel channel = new BasicMessageChannel<>( @@ -1094,6 +1897,72 @@ public void error(Throwable error) { } } } + /** + * Interface for global SDK initialization. + * + *

Generated interface from Pigeon that represents a handler of messages from Flutter. + */ + public interface MapsInitializerApi { + /** + * Initializes the Google Maps SDK with the given renderer preference. + * + *

A null renderer preference will result in the default renderer. + * + *

Calling this more than once in the lifetime of an application will result in an error. + */ + void initializeWithPreferredRenderer( + @Nullable PlatformRendererType type, @NonNull Result result); + + /** The codec used by MapsInitializerApi. */ + static @NonNull MessageCodec getCodec() { + return PigeonCodec.INSTANCE; + } + /** + * Sets up an instance of `MapsInitializerApi` to handle messages through the `binaryMessenger`. + */ + static void setUp(@NonNull BinaryMessenger binaryMessenger, @Nullable MapsInitializerApi api) { + setUp(binaryMessenger, "", api); + } + + static void setUp( + @NonNull BinaryMessenger binaryMessenger, + @NonNull String messageChannelSuffix, + @Nullable MapsInitializerApi api) { + messageChannelSuffix = messageChannelSuffix.isEmpty() ? "" : "." + messageChannelSuffix; + { + BasicMessageChannel channel = + new BasicMessageChannel<>( + binaryMessenger, + "dev.flutter.pigeon.google_maps_flutter_android.MapsInitializerApi.initializeWithPreferredRenderer" + + messageChannelSuffix, + getCodec()); + if (api != null) { + channel.setMessageHandler( + (message, reply) -> { + ArrayList wrapped = new ArrayList(); + ArrayList args = (ArrayList) message; + PlatformRendererType typeArg = (PlatformRendererType) args.get(0); + Result resultCallback = + new Result() { + public void success(PlatformRendererType result) { + wrapped.add(0, result); + reply.reply(wrapped); + } + + public void error(Throwable error) { + ArrayList wrappedError = wrapError(error); + reply.reply(wrappedError); + } + }; + + api.initializeWithPreferredRenderer(typeArg, resultCallback); + }); + } else { + channel.setMessageHandler(null); + } + } + } + } /** * Inspector API only intended for use in integration tests. * diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java index 6f855db0799..a68e3e89ea8 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolygonsController.java @@ -4,6 +4,7 @@ package io.flutter.plugins.googlemaps; +import androidx.annotation.NonNull; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.Polygon; import com.google.android.gms.maps.model.PolygonOptions; @@ -31,31 +32,28 @@ void setGoogleMap(GoogleMap googleMap) { this.googleMap = googleMap; } - void addPolygons(List polygonsToAdd) { + void addJsonPolygons(List polygonsToAdd) { if (polygonsToAdd != null) { for (Object polygonToAdd : polygonsToAdd) { - addPolygon(polygonToAdd); + addJsonPolygon(polygonToAdd); } } } - void changePolygons(List polygonsToChange) { - if (polygonsToChange != null) { - for (Object polygonToChange : polygonsToChange) { - changePolygon(polygonToChange); - } + void addPolygons(@NonNull List polygonsToAdd) { + for (Messages.PlatformPolygon polygonToAdd : polygonsToAdd) { + addJsonPolygon(polygonToAdd.getJson()); } } - void removePolygons(List polygonIdsToRemove) { - if (polygonIdsToRemove == null) { - return; + void changePolygons(@NonNull List polygonsToChange) { + for (Messages.PlatformPolygon polygonToChange : polygonsToChange) { + changeJsonPolygon(polygonToChange.getJson()); } - for (Object rawPolygonId : polygonIdsToRemove) { - if (rawPolygonId == null) { - continue; - } - String polygonId = (String) rawPolygonId; + } + + void removePolygons(@NonNull List polygonIdsToRemove) { + for (String polygonId : polygonIdsToRemove) { final PolygonController polygonController = polygonIdToController.remove(polygonId); if (polygonController != null) { polygonController.remove(); @@ -77,7 +75,7 @@ boolean onPolygonTap(String googlePolygonId) { return false; } - private void addPolygon(Object polygon) { + private void addJsonPolygon(Object polygon) { if (polygon == null) { return; } @@ -95,7 +93,7 @@ private void addPolygon( googleMapsPolygonIdToDartPolygonId.put(polygon.getId(), polygonId); } - private void changePolygon(Object polygon) { + private void changeJsonPolygon(Object polygon) { if (polygon == null) { return; } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java index 2dbad98fcfe..043474d3dc3 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/PolylinesController.java @@ -5,6 +5,7 @@ package io.flutter.plugins.googlemaps; import android.content.res.AssetManager; +import androidx.annotation.NonNull; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.Polyline; import com.google.android.gms.maps.model.PolylineOptions; @@ -34,31 +35,28 @@ void setGoogleMap(GoogleMap googleMap) { this.googleMap = googleMap; } - void addPolylines(List polylinesToAdd) { + void addJsonPolylines(List polylinesToAdd) { if (polylinesToAdd != null) { for (Object polylineToAdd : polylinesToAdd) { - addPolyline(polylineToAdd); + addJsonPolyline(polylineToAdd); } } } - void changePolylines(List polylinesToChange) { - if (polylinesToChange != null) { - for (Object polylineToChange : polylinesToChange) { - changePolyline(polylineToChange); - } + void addPolylines(@NonNull List polylinesToAdd) { + for (Messages.PlatformPolyline polylineToAdd : polylinesToAdd) { + addJsonPolyline(polylineToAdd.getJson()); } } - void removePolylines(List polylineIdsToRemove) { - if (polylineIdsToRemove == null) { - return; + void changePolylines(@NonNull List polylinesToChange) { + for (Messages.PlatformPolyline polylineToChange : polylinesToChange) { + changeJsonPolyline(polylineToChange.getJson()); } - for (Object rawPolylineId : polylineIdsToRemove) { - if (rawPolylineId == null) { - continue; - } - String polylineId = (String) rawPolylineId; + } + + void removePolylines(@NonNull List polylineIdsToRemove) { + for (String polylineId : polylineIdsToRemove) { final PolylineController polylineController = polylineIdToController.remove(polylineId); if (polylineController != null) { polylineController.remove(); @@ -80,7 +78,7 @@ boolean onPolylineTap(String googlePolylineId) { return false; } - private void addPolyline(Object polyline) { + private void addJsonPolyline(Object polyline) { if (polyline == null) { return; } @@ -99,7 +97,7 @@ private void addPolyline( googleMapsPolylineIdToDartPolylineId.put(polyline.getId(), polylineId); } - private void changePolyline(Object polyline) { + private void changeJsonPolyline(Object polyline) { if (polyline == null) { return; } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java index 52b9d1e6bc9..5dfbe2e8ee1 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/main/java/io/flutter/plugins/googlemaps/TileOverlaysController.java @@ -4,6 +4,7 @@ package io.flutter.plugins.googlemaps; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.google.android.gms.maps.GoogleMap; import com.google.android.gms.maps.model.TileOverlay; @@ -28,21 +29,28 @@ void setGoogleMap(GoogleMap googleMap) { this.googleMap = googleMap; } - void addTileOverlays(List> tileOverlaysToAdd) { + void addJsonTileOverlays(List> tileOverlaysToAdd) { if (tileOverlaysToAdd == null) { return; } for (Map tileOverlayToAdd : tileOverlaysToAdd) { - addTileOverlay(tileOverlayToAdd); + addJsonTileOverlay(tileOverlayToAdd); } } - void changeTileOverlays(List> tileOverlaysToChange) { - if (tileOverlaysToChange == null) { - return; + void addTileOverlays(@NonNull List tileOverlaysToAdd) { + for (Messages.PlatformTileOverlay tileOverlayToAdd : tileOverlaysToAdd) { + @SuppressWarnings("unchecked") + final Map overlayJson = (Map) tileOverlayToAdd.getJson(); + addJsonTileOverlay(overlayJson); } - for (Map tileOverlayToChange : tileOverlaysToChange) { - changeTileOverlay(tileOverlayToChange); + } + + void changeTileOverlays(@NonNull List tileOverlaysToChange) { + for (Messages.PlatformTileOverlay tileOverlayToChange : tileOverlaysToChange) { + @SuppressWarnings("unchecked") + final Map overlayJson = (Map) tileOverlayToChange.getJson(); + changeJsonTileOverlay(overlayJson); } } @@ -80,7 +88,7 @@ TileOverlay getTileOverlay(String tileOverlayId) { return tileOverlayController.getTileOverlay(); } - private void addTileOverlay(Map tileOverlayOptions) { + private void addJsonTileOverlay(Map tileOverlayOptions) { if (tileOverlayOptions == null) { return; } @@ -96,7 +104,7 @@ private void addTileOverlay(Map tileOverlayOptions) { tileOverlayIdToController.put(tileOverlayId, tileOverlayController); } - private void changeTileOverlay(Map tileOverlayOptions) { + private void changeJsonTileOverlay(Map tileOverlayOptions) { if (tileOverlayOptions == null) { return; } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ClusterManagersControllerTest.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ClusterManagersControllerTest.java index bc80627c35f..aaa50542e7f 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ClusterManagersControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/ClusterManagersControllerTest.java @@ -68,7 +68,7 @@ public void setUp() { @Test @SuppressWarnings("unchecked") - public void AddClusterManagersAndMarkers() throws InterruptedException { + public void AddJsonClusterManagersAndMarkers() throws InterruptedException { final String clusterManagerId = "cm_1"; final String markerId1 = "mid_1"; final String markerId2 = "mid_2"; @@ -90,6 +90,61 @@ public void AddClusterManagersAndMarkers() throws InterruptedException { initialClusterManager.put("clusterManagerId", clusterManagerId); List clusterManagersToAdd = new ArrayList<>(); clusterManagersToAdd.add(initialClusterManager); + controller.addJsonClusterManagers(clusterManagersToAdd); + + MarkerBuilder markerBuilder1 = new MarkerBuilder(markerId1, clusterManagerId); + MarkerBuilder markerBuilder2 = new MarkerBuilder(markerId2, clusterManagerId); + + final Map markerData1 = + createMarkerData(markerId1, location1, clusterManagerId); + final Map markerData2 = + createMarkerData(markerId2, location2, clusterManagerId); + + Convert.interpretMarkerOptions(markerData1, markerBuilder1, assetManager, density); + Convert.interpretMarkerOptions(markerData2, markerBuilder2, assetManager, density); + + controller.addItem(markerBuilder1); + controller.addItem(markerBuilder2); + + Set> clusters = + controller.getClustersWithClusterManagerId(clusterManagerId); + assertEquals("Amount of clusters should be 1", 1, clusters.size()); + + Cluster cluster = clusters.iterator().next(); + assertNotNull("Cluster position should not be null", cluster.getPosition()); + Set markerIds = new HashSet<>(); + for (MarkerBuilder marker : cluster.getItems()) { + markerIds.add(marker.markerId()); + } + assertTrue("Marker IDs should contain markerId1", markerIds.contains(markerId1)); + assertTrue("Marker IDs should contain markerId2", markerIds.contains(markerId2)); + assertEquals("Cluster should contain exactly 2 markers", 2, cluster.getSize()); + } + + @Test + @SuppressWarnings("unchecked") + public void AddClusterManagersAndMarkers() throws InterruptedException { + final String clusterManagerId = "cm_1"; + final String markerId1 = "mid_1"; + final String markerId2 = "mid_2"; + + final LatLng latLng1 = new LatLng(1.1, 2.2); + final LatLng latLng2 = new LatLng(3.3, 4.4); + + final List location1 = new ArrayList<>(); + location1.add(latLng1.latitude); + location1.add(latLng1.longitude); + + final List location2 = new ArrayList<>(); + location2.add(latLng2.latitude); + location2.add(latLng2.longitude); + + when(googleMap.getCameraPosition()) + .thenReturn(CameraPosition.builder().target(new LatLng(0, 0)).build()); + Messages.PlatformClusterManager initialClusterManager = + new Messages.PlatformClusterManager.Builder().setIdentifier(clusterManagerId).build(); + List clusterManagersToAdd = new ArrayList<>(); + clusterManagersToAdd.add(initialClusterManager); controller.addClusterManagers(clusterManagersToAdd); MarkerBuilder markerBuilder1 = new MarkerBuilder(markerId1, clusterManagerId); @@ -150,9 +205,9 @@ public void RemoveClusterManagers() { when(googleMap.getCameraPosition()) .thenReturn(CameraPosition.builder().target(new LatLng(0, 0)).build()); - Map initialClusterManager = new HashMap<>(); - initialClusterManager.put("clusterManagerId", clusterManagerId); - List clusterManagersToAdd = new ArrayList<>(); + Messages.PlatformClusterManager initialClusterManager = + new Messages.PlatformClusterManager.Builder().setIdentifier(clusterManagerId).build(); + List clusterManagersToAdd = new ArrayList<>(); clusterManagersToAdd.add(initialClusterManager); controller.addClusterManagers(clusterManagersToAdd); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java index 3459b9b3139..f68ab346077 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapControllerTest.java @@ -203,7 +203,7 @@ public void SetInitialClusterManagers() { googleMapController.onMapReady(mockGoogleMap); // Verify if the ClusterManagersController.addClusterManagers method is called with initial cluster managers. - verify(mockClusterManagersController, times(1)).addClusterManagers(any()); + verify(mockClusterManagersController, times(1)).addJsonClusterManagers(any()); } @Test diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapInitializerTest.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapInitializerTest.java index 2f9f5e5619f..374964cbad6 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapInitializerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/GoogleMapInitializerTest.java @@ -6,7 +6,6 @@ import static org.mockito.Mockito.any; import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -18,9 +17,6 @@ import androidx.test.core.app.ApplicationProvider; import com.google.android.gms.maps.MapsInitializer.Renderer; import io.flutter.plugin.common.BinaryMessenger; -import io.flutter.plugin.common.MethodCall; -import io.flutter.plugin.common.MethodChannel; -import java.util.HashMap; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -46,53 +42,33 @@ public void before() { @Test public void initializer_OnMapsSdkInitializedWithLatestRenderer() { doNothing().when(googleMapInitializer).initializeWithRendererRequest(Renderer.LATEST); - MethodChannel.Result result = mock(MethodChannel.Result.class); - googleMapInitializer.onMethodCall( - new MethodCall( - "initializer#preferRenderer", - new HashMap() { - { - put("value", "latest"); - } - }), - result); + @SuppressWarnings("unchecked") + Messages.Result result = mock(Messages.Result.class); + googleMapInitializer.initializeWithPreferredRenderer( + Messages.PlatformRendererType.LATEST, result); googleMapInitializer.onMapsSdkInitialized(Renderer.LATEST); - verify(result, times(1)).success("latest"); - verify(result, never()).error(any(), any(), any()); + verify(result, times(1)).success(Messages.PlatformRendererType.LATEST); + verify(result, never()).error(any()); } @Test public void initializer_OnMapsSdkInitializedWithLegacyRenderer() { doNothing().when(googleMapInitializer).initializeWithRendererRequest(Renderer.LEGACY); - MethodChannel.Result result = mock(MethodChannel.Result.class); - googleMapInitializer.onMethodCall( - new MethodCall( - "initializer#preferRenderer", - new HashMap() { - { - put("value", "legacy"); - } - }), - result); + @SuppressWarnings("unchecked") + Messages.Result result = mock(Messages.Result.class); + googleMapInitializer.initializeWithPreferredRenderer( + Messages.PlatformRendererType.LEGACY, result); googleMapInitializer.onMapsSdkInitialized(Renderer.LEGACY); - verify(result, times(1)).success("legacy"); - verify(result, never()).error(any(), any(), any()); + verify(result, times(1)).success(Messages.PlatformRendererType.LEGACY); + verify(result, never()).error(any()); } @Test - public void initializer_onMethodCallWithUnknownRenderer() { - doNothing().when(googleMapInitializer).initializeWithRendererRequest(Renderer.LEGACY); - MethodChannel.Result result = mock(MethodChannel.Result.class); - googleMapInitializer.onMethodCall( - new MethodCall( - "initializer#preferRenderer", - new HashMap() { - { - put("value", "wrong_renderer"); - } - }), - result); - verify(result, never()).success(any()); - verify(result, times(1)).error(eq("Invalid renderer type"), any(), any()); + public void initializer_onMethodCallWithNoRendererPreference() { + doNothing().when(googleMapInitializer).initializeWithRendererRequest(null); + @SuppressWarnings("unchecked") + Messages.Result result = mock(Messages.Result.class); + googleMapInitializer.initializeWithPreferredRenderer(null, result); + verify(result, never()).error(any()); } } diff --git a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/MarkersControllerTest.java b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/MarkersControllerTest.java index 116f8381bce..41444d9f290 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/MarkersControllerTest.java +++ b/packages/google_maps_flutter/google_maps_flutter_android/android/src/test/java/io/flutter/plugins/googlemaps/MarkersControllerTest.java @@ -25,6 +25,7 @@ import io.flutter.plugin.common.MethodCodec; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -81,7 +82,7 @@ public void controller_OnMarkerDragStart() { markerOptions.put("markerId", googleMarkerId); final List markers = Arrays.asList(markerOptions); - controller.addMarkers(markers); + controller.addJsonMarkers(markers); controller.onMarkerDragStart(googleMarkerId, latLng); final List points = new ArrayList<>(); @@ -108,7 +109,7 @@ public void controller_OnMarkerDragEnd() { markerOptions.put("markerId", googleMarkerId); final List markers = Arrays.asList(markerOptions); - controller.addMarkers(markers); + controller.addJsonMarkers(markers); controller.onMarkerDragEnd(googleMarkerId, latLng); final List points = new ArrayList<>(); @@ -135,7 +136,7 @@ public void controller_OnMarkerDrag() { markerOptions.put("markerId", googleMarkerId); final List markers = Arrays.asList(markerOptions); - controller.addMarkers(markers); + controller.addJsonMarkers(markers); controller.onMarkerDrag(googleMarkerId, latLng); final List points = new ArrayList<>(); @@ -154,7 +155,7 @@ public void controller_AddMarkerThrowsErrorIfMarkerIdIsNull() { final List markers = Arrays.asList(markerOptions); try { - controller.addMarkers(markers); + controller.addJsonMarkers(markers); } catch (IllegalArgumentException e) { assertEquals("markerId was null", e.getMessage()); throw e; @@ -183,7 +184,7 @@ public void controller_AddChangeAndRemoveMarkerWithClusterManagerId() { final List markers = Arrays.asList(markerOptions1); // Add marker and capture the markerBuilder - controller.addMarkers(markers); + controller.addJsonMarkers(markers); ArgumentCaptor captor = ArgumentCaptor.forClass(MarkerBuilder.class); Mockito.verify(clusterManagersController, times(1)).addItem(captor.capture()); MarkerBuilder capturedMarkerBuilder = captor.getValue(); @@ -202,7 +203,9 @@ public void controller_AddChangeAndRemoveMarkerWithClusterManagerId() { markerOptions2.put("markerId", googleMarkerId); markerOptions2.put("position", location2); markerOptions2.put("clusterManagerId", clusterManagerId); - final List updatedMarkers = Arrays.asList(markerOptions2); + final List updatedMarkers = + Collections.singletonList( + new Messages.PlatformMarker.Builder().setJson(markerOptions2).build()); controller.changeMarkers(updatedMarkers); Mockito.verify(marker, times(1)).setPosition(latLng2); @@ -232,7 +235,7 @@ public void controller_AddChangeAndRemoveMarkerWithoutClusterManagerId() { markerOptions1.put("markerId", googleMarkerId); final List markers = Arrays.asList(markerOptions1); - controller.addMarkers(markers); + controller.addJsonMarkers(markers); // clusterManagersController should not be called when adding the marker Mockito.verify(clusterManagersController, times(0)).addItem(any()); @@ -244,7 +247,9 @@ public void controller_AddChangeAndRemoveMarkerWithoutClusterManagerId() { markerOptions2.put("markerId", googleMarkerId); markerOptions2.put("alpha", alpha); - final List markerUpdates = Arrays.asList(markerOptions2); + final List markerUpdates = + Collections.singletonList( + new Messages.PlatformMarker.Builder().setJson(markerOptions2).build()); controller.changeMarkers(markerUpdates); Mockito.verify(marker, times(1)).setAlpha(alpha); diff --git a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart index 0664ae3accd..3b77fa91480 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/google_maps_flutter_android.dart @@ -70,10 +70,6 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { GoogleMapsFlutterPlatform.instance = GoogleMapsFlutterAndroid(); } - /// The method channel used to initialize the native Google Maps SDK. - final MethodChannel _initializerChannel = const MethodChannel( - 'plugins.flutter.dev/google_maps_android_initializer'); - // Keep a collection of id -> channel // Every method call passes the int mapId final Map _channels = {}; @@ -83,15 +79,6 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { // A method to create MapsApi instances, which can be overridden for testing. final MapsApi Function(int mapId) _apiProvider; - /// Accesses the MethodChannel associated to the passed mapId. - MethodChannel _channel(int mapId) { - final MethodChannel? channel = _channels[mapId]; - if (channel == null) { - throw UnknownMapIDError(mapId); - } - return channel; - } - /// Accesses the MapsApi associated to the passed mapId. MapsApi _hostApi(int mapId) { final MapsApi? api = _hostMaps[mapId]; @@ -341,17 +328,22 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { return (call.arguments as Map).cast(); } + @override + Future updateMapConfiguration( + MapConfiguration configuration, { + required int mapId, + }) { + return updateMapOptions(_jsonForMapConfiguration(configuration), + mapId: mapId); + } + @override Future updateMapOptions( Map optionsUpdate, { required int mapId, }) { - return _channel(mapId).invokeMethod( - 'map#update', - { - 'options': optionsUpdate, - }, - ); + return _hostApi(mapId) + .updateMapConfiguration(PlatformMapConfiguration(json: optionsUpdate)); } @override @@ -359,9 +351,10 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { MarkerUpdates markerUpdates, { required int mapId, }) { - return _channel(mapId).invokeMethod( - 'markers#update', - markerUpdates.toJson(), + return _hostApi(mapId).updateMarkers( + markerUpdates.markersToAdd.map(_platformMarkerFromMarker).toList(), + markerUpdates.markersToChange.map(_platformMarkerFromMarker).toList(), + markerUpdates.markerIdsToRemove.map((MarkerId id) => id.value).toList(), ); } @@ -370,9 +363,12 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { PolygonUpdates polygonUpdates, { required int mapId, }) { - return _channel(mapId).invokeMethod( - 'polygons#update', - polygonUpdates.toJson(), + return _hostApi(mapId).updatePolygons( + polygonUpdates.polygonsToAdd.map(_platformPolygonFromPolygon).toList(), + polygonUpdates.polygonsToChange.map(_platformPolygonFromPolygon).toList(), + polygonUpdates.polygonIdsToRemove + .map((PolygonId id) => id.value) + .toList(), ); } @@ -381,9 +377,16 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { PolylineUpdates polylineUpdates, { required int mapId, }) { - return _channel(mapId).invokeMethod( - 'polylines#update', - polylineUpdates.toJson(), + return _hostApi(mapId).updatePolylines( + polylineUpdates.polylinesToAdd + .map(_platformPolylineFromPolyline) + .toList(), + polylineUpdates.polylinesToChange + .map(_platformPolylineFromPolyline) + .toList(), + polylineUpdates.polylineIdsToRemove + .map((PolylineId id) => id.value) + .toList(), ); } @@ -392,9 +395,10 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { CircleUpdates circleUpdates, { required int mapId, }) { - return _channel(mapId).invokeMethod( - 'circles#update', - circleUpdates.toJson(), + return _hostApi(mapId).updateCircles( + circleUpdates.circlesToAdd.map(_platformCircleFromCircle).toList(), + circleUpdates.circlesToChange.map(_platformCircleFromCircle).toList(), + circleUpdates.circleIdsToRemove.map((CircleId id) => id.value).toList(), ); } @@ -411,9 +415,16 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { final _TileOverlayUpdates updates = _TileOverlayUpdates.from(previousSet, newTileOverlays); _tileOverlays[mapId] = keyTileOverlayId(newTileOverlays); - return _channel(mapId).invokeMethod( - 'tileOverlays#update', - updates.toJson(), + return _hostApi(mapId).updateTileOverlays( + updates.tileOverlaysToAdd + .map(_platformTileOverlayFromTileOverlay) + .toList(), + updates.tileOverlaysToChange + .map(_platformTileOverlayFromTileOverlay) + .toList(), + updates.tileOverlayIdsToRemove + .map((TileOverlayId id) => id.value) + .toList(), ); } @@ -422,9 +433,13 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { ClusterManagerUpdates clusterManagerUpdates, { required int mapId, }) { - return _channel(mapId).invokeMethod( - 'clusterManagers#update', - serializeClusterManagerUpdates(clusterManagerUpdates), + return _hostApi(mapId).updateClusterManagers( + clusterManagerUpdates.clusterManagersToAdd + .map(_platformClusterManagerFromClusterManager) + .toList(), + clusterManagerUpdates.clusterManagerIdsToRemove + .map((ClusterManagerId id) => id.value) + .toList(), ); } @@ -441,10 +456,8 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { CameraUpdate cameraUpdate, { required int mapId, }) { - return _channel(mapId) - .invokeMethod('camera#animate', { - 'cameraUpdate': cameraUpdate.toJson(), - }); + return _hostApi(mapId) + .animateCamera(PlatformCameraUpdate(json: cameraUpdate.toJson())); } @override @@ -452,9 +465,8 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { CameraUpdate cameraUpdate, { required int mapId, }) { - return _channel(mapId).invokeMethod('camera#move', { - 'cameraUpdate': cameraUpdate.toJson(), - }); + return _hostApi(mapId) + .moveCamera(PlatformCameraUpdate(json: cameraUpdate.toJson())); } @override @@ -561,35 +573,25 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { /// Initialized [AndroidMapRenderer] type is returned. Future initializeWithRenderer( AndroidMapRenderer? rendererType) async { - String preferredRenderer; + PlatformRendererType? preferredRenderer; switch (rendererType) { case AndroidMapRenderer.latest: - preferredRenderer = 'latest'; + preferredRenderer = PlatformRendererType.latest; case AndroidMapRenderer.legacy: - preferredRenderer = 'legacy'; + preferredRenderer = PlatformRendererType.legacy; case AndroidMapRenderer.platformDefault: case null: - preferredRenderer = 'default'; + preferredRenderer = null; } - final String? initializedRenderer = await _initializerChannel - .invokeMethod('initializer#preferRenderer', - {'value': preferredRenderer}); - - if (initializedRenderer == null) { - throw AndroidMapRendererException('Failed to initialize map renderer.'); - } + final MapsInitializerApi hostApi = MapsInitializerApi(); + final PlatformRendererType initializedRenderer = + await hostApi.initializeWithPreferredRenderer(preferredRenderer); - // Returns mapped [AndroidMapRenderer] enum type. - switch (initializedRenderer) { - case 'latest': - return AndroidMapRenderer.latest; - case 'legacy': - return AndroidMapRenderer.legacy; - default: - throw AndroidMapRendererException( - 'Failed to initialize latest or legacy renderer, got $initializedRenderer.'); - } + return switch (initializedRenderer) { + PlatformRendererType.latest => AndroidMapRenderer.latest, + PlatformRendererType.legacy => AndroidMapRenderer.legacy, + }; } Widget _buildView( @@ -599,6 +601,8 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { MapObjects mapObjects = const MapObjects(), Map mapOptions = const {}, }) { + // TODO(stuartmorgan): Convert this to Pigeon-generated structures once + // https://github.com/flutter/flutter/issues/150631 is fixed. final Map creationParams = { 'initialCameraPosition': widgetConfiguration.initialCameraPosition.toMap(), @@ -815,6 +819,33 @@ class GoogleMapsFlutterAndroid extends GoogleMapsFlutterPlatform { southwest: _latLngFromPlatformLatLng(bounds.southwest), northeast: _latLngFromPlatformLatLng(bounds.northeast)); } + + static PlatformCircle _platformCircleFromCircle(Circle circle) { + return PlatformCircle(json: circle.toJson()); + } + + static PlatformClusterManager _platformClusterManagerFromClusterManager( + ClusterManager clusterManager) { + return PlatformClusterManager( + identifier: clusterManager.clusterManagerId.value); + } + + static PlatformMarker _platformMarkerFromMarker(Marker marker) { + return PlatformMarker(json: marker.toJson()); + } + + static PlatformPolygon _platformPolygonFromPolygon(Polygon polygon) { + return PlatformPolygon(json: polygon.toJson()); + } + + static PlatformPolyline _platformPolylineFromPolyline(Polyline polyline) { + return PlatformPolyline(json: polyline.toJson()); + } + + static PlatformTileOverlay _platformTileOverlayFromTileOverlay( + TileOverlay tileOverlay) { + return PlatformTileOverlay(json: tileOverlay.toJson()); + } } Map _jsonForMapConfiguration(MapConfiguration config) { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart index fa7445f748f..23f7aa45c0a 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/messages.g.dart @@ -18,6 +18,183 @@ PlatformException _createConnectionError(String channelName) { ); } +enum PlatformRendererType { + legacy, + latest, +} + +/// Pigeon representation of a CameraUpdate. +class PlatformCameraUpdate { + PlatformCameraUpdate({ + required this.json, + }); + + /// The update data, as JSON. This should only be set from + /// CameraUpdate.toJson, and the native code must intepret it according to the + /// internal implementation details of the CameraUpdate class. + Object json; + + Object encode() { + return [ + json, + ]; + } + + static PlatformCameraUpdate decode(Object result) { + result as List; + return PlatformCameraUpdate( + json: result[0]!, + ); + } +} + +/// Pigeon equivalent of the Circle class. +class PlatformCircle { + PlatformCircle({ + required this.json, + }); + + /// The circle data, as JSON. This should only be set from + /// Circle.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + Object json; + + Object encode() { + return [ + json, + ]; + } + + static PlatformCircle decode(Object result) { + result as List; + return PlatformCircle( + json: result[0]!, + ); + } +} + +/// Pigeon equivalent of the ClusterManager class. +class PlatformClusterManager { + PlatformClusterManager({ + required this.identifier, + }); + + String identifier; + + Object encode() { + return [ + identifier, + ]; + } + + static PlatformClusterManager decode(Object result) { + result as List; + return PlatformClusterManager( + identifier: result[0]! as String, + ); + } +} + +/// Pigeon equivalent of the Marker class. +class PlatformMarker { + PlatformMarker({ + required this.json, + }); + + /// The marker data, as JSON. This should only be set from + /// Marker.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + Object json; + + Object encode() { + return [ + json, + ]; + } + + static PlatformMarker decode(Object result) { + result as List; + return PlatformMarker( + json: result[0]!, + ); + } +} + +/// Pigeon equivalent of the Polygon class. +class PlatformPolygon { + PlatformPolygon({ + required this.json, + }); + + /// The polygon data, as JSON. This should only be set from + /// Polygon.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + Object json; + + Object encode() { + return [ + json, + ]; + } + + static PlatformPolygon decode(Object result) { + result as List; + return PlatformPolygon( + json: result[0]!, + ); + } +} + +/// Pigeon equivalent of the Polyline class. +class PlatformPolyline { + PlatformPolyline({ + required this.json, + }); + + /// The polyline data, as JSON. This should only be set from + /// Polyline.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + Object json; + + Object encode() { + return [ + json, + ]; + } + + static PlatformPolyline decode(Object result) { + result as List; + return PlatformPolyline( + json: result[0]!, + ); + } +} + +/// Pigeon equivalent of the TileOverlay class. +class PlatformTileOverlay { + PlatformTileOverlay({ + required this.json, + }); + + /// The tile overlay data, as JSON. This should only be set from + /// TileOverlay.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + Object json; + + Object encode() { + return [ + json, + ]; + } + + static PlatformTileOverlay decode(Object result) { + result as List; + return PlatformTileOverlay( + json: result[0]!, + ); + } +} + /// Pigeon equivalent of LatLng. class PlatformLatLng { PlatformLatLng({ @@ -109,6 +286,31 @@ class PlatformCluster { } } +/// Pigeon equivalent of MapConfiguration. +class PlatformMapConfiguration { + PlatformMapConfiguration({ + required this.json, + }); + + /// The configuration options, as JSON. This should only be set from + /// _jsonForMapConfiguration, and the native code must intepret it according + /// to the internal implementation details of that method. + Object json; + + Object encode() { + return [ + json, + ]; + } + + static PlatformMapConfiguration decode(Object result) { + result as List; + return PlatformMapConfiguration( + json: result[0]!, + ); + } +} + /// Pigeon representation of an x,y coordinate. class PlatformPoint { PlatformPoint({ @@ -204,24 +406,51 @@ class _PigeonCodec extends StandardMessageCodec { const _PigeonCodec(); @override void writeValue(WriteBuffer buffer, Object? value) { - if (value is PlatformLatLng) { + if (value is PlatformCameraUpdate) { buffer.putUint8(129); writeValue(buffer, value.encode()); - } else if (value is PlatformLatLngBounds) { + } else if (value is PlatformCircle) { buffer.putUint8(130); writeValue(buffer, value.encode()); - } else if (value is PlatformCluster) { + } else if (value is PlatformClusterManager) { buffer.putUint8(131); writeValue(buffer, value.encode()); - } else if (value is PlatformPoint) { + } else if (value is PlatformMarker) { buffer.putUint8(132); writeValue(buffer, value.encode()); - } else if (value is PlatformTileLayer) { + } else if (value is PlatformPolygon) { buffer.putUint8(133); writeValue(buffer, value.encode()); - } else if (value is PlatformZoomRange) { + } else if (value is PlatformPolyline) { buffer.putUint8(134); writeValue(buffer, value.encode()); + } else if (value is PlatformTileOverlay) { + buffer.putUint8(135); + writeValue(buffer, value.encode()); + } else if (value is PlatformLatLng) { + buffer.putUint8(136); + writeValue(buffer, value.encode()); + } else if (value is PlatformLatLngBounds) { + buffer.putUint8(137); + writeValue(buffer, value.encode()); + } else if (value is PlatformCluster) { + buffer.putUint8(138); + writeValue(buffer, value.encode()); + } else if (value is PlatformMapConfiguration) { + buffer.putUint8(139); + writeValue(buffer, value.encode()); + } else if (value is PlatformPoint) { + buffer.putUint8(140); + writeValue(buffer, value.encode()); + } else if (value is PlatformTileLayer) { + buffer.putUint8(141); + writeValue(buffer, value.encode()); + } else if (value is PlatformZoomRange) { + buffer.putUint8(142); + writeValue(buffer, value.encode()); + } else if (value is PlatformRendererType) { + buffer.putUint8(143); + writeValue(buffer, value.index); } else { super.writeValue(buffer, value); } @@ -231,17 +460,36 @@ class _PigeonCodec extends StandardMessageCodec { Object? readValueOfType(int type, ReadBuffer buffer) { switch (type) { case 129: - return PlatformLatLng.decode(readValue(buffer)!); + return PlatformCameraUpdate.decode(readValue(buffer)!); case 130: - return PlatformLatLngBounds.decode(readValue(buffer)!); + return PlatformCircle.decode(readValue(buffer)!); case 131: - return PlatformCluster.decode(readValue(buffer)!); + return PlatformClusterManager.decode(readValue(buffer)!); case 132: - return PlatformPoint.decode(readValue(buffer)!); + return PlatformMarker.decode(readValue(buffer)!); case 133: - return PlatformTileLayer.decode(readValue(buffer)!); + return PlatformPolygon.decode(readValue(buffer)!); case 134: + return PlatformPolyline.decode(readValue(buffer)!); + case 135: + return PlatformTileOverlay.decode(readValue(buffer)!); + case 136: + return PlatformLatLng.decode(readValue(buffer)!); + case 137: + return PlatformLatLngBounds.decode(readValue(buffer)!); + case 138: + return PlatformCluster.decode(readValue(buffer)!); + case 139: + return PlatformMapConfiguration.decode(readValue(buffer)!); + case 140: + return PlatformPoint.decode(readValue(buffer)!); + case 141: + return PlatformTileLayer.decode(readValue(buffer)!); + case 142: return PlatformZoomRange.decode(readValue(buffer)!); + case 143: + final int? value = readValue(buffer) as int?; + return value == null ? null : PlatformRendererType.values[value]; default: return super.readValueOfType(type, buffer); } @@ -290,6 +538,191 @@ class MapsApi { } } + /// Updates the map's configuration options. + /// + /// Only non-null configuration values will result in updates; options with + /// null values will remain unchanged. + Future updateMapConfiguration( + PlatformMapConfiguration configuration) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateMapConfiguration$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([configuration]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of circles on the map. + Future updateCircles(List toAdd, + List toChange, List idsToRemove) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateCircles$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = await __pigeon_channel + .send([toAdd, toChange, idsToRemove]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of custer managers for clusters on the map. + Future updateClusterManagers( + List toAdd, List idsToRemove) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateClusterManagers$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = await __pigeon_channel + .send([toAdd, idsToRemove]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of markers on the map. + Future updateMarkers(List toAdd, + List toChange, List idsToRemove) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateMarkers$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = await __pigeon_channel + .send([toAdd, toChange, idsToRemove]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of polygonss on the map. + Future updatePolygons(List toAdd, + List toChange, List idsToRemove) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updatePolygons$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = await __pigeon_channel + .send([toAdd, toChange, idsToRemove]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of polylines on the map. + Future updatePolylines(List toAdd, + List toChange, List idsToRemove) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updatePolylines$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = await __pigeon_channel + .send([toAdd, toChange, idsToRemove]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + /// Updates the set of tile overlays on the map. + Future updateTileOverlays(List toAdd, + List toChange, List idsToRemove) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.updateTileOverlays$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = await __pigeon_channel + .send([toAdd, toChange, idsToRemove]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + /// Gets the screen coordinate for the given map location. Future getScreenCoordinate(PlatformLatLng latLng) async { final String __pigeon_channelName = @@ -380,6 +813,57 @@ class MapsApi { } } + /// Moves the camera according to [cameraUpdate] immediately, with no + /// animation. + Future moveCamera(PlatformCameraUpdate cameraUpdate) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.moveCamera$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([cameraUpdate]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + + /// Moves the camera according to [cameraUpdate], animating the update. + Future animateCamera(PlatformCameraUpdate cameraUpdate) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsApi.animateCamera$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([cameraUpdate]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else { + return; + } + } + /// Gets the current map zoom level. Future getZoomLevel() async { final String __pigeon_channelName = @@ -615,6 +1099,59 @@ class MapsApi { } } +/// Interface for global SDK initialization. +class MapsInitializerApi { + /// Constructor for [MapsInitializerApi]. The [binaryMessenger] named argument is + /// available for dependency injection. If it is left null, the default + /// BinaryMessenger will be used which routes to the host platform. + MapsInitializerApi( + {BinaryMessenger? binaryMessenger, String messageChannelSuffix = ''}) + : __pigeon_binaryMessenger = binaryMessenger, + __pigeon_messageChannelSuffix = + messageChannelSuffix.isNotEmpty ? '.$messageChannelSuffix' : ''; + final BinaryMessenger? __pigeon_binaryMessenger; + + static const MessageCodec pigeonChannelCodec = _PigeonCodec(); + + final String __pigeon_messageChannelSuffix; + + /// Initializes the Google Maps SDK with the given renderer preference. + /// + /// A null renderer preference will result in the default renderer. + /// + /// Calling this more than once in the lifetime of an application will result + /// in an error. + Future initializeWithPreferredRenderer( + PlatformRendererType? type) async { + final String __pigeon_channelName = + 'dev.flutter.pigeon.google_maps_flutter_android.MapsInitializerApi.initializeWithPreferredRenderer$__pigeon_messageChannelSuffix'; + final BasicMessageChannel __pigeon_channel = + BasicMessageChannel( + __pigeon_channelName, + pigeonChannelCodec, + binaryMessenger: __pigeon_binaryMessenger, + ); + final List? __pigeon_replyList = + await __pigeon_channel.send([type]) as List?; + if (__pigeon_replyList == null) { + throw _createConnectionError(__pigeon_channelName); + } else if (__pigeon_replyList.length > 1) { + throw PlatformException( + code: __pigeon_replyList[0]! as String, + message: __pigeon_replyList[1] as String?, + details: __pigeon_replyList[2], + ); + } else if (__pigeon_replyList[0] == null) { + throw PlatformException( + code: 'null-error', + message: 'Host platform returned null value for non-null return value.', + ); + } else { + return (__pigeon_replyList[0] as PlatformRendererType?)!; + } + } +} + /// Inspector API only intended for use in integration tests. class MapsInspectorApi { /// Constructor for [MapsInspectorApi]. The [binaryMessenger] named argument is diff --git a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/utils/cluster_manager_utils.dart b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/utils/cluster_manager_utils.dart index cdb1d2c9244..1aab89354a0 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/lib/src/utils/cluster_manager_utils.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/lib/src/utils/cluster_manager_utils.dart @@ -17,18 +17,3 @@ Object _serializeClusterManager(ClusterManager clusterManager) { json['clusterManagerId'] = clusterManager.clusterManagerId.value; return json; } - -/// Converts a Cluster Manager updates into object serializable in JSON. -Object serializeClusterManagerUpdates( - ClusterManagerUpdates clusterManagerUpdates) { - final Map updateMap = {}; - - updateMap['clusterManagersToAdd'] = - serializeClusterManagerSet(clusterManagerUpdates.objectsToAdd); - updateMap['clusterManagerIdsToRemove'] = clusterManagerUpdates - .objectIdsToRemove - .map((MapsObjectId id) => id.value) - .toList(); - - return updateMap; -} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pigeons/messages.dart b/packages/google_maps_flutter/google_maps_flutter_android/pigeons/messages.dart index 1a50204c580..3b78a5b180b 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pigeons/messages.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/pigeons/messages.dart @@ -11,6 +11,91 @@ import 'package:pigeon/pigeon.dart'; copyrightHeader: 'pigeons/copyright.txt', )) +// Pigeon equivalent of the Java MapsInitializer.Renderer. +enum PlatformRendererType { legacy, latest } + +/// Pigeon representation of a CameraUpdate. +class PlatformCameraUpdate { + PlatformCameraUpdate(this.json); + + /// The update data, as JSON. This should only be set from + /// CameraUpdate.toJson, and the native code must intepret it according to the + /// internal implementation details of the CameraUpdate class. + // TODO(stuartmorgan): Update the google_maps_platform_interface CameraUpdate + // class to provide a structured representation of an update. Currently it + // uses JSON as its only state, so there is no way to preserve structure. + // This wrapper class exists as a placeholder for now to at least provide + // type safety in the top-level call's arguments. + final Object json; +} + +/// Pigeon equivalent of the Circle class. +class PlatformCircle { + PlatformCircle(this.json); + + /// The circle data, as JSON. This should only be set from + /// Circle.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + // TODO(stuartmorgan): Replace this with structured data. This exists only to + // allow incremental migration to Pigeon. + final Object json; +} + +/// Pigeon equivalent of the ClusterManager class. +class PlatformClusterManager { + PlatformClusterManager({required this.identifier}); + + final String identifier; +} + +/// Pigeon equivalent of the Marker class. +class PlatformMarker { + PlatformMarker(this.json); + + /// The marker data, as JSON. This should only be set from + /// Marker.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + // TODO(stuartmorgan): Replace this with structured data. This exists only to + // allow incremental migration to Pigeon. + final Object json; +} + +/// Pigeon equivalent of the Polygon class. +class PlatformPolygon { + PlatformPolygon(this.json); + + /// The polygon data, as JSON. This should only be set from + /// Polygon.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + // TODO(stuartmorgan): Replace this with structured data. This exists only to + // allow incremental migration to Pigeon. + final Object json; +} + +/// Pigeon equivalent of the Polyline class. +class PlatformPolyline { + PlatformPolyline(this.json); + + /// The polyline data, as JSON. This should only be set from + /// Polyline.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + // TODO(stuartmorgan): Replace this with structured data. This exists only to + // allow incremental migration to Pigeon. + final Object json; +} + +/// Pigeon equivalent of the TileOverlay class. +class PlatformTileOverlay { + PlatformTileOverlay(this.json); + + /// The tile overlay data, as JSON. This should only be set from + /// TileOverlay.toJson, and the native code must intepret it according to the + /// internal implementation details of that method. + // TODO(stuartmorgan): Replace this with structured data. This exists only to + // allow incremental migration to Pigeon. + final Object json; +} + /// Pigeon equivalent of LatLng. class PlatformLatLng { PlatformLatLng({required this.latitude, required this.longitude}); @@ -45,6 +130,18 @@ class PlatformCluster { final List markerIds; } +/// Pigeon equivalent of MapConfiguration. +class PlatformMapConfiguration { + PlatformMapConfiguration({required this.json}); + + /// The configuration options, as JSON. This should only be set from + /// _jsonForMapConfiguration, and the native code must intepret it according + /// to the internal implementation details of that method. + // TODO(stuartmorgan): Replace this with structured data. This exists only to + // allow incremental migration to Pigeon. + final Object json; +} + /// Pigeon representation of an x,y coordinate. class PlatformPoint { PlatformPoint({required this.x, required this.y}); @@ -85,6 +182,54 @@ abstract class MapsApi { @async void waitForMap(); + /// Updates the map's configuration options. + /// + /// Only non-null configuration values will result in updates; options with + /// null values will remain unchanged. + void updateMapConfiguration(PlatformMapConfiguration configuration); + + /// Updates the set of circles on the map. + // TODO(stuartmorgan): Make the generic type non-nullable once supported. + // https://github.com/flutter/flutter/issues/97848 + // The consuming code treats the entries as non-nullable. + void updateCircles(List toAdd, + List toChange, List idsToRemove); + + /// Updates the set of custer managers for clusters on the map. + // TODO(stuartmorgan): Make the generic type non-nullable once supported. + // https://github.com/flutter/flutter/issues/97848 + // The consuming code treats the entries as non-nullable. + void updateClusterManagers( + List toAdd, List idsToRemove); + + /// Updates the set of markers on the map. + // TODO(stuartmorgan): Make the generic type non-nullable once supported. + // https://github.com/flutter/flutter/issues/97848 + // The consuming code treats the entries as non-nullable. + void updateMarkers(List toAdd, + List toChange, List idsToRemove); + + /// Updates the set of polygonss on the map. + // TODO(stuartmorgan): Make the generic type non-nullable once supported. + // https://github.com/flutter/flutter/issues/97848 + // The consuming code treats the entries as non-nullable. + void updatePolygons(List toAdd, + List toChange, List idsToRemove); + + /// Updates the set of polylines on the map. + // TODO(stuartmorgan): Make the generic type non-nullable once supported. + // https://github.com/flutter/flutter/issues/97848 + // The consuming code treats the entries as non-nullable. + void updatePolylines(List toAdd, + List toChange, List idsToRemove); + + /// Updates the set of tile overlays on the map. + // TODO(stuartmorgan): Make the generic type non-nullable once supported. + // https://github.com/flutter/flutter/issues/97848 + // The consuming code treats the entries as non-nullable. + void updateTileOverlays(List toAdd, + List toChange, List idsToRemove); + /// Gets the screen coordinate for the given map location. PlatformPoint getScreenCoordinate(PlatformLatLng latLng); @@ -94,6 +239,13 @@ abstract class MapsApi { /// Gets the map region currently displayed on the map. PlatformLatLngBounds getVisibleRegion(); + /// Moves the camera according to [cameraUpdate] immediately, with no + /// animation. + void moveCamera(PlatformCameraUpdate cameraUpdate); + + /// Moves the camera according to [cameraUpdate], animating the update. + void animateCamera(PlatformCameraUpdate cameraUpdate); + /// Gets the current map zoom level. double getZoomLevel(); @@ -129,6 +281,20 @@ abstract class MapsApi { Uint8List takeSnapshot(); } +/// Interface for global SDK initialization. +@HostApi() +abstract class MapsInitializerApi { + /// Initializes the Google Maps SDK with the given renderer preference. + /// + /// A null renderer preference will result in the default renderer. + /// + /// Calling this more than once in the lifetime of an application will result + /// in an error. + @async + PlatformRendererType initializeWithPreferredRenderer( + PlatformRendererType? type); +} + /// Inspector API only intended for use in integration tests. @HostApi() abstract class MapsInspectorApi { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml index 087914e6b3e..e55b16a6b94 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml +++ b/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml @@ -2,7 +2,7 @@ name: google_maps_flutter_android description: Android implementation of the google_maps_flutter plugin. repository: https://github.com/flutter/packages/tree/main/packages/google_maps_flutter/google_maps_flutter_android issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+maps%22 -version: 2.10.0 +version: 2.11.0 environment: sdk: ^3.4.0 diff --git a/packages/google_maps_flutter/google_maps_flutter_android/test/cluster_manager_utils_test.dart b/packages/google_maps_flutter/google_maps_flutter_android/test/cluster_manager_utils_test.dart deleted file mode 100644 index 56963ddbdd9..00000000000 --- a/packages/google_maps_flutter/google_maps_flutter_android/test/cluster_manager_utils_test.dart +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright 2013 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -import 'package:flutter_test/flutter_test.dart'; -import 'package:google_maps_flutter_android/src/utils/cluster_manager_utils.dart'; -import 'package:google_maps_flutter_platform_interface/google_maps_flutter_platform_interface.dart'; - -void main() { - test('serializeClusterManagerUpdates', () async { - const ClusterManagerId clusterManagerId1 = ClusterManagerId('cm1'); - const ClusterManagerId clusterManagerId2 = ClusterManagerId('cm2'); - - const ClusterManager clusterManager1 = ClusterManager( - clusterManagerId: clusterManagerId1, - ); - const ClusterManager clusterManager2 = ClusterManager( - clusterManagerId: clusterManagerId2, - ); - - final Set clusterManagersSet1 = {}; - final Set clusterManagersSet2 = { - clusterManager1, - clusterManager2 - }; - final Set clusterManagersSet3 = { - clusterManager1 - }; - - final ClusterManagerUpdates clusterManagerUpdates1 = - ClusterManagerUpdates.from(clusterManagersSet1, clusterManagersSet2); - final Map serializedData1 = - serializeClusterManagerUpdates(clusterManagerUpdates1) - as Map; - expect(serializedData1['clusterManagersToAdd'], isNotNull); - final List clusterManagersToAdd1 = - serializedData1['clusterManagersToAdd']! as List; - expect(clusterManagersToAdd1.length, 2); - expect(serializedData1['clusterManagerIdsToRemove'], isNotNull); - final List clusterManagersToRemove1 = - serializedData1['clusterManagerIdsToRemove']! as List; - expect(clusterManagersToRemove1.length, 0); - - final ClusterManagerUpdates clusterManagerUpdates2 = - ClusterManagerUpdates.from(clusterManagersSet2, clusterManagersSet3); - serializeClusterManagerUpdates(clusterManagerUpdates2); - final Map serializedData2 = - serializeClusterManagerUpdates(clusterManagerUpdates2) - as Map; - expect(serializedData2['clusterManagersToAdd'], isNotNull); - final List clusterManagersToAdd2 = - serializedData2['clusterManagersToAdd']! as List; - expect(clusterManagersToAdd2.length, 0); - expect(serializedData1['clusterManagerIdsToRemove'], isNotNull); - final List clusterManagersToRemove2 = - serializedData2['clusterManagerIdsToRemove']! as List; - expect(clusterManagersToRemove2.length, 1); - expect(clusterManagersToRemove2.first as String, equals('cm2')); - }); -} diff --git a/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.dart b/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.dart index 109b9411a32..cfe6b976695 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.dart @@ -113,6 +113,35 @@ void main() { expect(bounds, expectedBounds); }); + test('moveCamera calls through', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + final CameraUpdate update = CameraUpdate.scrollBy(10, 20); + await maps.moveCamera(update, mapId: mapId); + + final VerificationResult verification = verify(api.moveCamera(captureAny)); + final PlatformCameraUpdate passedUpdate = + verification.captured[0] as PlatformCameraUpdate; + expect(passedUpdate.json, update.toJson()); + }); + + test('animateCamera calls through', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + final CameraUpdate update = CameraUpdate.scrollBy(10, 20); + await maps.animateCamera(update, mapId: mapId); + + final VerificationResult verification = + verify(api.animateCamera(captureAny)); + final PlatformCameraUpdate passedUpdate = + verification.captured[0] as PlatformCameraUpdate; + expect(passedUpdate.json, update.toJson()); + }); + test('getZoomLevel passes values correctly', () async { const int mapId = 1; final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = @@ -183,6 +212,258 @@ void main() { verify(api.clearTileCache(tileOverlayId)); }); + test('updateMapConfiguration passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + // Set some arbitrary options. + const MapConfiguration config = MapConfiguration( + compassEnabled: true, + liteModeEnabled: false, + mapType: MapType.terrain, + ); + await maps.updateMapConfiguration(config, mapId: mapId); + + final VerificationResult verification = + verify(api.updateMapConfiguration(captureAny)); + final PlatformMapConfiguration passedConfig = + verification.captured[0] as PlatformMapConfiguration; + final Map passedConfigJson = + passedConfig.json as Map; + // Each set option should be present. + expect(passedConfigJson['compassEnabled'], true); + expect(passedConfigJson['liteModeEnabled'], false); + expect(passedConfigJson['mapType'], MapType.terrain.index); + // Spot-check that unset options are not be present. + expect(passedConfigJson['myLocationEnabled'], isNull); + expect(passedConfigJson['cameraTargetBounds'], isNull); + expect(passedConfigJson['padding'], isNull); + }); + + test('updateMapOptions passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + // Set some arbitrary options. + final Map config = { + 'compassEnabled': true, + 'liteModeEnabled': false, + 'mapType': MapType.terrain.index, + }; + await maps.updateMapOptions(config, mapId: mapId); + + final VerificationResult verification = + verify(api.updateMapConfiguration(captureAny)); + final PlatformMapConfiguration passedConfig = + verification.captured[0] as PlatformMapConfiguration; + final Map passedConfigJson = + passedConfig.json as Map; + // Each set option should be present. + expect(passedConfigJson['compassEnabled'], true); + expect(passedConfigJson['liteModeEnabled'], false); + expect(passedConfigJson['mapType'], MapType.terrain.index); + // Spot-check that unset options are not be present. + expect(passedConfigJson['myLocationEnabled'], isNull); + expect(passedConfigJson['cameraTargetBounds'], isNull); + expect(passedConfigJson['padding'], isNull); + }); + + test('updateCircles passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + const Circle object1 = Circle(circleId: CircleId('1')); + const Circle object2old = Circle(circleId: CircleId('2')); + final Circle object2new = object2old.copyWith(radiusParam: 42); + const Circle object3 = Circle(circleId: CircleId('3')); + await maps.updateCircles( + CircleUpdates.from( + {object1, object2old}, {object2new, object3}), + mapId: mapId); + + final VerificationResult verification = + verify(api.updateCircles(captureAny, captureAny, captureAny)); + final List toAdd = + verification.captured[0] as List; + final List toChange = + verification.captured[1] as List; + final List toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.circleId.value); + // Object two should be changed. + expect(toChange.length, 1); + expect(toChange.first?.json, object2new.toJson()); + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first?.json, object3.toJson()); + }); + + test('updateClusterManagers passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + const ClusterManager object1 = + ClusterManager(clusterManagerId: ClusterManagerId('1')); + const ClusterManager object3 = + ClusterManager(clusterManagerId: ClusterManagerId('3')); + await maps.updateClusterManagers( + ClusterManagerUpdates.from( + {object1}, {object3}), + mapId: mapId); + + final VerificationResult verification = + verify(api.updateClusterManagers(captureAny, captureAny)); + final List toAdd = + verification.captured[0] as List; + final List toRemove = verification.captured[1] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.clusterManagerId.value); + // Unlike other map object types, changes are not possible for cluster + // managers, since they have no non-ID properties. + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first?.identifier, object3.clusterManagerId.value); + }); + + test('updateMarkers passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + const Marker object1 = Marker(markerId: MarkerId('1')); + const Marker object2old = Marker(markerId: MarkerId('2')); + final Marker object2new = object2old.copyWith(rotationParam: 42); + const Marker object3 = Marker(markerId: MarkerId('3')); + await maps.updateMarkers( + MarkerUpdates.from( + {object1, object2old}, {object2new, object3}), + mapId: mapId); + + final VerificationResult verification = + verify(api.updateMarkers(captureAny, captureAny, captureAny)); + final List toAdd = + verification.captured[0] as List; + final List toChange = + verification.captured[1] as List; + final List toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.markerId.value); + // Object two should be changed. + expect(toChange.length, 1); + expect(toChange.first?.json, object2new.toJson()); + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first?.json, object3.toJson()); + }); + + test('updatePolygons passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + const Polygon object1 = Polygon(polygonId: PolygonId('1')); + const Polygon object2old = Polygon(polygonId: PolygonId('2')); + final Polygon object2new = object2old.copyWith(strokeWidthParam: 42); + const Polygon object3 = Polygon(polygonId: PolygonId('3')); + await maps.updatePolygons( + PolygonUpdates.from( + {object1, object2old}, {object2new, object3}), + mapId: mapId); + + final VerificationResult verification = + verify(api.updatePolygons(captureAny, captureAny, captureAny)); + final List toAdd = + verification.captured[0] as List; + final List toChange = + verification.captured[1] as List; + final List toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.polygonId.value); + // Object two should be changed. + expect(toChange.length, 1); + expect(toChange.first?.json, object2new.toJson()); + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first?.json, object3.toJson()); + }); + + test('updatePolylines passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + const Polyline object1 = Polyline(polylineId: PolylineId('1')); + const Polyline object2old = Polyline(polylineId: PolylineId('2')); + final Polyline object2new = object2old.copyWith(widthParam: 42); + const Polyline object3 = Polyline(polylineId: PolylineId('3')); + await maps.updatePolylines( + PolylineUpdates.from( + {object1, object2old}, {object2new, object3}), + mapId: mapId); + + final VerificationResult verification = + verify(api.updatePolylines(captureAny, captureAny, captureAny)); + final List toAdd = + verification.captured[0] as List; + final List toChange = + verification.captured[1] as List; + final List toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.polylineId.value); + // Object two should be changed. + expect(toChange.length, 1); + expect(toChange.first?.json, object2new.toJson()); + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first?.json, object3.toJson()); + }); + + test('updateTileOverlays passes expected arguments', () async { + const int mapId = 1; + final (GoogleMapsFlutterAndroid maps, MockMapsApi api) = + setUpMockMap(mapId: mapId); + + const TileOverlay object1 = TileOverlay(tileOverlayId: TileOverlayId('1')); + const TileOverlay object2old = + TileOverlay(tileOverlayId: TileOverlayId('2')); + final TileOverlay object2new = object2old.copyWith(zIndexParam: 42); + const TileOverlay object3 = TileOverlay(tileOverlayId: TileOverlayId('3')); + // Pre-set the initial state, since this update method doesn't take the old + // state. + await maps.updateTileOverlays( + newTileOverlays: {object1, object2old}, mapId: mapId); + clearInteractions(api); + + await maps.updateTileOverlays( + newTileOverlays: {object2new, object3}, mapId: mapId); + + final VerificationResult verification = + verify(api.updateTileOverlays(captureAny, captureAny, captureAny)); + final List toAdd = + verification.captured[0] as List; + final List toChange = + verification.captured[1] as List; + final List toRemove = verification.captured[2] as List; + // Object one should be removed. + expect(toRemove.length, 1); + expect(toRemove.first, object1.tileOverlayId.value); + // Object two should be changed. + expect(toChange.length, 1); + expect(toChange.first?.json, object2new.toJson()); + // Object 3 should be added. + expect(toAdd.length, 1); + expect(toAdd.first?.json, object3.toJson()); + }); + test('markers send drag event to correct streams', () async { const int mapId = 1; final Map jsonMarkerDragStartEvent = { diff --git a/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.mocks.dart b/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.mocks.dart index f819660e213..c49d6268926 100644 --- a/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.mocks.dart +++ b/packages/google_maps_flutter/google_maps_flutter_android/test/google_maps_flutter_android_test.mocks.dart @@ -68,6 +68,130 @@ class MockMapsApi extends _i1.Mock implements _i2.MapsApi { returnValueForMissingStub: _i3.Future.value(), ) as _i3.Future); + @override + _i3.Future updateMapConfiguration( + _i2.PlatformMapConfiguration? configuration) => + (super.noSuchMethod( + Invocation.method( + #updateMapConfiguration, + [configuration], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future updateCircles( + List<_i2.PlatformCircle?>? toAdd, + List<_i2.PlatformCircle?>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method( + #updateCircles, + [ + toAdd, + toChange, + idsToRemove, + ], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future updateClusterManagers( + List<_i2.PlatformClusterManager?>? toAdd, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method( + #updateClusterManagers, + [ + toAdd, + idsToRemove, + ], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future updateMarkers( + List<_i2.PlatformMarker?>? toAdd, + List<_i2.PlatformMarker?>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method( + #updateMarkers, + [ + toAdd, + toChange, + idsToRemove, + ], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future updatePolygons( + List<_i2.PlatformPolygon?>? toAdd, + List<_i2.PlatformPolygon?>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method( + #updatePolygons, + [ + toAdd, + toChange, + idsToRemove, + ], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future updatePolylines( + List<_i2.PlatformPolyline?>? toAdd, + List<_i2.PlatformPolyline?>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method( + #updatePolylines, + [ + toAdd, + toChange, + idsToRemove, + ], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future updateTileOverlays( + List<_i2.PlatformTileOverlay?>? toAdd, + List<_i2.PlatformTileOverlay?>? toChange, + List? idsToRemove, + ) => + (super.noSuchMethod( + Invocation.method( + #updateTileOverlays, + [ + toAdd, + toChange, + idsToRemove, + ], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override _i3.Future<_i2.PlatformPoint> getScreenCoordinate( _i2.PlatformLatLng? latLng) => @@ -143,6 +267,28 @@ class MockMapsApi extends _i1.Mock implements _i2.MapsApi { )), ) as _i3.Future<_i2.PlatformLatLngBounds>); + @override + _i3.Future moveCamera(_i2.PlatformCameraUpdate? cameraUpdate) => + (super.noSuchMethod( + Invocation.method( + #moveCamera, + [cameraUpdate], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + + @override + _i3.Future animateCamera(_i2.PlatformCameraUpdate? cameraUpdate) => + (super.noSuchMethod( + Invocation.method( + #animateCamera, + [cameraUpdate], + ), + returnValue: _i3.Future.value(), + returnValueForMissingStub: _i3.Future.value(), + ) as _i3.Future); + @override _i3.Future getZoomLevel() => (super.noSuchMethod( Invocation.method( From d2c7c673ce7580c226dcce2a73d306870702ebc3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Jul 2024 19:52:19 +0000 Subject: [PATCH 12/13] [in_app_pur]: Bump androidx.test.espresso:espresso-core from 3.5.1 to 3.6.1 in /packages/in_app_purchase/in_app_purchase_android/android (#7032) Bumps androidx.test.espresso:espresso-core from 3.5.1 to 3.6.1. [![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=androidx.test.espresso:espresso-core&package-manager=gradle&previous-version=3.5.1&new-version=3.6.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
--- .../in_app_purchase_android/android/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/in_app_purchase/in_app_purchase_android/android/build.gradle b/packages/in_app_purchase/in_app_purchase_android/android/build.gradle index bd28bd93ed0..5f0fecc642e 100644 --- a/packages/in_app_purchase/in_app_purchase_android/android/build.gradle +++ b/packages/in_app_purchase/in_app_purchase_android/android/build.gradle @@ -69,5 +69,5 @@ dependencies { testImplementation 'androidx.test:core:1.5.0' testImplementation 'org.robolectric:robolectric:4.10.3' androidTestImplementation 'androidx.test:runner:1.5.2' - androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.6.1' } From d2705fb82b2605633e8528c053148128cc202327 Mon Sep 17 00:00:00 2001 From: engine-flutter-autoroll Date: Mon, 1 Jul 2024 17:58:04 -0400 Subject: [PATCH 13/13] Roll Flutter from 651a17db5427 to 99bb2ff6a614 (10 revisions) (#7038) https://github.com/flutter/flutter/compare/651a17db5427...99bb2ff6a614 2024-07-01 engine-flutter-autoroll@skia.org Roll Flutter Engine from 0d93da7e2fe1 to b57a044ed10f (1 revision) (flutter/flutter#151082) 2024-06-30 engine-flutter-autoroll@skia.org Roll Flutter Engine from ad1343cfb99e to 0d93da7e2fe1 (9 revisions) (flutter/flutter#151062) 2024-06-29 jason-simmons@users.noreply.github.com Reduce the depth used in a test that applies finders to deep widget trees (flutter/flutter#151049) 2024-06-29 engine-flutter-autoroll@skia.org Roll Flutter Engine from f828363d03ff to ad1343cfb99e (3 revisions) (flutter/flutter#151016) 2024-06-29 32538273+ValentinVignal@users.noreply.github.com Add test for segmented_button.0.dart (flutter/flutter#150676) 2024-06-29 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#151022) 2024-06-29 137456488+flutter-pub-roller-bot@users.noreply.github.com Roll pub packages (flutter/flutter#150827) 2024-06-28 engine-flutter-autoroll@skia.org Roll Flutter Engine from 2f7e9ab27493 to f828363d03ff (3 revisions) (flutter/flutter#151013) 2024-06-28 49699333+dependabot[bot]@users.noreply.github.com Bump github/codeql-action from 3.25.10 to 3.25.11 (flutter/flutter#151012) 2024-06-28 andrewrkolos@gmail.com [tool] when writing to openssl as a part of macOS/iOS code-signing, flush the stdin stream before closing it (flutter/flutter#150120) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-packages Please CC camillesimon@google.com,rmistry@google.com,stuartmorgan@google.com on the revert to ensure that a human is aware of the problem. To file a bug in Packages: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md --- .ci/flutter_master.version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.ci/flutter_master.version b/.ci/flutter_master.version index de12310d68a..02c8bcb4c2e 100644 --- a/.ci/flutter_master.version +++ b/.ci/flutter_master.version @@ -1 +1 @@ -651a17db5427edd1d0bd849f4bad9e3f33952412 +99bb2ff6a61428036323bb8734e92dad0daf950e