-
Notifications
You must be signed in to change notification settings - Fork 3.2k
[google_maps_flutter] Support for Ground Overlay #8432
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[google_maps_flutter] Support for Ground Overlay #8432
Conversation
c94285d
to
19a7808
Compare
@@ -22,7 +21,7 @@ void main() { | |||
} | |||
|
|||
void runTests() { | |||
const double floatTolerance = 1e-8; | |||
const double floatTolerance = 1e-6; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added bigger tolerance as on Android and iOS tests failed as diff was bigger than 1e-8
Color.fromARGB(255, 0, 0, 191), | ||
0.6, | ||
); | ||
await tester.pumpAndSettle(const Duration(seconds: 3)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Without this line tests timeouted on Web platform, and we were not able to test ground overlay below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Were they timing out in all tests, or wasm specifically? I know I had to revisit a bunch of plugins and add a few pump
s and pumpAndSettle
when enabling the wasm tests. See:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ditman
Note that google_maps_flutter
tests are currently excluded for web platform because failing tests:
https://github.com/flutter/packages/blob/main/script/configs/exclude_integration_web.yaml
New implemented tests pass with and without wasm
enabled, but only if I disable other test sets (that fail because other reasons). The new tests are located in tiles_inspector.dart
and I just run this set, which includes tests for tiles, heatmaps, and ground overlays. This file should probably be renamed or split?

Fixing other tests is out of scope of this PR, but this must include working integration tests for web for new features and functionality.
So when only tiles_inspector.dart tests are enabled tests pass with following commands:
Without wasm
dart run ./script/tool/bin/flutter_plugin_tools.dart drive-examples --web --run-chromedriver --packages=google_maps_flutter/google_maps_flutter
and with wasm
dart run ./script/tool/bin/flutter_plugin_tools.dart drive-examples --web --wasm --run-chromedriver --packages=google_maps_flutter/google_maps_flutter
...es/google_maps_flutter/google_maps_flutter/example/integration_test/src/tiles_inspector.dart
Show resolved
Hide resolved
expect(wll1.weight, wll2.weight); | ||
expect(wll1.point.latitude, moreOrLessEquals(wll2.point.latitude)); | ||
expect(wll1.point.longitude, moreOrLessEquals(wll2.point.longitude)); | ||
group('Heatmaps', () { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added Heatmap tests to own group, like tile overlay tests and ground overlay tests.
...ps_flutter_platform_interface/lib/src/platform_interface/google_maps_inspector_platform.dart
Outdated
Show resolved
Hide resolved
...ps_flutter_platform_interface/lib/src/platform_interface/google_maps_inspector_platform.dart
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really good! I did a pass over everything apart from web, and mostly just have minor comments and questions.
...google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart
Outdated
Show resolved
Hide resolved
...google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart
Outdated
Show resolved
Hide resolved
...google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart
Outdated
Show resolved
Hide resolved
...google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart
Outdated
Show resolved
Hide resolved
...google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart
Outdated
Show resolved
Hide resolved
} | ||
|
||
- (void)didTapGroundOverlayWithIdentifier:(NSString *)identifier { | ||
if (!identifier) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here and in the next method: the identifier params were annotated as non-nullable in the interface, so the implementation code shouldn't be handling nil.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch. Removed the null check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's still here in this method.
packages/google_maps_flutter/google_maps_flutter_ios/ios/Classes/FGMUtils.h
Outdated
Show resolved
Hide resolved
NS_ASSUME_NONNULL_BEGIN | ||
|
||
@interface FGMUtils : NSObject | ||
+ (UIImage *)iconFromBitmap:(FGMPlatformBitmap *)platformBitmap |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These new APIs need declaration comments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this be given a more specific name? It's already the case that this plugin has at least one other file of utils (the conversion function file).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I renamed it FGMImageUtils
.
final PlatformBitmap image; | ||
final PlatformLatLng? position; | ||
final PlatformLatLngBounds? bounds; | ||
final PlatformDoublePair? anchor; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this conceptually a point? We already have PlatformPoint
, so shouldn't need a new PlatformDoublePair
for this unless there's a conceptual difference in meaning here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed this to PlatformPoint.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some scattered minor issues remaining. Feel free to split out the first sub-PR at this point!
...google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay.dart
Outdated
Show resolved
Hide resolved
if (west <= east) { | ||
longitudeOffset = position.longitude - west; | ||
} else { | ||
longitudeOffset = position.longitude - west; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the same in both branches; is that a copy/paste mistake?
If not, it should be factored out of the if/else.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(And if so, that suggests missing test coverage for the behavior in these branches.)
@import GoogleMaps; | ||
|
||
#import <OCMock/OCMock.h> | ||
#import <google_maps_flutter_ios/FGMGroundOverlayController_Test.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be before all other imports; see https://google.github.io/styleguide/objcguide.html#order-of-includes
|
||
#import <google_maps_flutter_ios/FGMGroundOverlayController_Test.h> | ||
|
||
#import <OCMock/OCMock.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be grouped with the other framework imports. Grouping is by type of thing import, not by @
vs #
.
/// Returns true if a ground overlay with the given identifier exists on the map. | ||
- (bool)hasGroundOverlaysWithIdentifier:(NSString *)identifier; | ||
|
||
/// Returns FGMPlatformGroundOverlay for identifier. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"Returns the ground overlay with the given identifier."
registrar:(NSObject<FlutterPluginRegistrar> *)registrar | ||
screenScale:(CGFloat)screenScale { | ||
[self setConsumeTapEvents:groundOverlay.clickable]; | ||
[self setVisible:groundOverlay.visible]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on investigation of similar methods in a recent PR (which hasn't landed), this needs to be last to avoid potential flickering (likely due to Google Maps using its own render thread), so should be at the end of the method, and have a comment saying that nothing should be added after it.
} | ||
|
||
- (void)didTapGroundOverlayWithIdentifier:(NSString *)identifier { | ||
if (!identifier) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's still here in this method.
static UIImage *scaleImage(UIImage *image, double scale); | ||
static UIImage *scaledImageWithScale(UIImage *image, CGFloat scale); | ||
static UIImage *scaledImageWithSize(UIImage *image, CGSize size); | ||
static UIImage *scaledImage(UIImage *image, NSNumber *width, NSNumber *height, CGFloat screenScale); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The declaration comments for all of these functions should be here, on the declarations, rather than on the definitions below.
#import "FGMImageUtils.h" | ||
#import "Foundation/Foundation.h" | ||
|
||
static UIImage *scaleImage(UIImage *image, double scale); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be scaled
, not scale
, for consistency in naming.
NSNumber *zoomLevel) { | ||
/// Dummy image is used as image is required field of FGMPlatformGroundOverlay and converting | ||
/// image back to bitmap image is not currently supported. | ||
FGMPlatformBitmap *mockImage = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be called placeholderImage
rather than mockImage
, as "mock" generally refers to a specific test construct.
…#8518) This PR contains platform interface for the upcoming ground overlays support (#8432). Original PR with all the changes hasn't been approved yet but it was [okayed](#8432 (review)) to create the first sub-PR. I'm not the author of the original PR but helping @jokerttu while he's on vacation. Linked issue: flutter/flutter#26479
9f427b8
to
cda9938
Compare
I've addressed the last remaining review comments and split the platform-specific implementations into a separate PR: #8563. |
* @return the identifier of the ground overlay. | ||
* @throws IllegalArgumentException if required fields are missing or invalid. | ||
*/ | ||
static String interpretGroundOverlayOptions( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add non null or nullable annotations to the objects in this method.
* asset files stored in the application's assets directory. | ||
* @param density the density of the display, used to calculate pixel dimensions. | ||
* @param wrapper the BitmapDescriptorFactoryWrapper to create BitmapDescriptor. | ||
* @return the identifier of the ground overlay. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you know can you add more about the mutability of the ground overlay identifier. For example how long it is a valid id.
sink.setClickable(groundOverlay.getClickable()); | ||
sink.setImage(toBitmapDescriptor(groundOverlay.getImage(), assetManager, density, wrapper)); | ||
if (groundOverlay.getPosition() != null) { | ||
assert groundOverlay.getWidth() != null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Asserts I believe are compiled out so the else condition can still NPE here. Can you convert this assert to a check or handle null width?
sink.setImage(toBitmapDescriptor(groundOverlay.getImage(), assetManager, density, wrapper)); | ||
if (groundOverlay.getPosition() != null) { | ||
assert groundOverlay.getWidth() != null; | ||
if (groundOverlay.getHeight() != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe these are the same except the width value. Can you minimize the scope by either making the check cover width only?
new Messages.PlatformGroundOverlay.Builder() | ||
.setGroundOverlayId(groundOverlayId) | ||
.setImage(dummyImage) | ||
.setWidth((double) groundOverlay.getWidth()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why use doubles here but floats above for width?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pigeon uses doubles and google maps uses floats, so conversion between these need to be done while converting values between PlatformGroundOverlay and GoogleMaps SDK GroundOverlay object
.setVisible(groundOverlay.isVisible()) | ||
.setClickable(groundOverlay.isClickable()); | ||
|
||
if (isCreatedWithBounds) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is possible to determine this instead of having it be passed in? For example could a non null getBounds or getPosition indicate that one of those should be used?
The code above in interpretGroundOverlayOptions
seem to imply that position is more important that bounds. This code seem to imply that if bounds are used then position should not be.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Google maps object internally have both, bounds and position when the object is created using either of them. When bounds are used, the position representes the achor point in LatLng format for the ground overlay. And if position (with width/height) the bounds are calculated automatically as well.
For integration testing purposes we need track which creation method was used, to be able to check that conversions are handled correctly on each platform.
|
||
/** Receiver of GroundOverlayOptions configuration. */ | ||
interface GroundOverlaySink { | ||
void setTransparency(float transparency); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add javadocs to these methods for where someone can learn more about the inputs either here or in groundOverlayController
For example what are the min and max values for transparency. Can zindex be negative? what does setClickable do? etc.
GroundOverlayController groundOverlayController = | ||
groundOverlayIdToController.get(groundOverlayId); | ||
if (groundOverlayController != null) { | ||
groundOverlayController.remove(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the order of these removals matter? if so please add a comment explaining the order.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Order does not matter here
String groundOverlayId = platformGroundOverlay.getGroundOverlayId(); | ||
GroundOverlayController groundOverlayController = | ||
groundOverlayIdToController.get(groundOverlayId); | ||
if (groundOverlayController != null) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is an error to call this with something that cant get a groundOverlayController? If so whos error is it (plugin or host app)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Api has updateGroundOverlays method takes GroundOverlayUpdates object as parameter:
https://github.com/flutter/packages/blob/ff7724c18a803542fc709f942c3bf1cecf7e4864/packages/google_maps_flutter/google_maps_flutter_platform_interface/lib/src/types/ground_overlay_updates.dart
This should be handled by the dart code so that changes only contains items that are available on map.
Not sure would it be good to throw error here if change is triggered for groundoverlay that is not added to the map beforehand. It is indeed misuse of the api, and this is tested in integration tests.
dcf54a1
to
caf5ead
Compare
This PR contains platform implementations for the ground overlays support (#8432). Linked issue: flutter/flutter#26479
caf5ead
to
89366c8
Compare
@stuartmorgan This PR now contains only app-facing plugin changes. packages/packages/google_maps_flutter/google_maps_flutter_android/pubspec.yaml Lines 7 to 9 in 297d5a1
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
flutter/packages@d450e1b...dd781d4 2025-03-19 [email protected] [camera_avfoundation] Tests backfilling - part 4 (flutter/packages#8854) 2025-03-18 [email protected] [camera_avfoundation] Tests backfilling - part 5 (flutter/packages#8873) 2025-03-18 [email protected] [video_player]: reduce video player position update interval from 500ms to 100ms (flutter/packages#8346) 2025-03-18 [email protected] [google_maps_flutter] Support for Ground Overlay (flutter/packages#8432) 2025-03-18 [email protected] [google_maps_flutter] Ground overlay support - platform impls (flutter/packages#8563) 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-flutter-autoroll Please CC [email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: 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
Adds Ground Overlay support for google_maps_flutter plugin.
Fixes flutter/flutter#26479
Android:

iOS:

Web:

Documentation for groundOverlays parameter on app-facing plugin:

Pre-launch Checklist
dart format
.)[shared_preferences]
pubspec.yaml
with an appropriate new version according to the pub versioning philosophy, or this PR is exempt from version changes.CHANGELOG.md
to add a description of the change, following repository CHANGELOG style, or this PR is exempt from CHANGELOG changes.///
).If you need help, consider asking for advice on the #hackers-new channel on Discord.