Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

[google_maps_flutter] Maps snapshot #1719

Closed
wants to merge 23 commits into from
Closed
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
50d99f8
[google_maps_flutter] snapshot on android
duzenko Jun 10, 2019
9cb8757
iOS side + formatting
duzenko Jun 10, 2019
51a499e
Merge branch 'master' into maps-snapshot
duzenko Jun 10, 2019
d4a7b4c
Post merge fixes
duzenko Jun 10, 2019
e30a8b6
Format
duzenko Jun 10, 2019
d661056
Analizer appeased
duzenko Jun 11, 2019
346dee6
Merge branch 'maps-snapshot' of https://github.com/duzenko/plugins in…
duzenko Jun 11, 2019
fb894e8
Merge remote-tracking branch 'upstream/master' into maps-snapshot
duzenko Jun 11, 2019
0b9963b
Merge remote-tracking branch 'upstream/master' into maps-snapshot
duzenko Jun 11, 2019
b7bd02b
Merge branch 'maps-snapshot' of https://github.com/duzenko/plugins in…
duzenko Jun 11, 2019
c04d235
Check failure blind shooting
duzenko Jun 11, 2019
cfe1f59
Blind shooting
duzenko Jun 11, 2019
cc16b6d
Reinstate my changes as the checking is seemingly broken
duzenko Jun 11, 2019
63a9b25
Merge commit '1e01c9e12d564642735e1a7308a21083b9769b11' into maps-sna…
duzenko Jun 13, 2019
ab7d53f
Merge remote-tracking branch 'upstream/master' into maps-snapshot
duzenko Jun 20, 2019
40148ca
Integration test. Bugfix.
duzenko Jun 20, 2019
5b0060a
Formatting
duzenko Jun 20, 2019
ef97946
Muckup revert
duzenko Jun 21, 2019
945e5d5
Merge commit '400bc414afb1e3088ff3c59b841149d1fba1a8e1' into maps-sna…
duzenko Jun 21, 2019
58afa69
iOS scaling fix
duzenko Jun 21, 2019
ec51343
Update main.dart
duzenko Jan 23, 2020
e0df524
Merge branch 'upstream-master' into maps-snapshot
duzenko Jan 24, 2020
ecc1560
formatting
Jan 28, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/google_maps_flutter/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
org.gradle.jvmargs=-Xmx1536M
#org.gradle.jvmargs=-Xmx1536M
duzenko marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import android.app.Application;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.os.Bundle;
import android.util.Log;
Expand All @@ -38,6 +39,7 @@
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.platform.PlatformView;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
Expand All @@ -61,6 +63,7 @@ final class GoogleMapController
OnMapReadyCallback,
GoogleMap.OnMapClickListener,
GoogleMap.OnMapLongClickListener,
GoogleMap.SnapshotReadyCallback,
GoogleMap.OnMarkerDragListener,
PlatformView {

Expand Down Expand Up @@ -229,6 +232,11 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) {
}
break;
}
case "map#snapshot":
{
googleMap.snapshot(this);
result.success(null);
}
case "map#getScreenCoordinate":
{
if (googleMap != null) {
Expand Down Expand Up @@ -464,6 +472,15 @@ public void onCircleClick(Circle circle) {
circlesController.onCircleTap(circle.getId());
}

@Override
public void onSnapshotReady(Bitmap bitmap) {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
bitmap.recycle();
methodChannel.invokeMethod("map#onSnapshot", byteArray);
}

@Override
public void dispose() {
if (disposed) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
org.gradle.jvmargs=-Xmx1536M
#org.gradle.jvmargs=-Xmx1536M
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

This comment has been minimized.

android.enableR8=true
android.useAndroidX=true
android.enableJetifier=true
66 changes: 46 additions & 20 deletions packages/google_maps_flutter/example/lib/map_ui.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

// ignore_for_file: public_member_api_docs

import 'dart:typed_data';
import 'dart:ui' as ui;
import 'package:flutter/material.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:flutter/services.dart' show rootBundle;
Expand Down Expand Up @@ -92,38 +94,29 @@ class MapUiBodyState extends State<MapUiBody> {
Widget _latLngBoundsToggler() {
return FlatButton(
child: Text(
_cameraTargetBounds.bounds == null
? 'bound camera target'
: 'release camera target',
_cameraTargetBounds.bounds == null ? 'bound camera target' : 'release camera target',
duzenko marked this conversation as resolved.
Show resolved Hide resolved
),
onPressed: () {
setState(() {
_cameraTargetBounds = _cameraTargetBounds.bounds == null
? CameraTargetBounds(sydneyBounds)
: CameraTargetBounds.unbounded;
_cameraTargetBounds = _cameraTargetBounds.bounds == null ? CameraTargetBounds(sydneyBounds) : CameraTargetBounds.unbounded;
});
},
);
}

Widget _zoomBoundsToggler() {
return FlatButton(
child: Text(_minMaxZoomPreference.minZoom == null
? 'bound zoom'
: 'release zoom'),
child: Text(_minMaxZoomPreference.minZoom == null ? 'bound zoom' : 'release zoom'),
onPressed: () {
setState(() {
_minMaxZoomPreference = _minMaxZoomPreference.minZoom == null
? const MinMaxZoomPreference(12.0, 16.0)
: MinMaxZoomPreference.unbounded;
_minMaxZoomPreference = _minMaxZoomPreference.minZoom == null ? const MinMaxZoomPreference(12.0, 16.0) : MinMaxZoomPreference.unbounded;
});
},
);
}

Widget _mapTypeCycler() {
final MapType nextType =
MapType.values[(_mapType.index + 1) % MapType.values.length];
final MapType nextType = MapType.values[(_mapType.index + 1) % MapType.values.length];
return FlatButton(
child: Text('change map type to $nextType'),
onPressed: () {
Expand Down Expand Up @@ -191,8 +184,7 @@ class MapUiBodyState extends State<MapUiBody> {

Widget _myLocationToggler() {
return FlatButton(
child: Text(
'${_myLocationButtonEnabled ? 'disable' : 'enable'} my location button'),
child: Text('${_myLocationButtonEnabled ? 'disable' : 'enable'} my location button'),
onPressed: () {
setState(() {
_myLocationEnabled = !_myLocationEnabled;
Expand All @@ -203,8 +195,7 @@ class MapUiBodyState extends State<MapUiBody> {

Widget _myLocationButtonToggler() {
return FlatButton(
child: Text(
'${_myLocationButtonEnabled ? 'disable' : 'enable'} my location button'),
child: Text('${_myLocationButtonEnabled ? 'disable' : 'enable'} my location button'),
onPressed: () {
setState(() {
_myLocationButtonEnabled = !_myLocationButtonEnabled;
Expand All @@ -213,6 +204,14 @@ class MapUiBodyState extends State<MapUiBody> {
);
}

Widget _snapshotter() {
return FlatButton(
child: const Text('make snapshot'),
onPressed: () {
_controller.snapshot();
});
}

Future<String> _getFileData(String path) async {
return await rootBundle.loadString(path);
}
Expand Down Expand Up @@ -261,6 +260,7 @@ class MapUiBodyState extends State<MapUiBody> {
myLocationEnabled: _myLocationEnabled,
myLocationButtonEnabled: _myLocationButtonEnabled,
onCameraMove: _updateCameraPosition,
onSnapshot: _snapshot,
);

final List<Widget> columnChildren = <Widget>[
Expand All @@ -282,8 +282,7 @@ class MapUiBodyState extends State<MapUiBody> {
child: ListView(
children: <Widget>[
Text('camera bearing: ${_position.bearing}'),
Text(
'camera target: ${_position.target.latitude.toStringAsFixed(4)},'
Text('camera target: ${_position.target.latitude.toStringAsFixed(4)},'
'${_position.target.longitude.toStringAsFixed(4)}'),
Text('camera zoom: ${_position.zoom}'),
Text('camera tilt: ${_position.tilt}'),
Expand All @@ -300,6 +299,7 @@ class MapUiBodyState extends State<MapUiBody> {
_indoorViewToggler(),
_myLocationToggler(),
_myLocationButtonToggler(),
_snapshotter(),
_nightModeToggler(),
],
),
Expand All @@ -320,9 +320,35 @@ class MapUiBodyState extends State<MapUiBody> {
}

void onMapCreated(GoogleMapController controller) {
_controller = controller;
duzenko marked this conversation as resolved.
Show resolved Hide resolved
setState(() {
_controller = controller;
_isMapCreated = true;
});
}

void _snapshot(Uint8List argument) async {
duzenko marked this conversation as resolved.
Show resolved Hide resolved
final ui.Codec codec = await ui.instantiateImageCodec(argument);
final ui.FrameInfo frame = await codec.getNextFrame();
final ui.Image img = frame.image;
print('${argument.length} bytes, ${img.width} x ${img.height} px');
await showDialog<void>(
context: context,
builder: (BuildContext context) {
return AlertDialog(
actions: <Widget>[
FlatButton(
child: const Text('OK'),
onPressed: () => Navigator.of(context).pop(),
)
],
content: Padding(
padding: const EdgeInsets.symmetric(vertical: 66),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[Image.memory(argument)],
)));
},
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,14 @@ - (void)onMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
} else if ([call.method isEqualToString:@"map#update"]) {
InterpretMapOptions(call.arguments[@"options"], self);
result(PositionToJson([self cameraPosition]));
} else if ([call.method isEqualToString:@"map#snapshot"]) {
UIGraphicsBeginImageContextWithOptions(_mapView.frame.size, NO, [UIScreen mainScreen].scale);
[_mapView.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage* screenShotImage = UIGraphicsGetImageFromCurrentImageContext();
NSData* imageData = UIImagePNGRepresentation(screenShotImage);
UIGraphicsEndImageContext();
result(nil);
[_channel invokeMethod:@"map#onSnapshot" arguments:imageData];
duzenko marked this conversation as resolved.
Show resolved Hide resolved
} else if ([call.method isEqualToString:@"map#getVisibleRegion"]) {
if (_mapView != nil) {
GMSVisibleRegion visibleRegion = _mapView.projection.visibleRegion;
Expand Down
29 changes: 15 additions & 14 deletions packages/google_maps_flutter/lib/src/controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ class GoogleMapController {
_GoogleMapState googleMapState,
) async {
assert(id != null);
final MethodChannel channel =
MethodChannel('plugins.flutter.io/google_maps_$id');
final MethodChannel channel = MethodChannel('plugins.flutter.io/google_maps_$id');
duzenko marked this conversation as resolved.
Show resolved Hide resolved
await channel.invokeMethod<void>('map#waitForMap');
return GoogleMapController._(
channel,
Expand Down Expand Up @@ -65,8 +64,7 @@ class GoogleMapController {
_googleMapState.onMarkerTap(call.arguments['markerId']);
break;
case 'marker#onDragEnd':
_googleMapState.onMarkerDragEnd(call.arguments['markerId'],
LatLng._fromJson(call.arguments['position']));
_googleMapState.onMarkerDragEnd(call.arguments['markerId'], LatLng._fromJson(call.arguments['position']));
break;
case 'infoWindow#onTap':
_googleMapState.onInfoWindowTap(call.arguments['markerId']);
Expand All @@ -84,8 +82,10 @@ class GoogleMapController {
_googleMapState.onTap(LatLng._fromJson(call.arguments['position']));
break;
case 'map#onLongPress':
_googleMapState
.onLongPress(LatLng._fromJson(call.arguments['position']));
_googleMapState.onLongPress(LatLng._fromJson(call.arguments['position']));
break;
case 'map#onSnapshot':
_googleMapState.onSnaphot(call.arguments);
break;
default:
throw MissingPluginException();
Expand Down Expand Up @@ -198,8 +198,7 @@ class GoogleMapController {
/// and [Android](https://developers.google.com/maps/documentation/android-sdk/style-reference)
/// style reference for more information regarding the supported styles.
Future<void> setMapStyle(String mapStyle) async {
final List<dynamic> successAndError =
await channel.invokeMethod<List<dynamic>>('map#setStyle', mapStyle);
final List<dynamic> successAndError = await channel.invokeMethod<List<dynamic>>('map#setStyle', mapStyle);
final bool success = successAndError[0];
if (!success) {
throw MapStyleException(successAndError[1]);
Expand All @@ -208,22 +207,25 @@ class GoogleMapController {

/// Return [LatLngBounds] defining the region that is visible in a map.
Future<LatLngBounds> getVisibleRegion() async {
final Map<String, dynamic> latLngBounds =
await channel.invokeMapMethod<String, dynamic>('map#getVisibleRegion');
final Map<String, dynamic> latLngBounds = await channel.invokeMapMethod<String, dynamic>('map#getVisibleRegion');
final LatLng southwest = LatLng._fromJson(latLngBounds['southwest']);
final LatLng northeast = LatLng._fromJson(latLngBounds['northeast']);

return LatLngBounds(northeast: northeast, southwest: southwest);
}

/// Ask for a snapshot to be returned via onSnapshot event
duzenko marked this conversation as resolved.
Show resolved Hide resolved
Future<void> snapshot() async {
await channel.invokeMethod<void>('map#snapshot');
}

/// Return [ScreenCoordinate] of the [LatLng] in the current map view.
///
/// A projection is used to translate between on screen location and geographic coordinates.
/// Screen location is in screen pixels (not display pixels) with respect to the top left corner
/// of the map, not necessarily of the whole screen.
Future<ScreenCoordinate> getScreenCoordinate(LatLng latLng) async {
final Map<String, int> point = await channel.invokeMapMethod<String, int>(
'map#getScreenCoordinate', latLng._toJson());
final Map<String, int> point = await channel.invokeMapMethod<String, int>('map#getScreenCoordinate', latLng._toJson());
return ScreenCoordinate(x: point['x'], y: point['y']);
}

Expand All @@ -232,8 +234,7 @@ class GoogleMapController {
/// Returned [LatLng] corresponds to a screen location. The screen location is specified in screen
/// pixels (not display pixels) relative to the top left of the map, not top left of the whole screen.
Future<LatLng> getLatLng(ScreenCoordinate screenCoordinate) async {
final List<dynamic> latLng = await channel.invokeMethod<List<dynamic>>(
'map#getLatLng', screenCoordinate._toJson());
final List<dynamic> latLng = await channel.invokeMethod<List<dynamic>>('map#getLatLng', screenCoordinate._toJson());
return LatLng(latLng[0], latLng[1]);
}
}
11 changes: 11 additions & 0 deletions packages/google_maps_flutter/lib/src/google_map.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class GoogleMap extends StatefulWidget {
this.onCameraIdle,
this.onTap,
this.onLongPress,
this.onSnapshot,
}) : assert(initialCameraPosition != null),
super(key: key);

Expand Down Expand Up @@ -136,6 +137,9 @@ class GoogleMap extends StatefulWidget {
/// Called every time a [GoogleMap] is long pressed.
final ArgumentCallback<LatLng> onLongPress;

/// Called when a snapshot has completed
duzenko marked this conversation as resolved.
Show resolved Hide resolved
final ArgumentCallback<Uint8List> onSnapshot;

/// True if a "My Location" layer should be shown on the map.
///
/// This layer includes a location indicator at the current device location,
Expand Down Expand Up @@ -375,6 +379,13 @@ class _GoogleMapState extends State<GoogleMap> {
widget.onLongPress(position);
}
}

void onSnaphot(Uint8List imgData) {
assert(imgData != null);
if (widget.onSnapshot != null) {
widget.onSnapshot(imgData);
}
}
}

/// Configuration options for the GoogleMaps user interface.
Expand Down