diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml
new file mode 100644
index 000000000..b6cfecda9
--- /dev/null
+++ b/.idea/codeStyleSettings.xml
@@ -0,0 +1,265 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.jscodeshiftignore b/.jscodeshiftignore
new file mode 100644
index 000000000..a78536177
--- /dev/null
+++ b/.jscodeshiftignore
@@ -0,0 +1,9 @@
+# To run a codeshift on the react-native-maps library, cd to the root dir and run:
+# jscodeshift -t PATH_TO_TRANSFORM . --ignore-config .jscodeshiftignore
+.idea
+android
+docs
+example
+gradle
+node_modules
+scripts
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5968b7e7b..50b2027bc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,13 @@
# Change Log
+## 0.15.3 (June 27, 2017)
+
+* iOS: [#1362](https://github.com/airbnb/react-native-maps/pull/1362) Updates for React 0.43-0.45 and React 16.
+* JS: [#1323](https://github.com/airbnb/react-native-maps/pull/1323) Updates for React 0.43-0.45 and React 16.
+* Android/iOS/JS: [#1440](https://github.com/airbnb/react-native-maps/pull/1440) Updates for React 0.43-0.45 and React 16.
+* iOS: [#1115](https://github.com/airbnb/react-native-maps/pull/1115) Fix animateToCoordinate and animateToRegion
+* Android: [#1403](https://github.com/airbnb/react-native-maps/pull/1403) Fix an NPE
+
## 0.15.2 (May 20, 2017)
* iOS: [#1351](https://github.com/airbnb/react-native-maps/pull/1351) Fix file references
diff --git a/README.md b/README.md
index 49d65ac72..91b22377b 100644
--- a/README.md
+++ b/README.md
@@ -207,7 +207,7 @@ Then add the AirGoogleMaps directory:
https://github.com/airbnb/react-native-maps/blob/1e71a21f39e7b88554852951f773c731c94680c9/docs/installation.md#ios
-An unoffical step-by-step guide is also available at https://gist.github.com/heron2014/e60fa003e9b117ce80d56bb1d5bfe9e0
+An unofficial step-by-step guide is also available at https://gist.github.com/heron2014/e60fa003e9b117ce80d56bb1d5bfe9e0
## Examples
diff --git a/docs/installation.md b/docs/installation.md
index 12842d7c6..ad9d4b383 100644
--- a/docs/installation.md
+++ b/docs/installation.md
@@ -123,6 +123,8 @@ Source: https://developers.google.com/maps/documentation/android-api/signup
## Troubleshooting
+If you get the error `duplicate symbols for architecture x86_64` when building for iOS, you may need to reconfigure your linking and Podfile as [described in detail in this comment on issue #718](https://github.com/airbnb/react-native-maps/issues/718#issuecomment-295585410)
+
If you have a blank map issue, ([#118](https://github.com/airbnb/react-native-maps/issues/118), [#176](https://github.com/airbnb/react-native-maps/issues/176), [#684](https://github.com/airbnb/react-native-maps/issues/684)), try the following lines :
### On iOS:
@@ -203,7 +205,7 @@ Enter the name of the API key and create it.
1. Clean the cache :
```
watchman watch-del-all
- npm clean cache
+ npm cache clean
```
1. When starting emulator, make sure you have enabled `Wipe user data`.
diff --git a/example/android/app/build.gradle b/example/android/app/build.gradle
index c5bdebe4c..7a8e8b7dd 100644
--- a/example/android/app/build.gradle
+++ b/example/android/app/build.gradle
@@ -85,7 +85,7 @@ def enableProguardInReleaseBuilds = false
android {
compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ buildToolsVersion "25.0.3"
defaultConfig {
applicationId "com.airbnb.android.react.maps.example"
@@ -127,8 +127,8 @@ android {
}
dependencies {
- compile 'com.facebook.react:react-native:0.42.+'
- compile 'com.android.support:appcompat-v7:25.1.1'
- compile 'com.android.support:support-annotations:25.1.1'
+ compile 'com.facebook.react:react-native:0.45.+'
+ compile 'com.android.support:appcompat-v7:25.3.0'
+ compile 'com.android.support:support-annotations:25.3.0'
compile project(':react-native-maps-lib')
}
diff --git a/example/android/app/src/main/java/com/airbnb/android/react/maps/example/MainActivity.java b/example/android/app/src/main/java/com/airbnb/android/react/maps/example/MainActivity.java
index eec2349a4..12149c20e 100644
--- a/example/android/app/src/main/java/com/airbnb/android/react/maps/example/MainActivity.java
+++ b/example/android/app/src/main/java/com/airbnb/android/react/maps/example/MainActivity.java
@@ -4,14 +4,12 @@
public class MainActivity extends ReactActivity {
-
- /**
- * Returns the name of the main component registered from JavaScript.
- * This is used to schedule rendering of the component.
- */
- @Override
- protected String getMainComponentName() {
- return "AirMapsExplorer";
- }
-
+ /**
+ * Returns the name of the main component registered from JavaScript.
+ * This is used to schedule rendering of the component.
+ */
+ @Override
+ protected String getMainComponentName() {
+ return "AirMapsExplorer";
+ }
}
diff --git a/example/examples/DisplayLatLng.js b/example/examples/DisplayLatLng.js
index 573617d41..aa2dde2ac 100644
--- a/example/examples/DisplayLatLng.js
+++ b/example/examples/DisplayLatLng.js
@@ -43,15 +43,25 @@ class DisplayLatLng extends React.Component {
this.map.animateToRegion(this.randomRegion());
}
- randomRegion() {
- const { region } = this.state;
+ animateRandomCoordinate() {
+ this.map.animateToCoordinate(this.randomCoordinate());
+ }
+
+ randomCoordinate() {
+ const region = this.state.region;
return {
- ...this.state.region,
latitude: region.latitude + ((Math.random() - 0.5) * (region.latitudeDelta / 2)),
longitude: region.longitude + ((Math.random() - 0.5) * (region.longitudeDelta / 2)),
};
}
+ randomRegion() {
+ return {
+ ...this.state.region,
+ ...this.randomCoordinate(),
+ };
+ }
+
render() {
return (
@@ -74,13 +84,19 @@ class DisplayLatLng extends React.Component {
onPress={() => this.jumpRandom()}
style={[styles.bubble, styles.button]}
>
- Jump
+ Jump
this.animateRandom()}
style={[styles.bubble, styles.button]}
>
- Animate
+ Animate (Region)
+
+ this.animateRandomCoordinate()}
+ style={[styles.bubble, styles.button]}
+ >
+ Animate (Coordinate)
@@ -112,16 +128,20 @@ const styles = StyleSheet.create({
alignItems: 'stretch',
},
button: {
- width: 80,
- paddingHorizontal: 12,
+ width: 100,
+ paddingHorizontal: 8,
alignItems: 'center',
- marginHorizontal: 10,
+ justifyContent: 'center',
+ marginHorizontal: 5,
},
buttonContainer: {
flexDirection: 'row',
marginVertical: 20,
backgroundColor: 'transparent',
},
+ buttonText: {
+ textAlign: 'center',
+ },
});
module.exports = DisplayLatLng;
diff --git a/example/examples/EventListener.js b/example/examples/EventListener.js
index c8d3e937f..19a393063 100644
--- a/example/examples/EventListener.js
+++ b/example/examples/EventListener.js
@@ -7,7 +7,7 @@ import {
ScrollView,
} from 'react-native';
// eslint-disable-next-line max-len
-import SyntheticEvent from 'react-native/Libraries/Renderer/src/renderers/shared/stack/event/SyntheticEvent';
+import SyntheticEvent from 'react-native/Libraries/Renderer/src/renderers/shared/shared/event/SyntheticEvent';
import MapView from 'react-native-maps';
import PriceMarker from './PriceMarker';
diff --git a/example/ios/Podfile b/example/ios/Podfile
index 6cff9aae8..656f283e1 100644
--- a/example/ios/Podfile
+++ b/example/ios/Podfile
@@ -18,7 +18,8 @@ target 'AirMapsExplorer' do
'RCTSettings',
'RCTText',
'RCTVibration',
- 'RCTWebSocket'
+ 'RCTWebSocket',
+ 'BatchedBridge'
]
pod 'GoogleMaps' # <~~ remove this line if you do not want to support GoogleMaps on iOS
diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock
index ff6774aa2..3eec18fee 100644
--- a/example/ios/Podfile.lock
+++ b/example/ios/Podfile.lock
@@ -4,46 +4,49 @@ PODS:
- GoogleMaps/Base (2.1.1)
- GoogleMaps/Maps (2.1.1):
- GoogleMaps/Base
- - React (0.42.3):
- - React/Core (= 0.42.3)
- - react-native-google-maps (0.13.1):
+ - React (0.45.1):
+ - React/Core (= 0.45.1)
+ - react-native-google-maps (0.15.2):
- GoogleMaps (= 2.1.1)
- React
- - react-native-maps (0.13.1):
+ - react-native-maps (0.15.2):
- React
- - React/Core (0.42.3):
- - React/cxxreact
- - Yoga (= 0.42.3.React)
- - React/cxxreact (0.42.3):
- - React/jschelpers
- - React/jschelpers (0.42.3)
- - React/RCTActionSheet (0.42.3):
+ - React/BatchedBridge (0.45.1):
- React/Core
- - React/RCTAnimation (0.42.3):
+ - React/cxxreact_legacy
+ - React/Core (0.45.1):
+ - Yoga (= 0.45.1.React)
+ - React/cxxreact_legacy (0.45.1):
+ - React/jschelpers_legacy
+ - React/jschelpers_legacy (0.45.1)
+ - React/RCTActionSheet (0.45.1):
- React/Core
- - React/RCTGeolocation (0.42.3):
+ - React/RCTAnimation (0.45.1):
- React/Core
- - React/RCTImage (0.42.3):
+ - React/RCTGeolocation (0.45.1):
+ - React/Core
+ - React/RCTImage (0.45.1):
- React/Core
- React/RCTNetwork
- - React/RCTLinkingIOS (0.42.3):
+ - React/RCTLinkingIOS (0.45.1):
- React/Core
- - React/RCTNetwork (0.42.3):
+ - React/RCTNetwork (0.45.1):
- React/Core
- - React/RCTSettings (0.42.3):
+ - React/RCTSettings (0.45.1):
- React/Core
- - React/RCTText (0.42.3):
+ - React/RCTText (0.45.1):
- React/Core
- - React/RCTVibration (0.42.3):
+ - React/RCTVibration (0.45.1):
- React/Core
- - React/RCTWebSocket (0.42.3):
+ - React/RCTWebSocket (0.45.1):
- React/Core
- - Yoga (0.42.3.React)
+ - Yoga (0.45.1.React)
DEPENDENCIES:
- GoogleMaps
- react-native-google-maps (from `../../`)
- react-native-maps (from `../../`)
+ - React/BatchedBridge (from `../../node_modules/react-native`)
- React/Core (from `../../node_modules/react-native`)
- React/RCTActionSheet (from `../../node_modules/react-native`)
- React/RCTAnimation (from `../../node_modules/react-native`)
@@ -69,11 +72,11 @@ EXTERNAL SOURCES:
SPEC CHECKSUMS:
GoogleMaps: a5b5bbe47734e2443bde781a6aa64e69fdb6d785
- React: 35e039680feacd0563677d49ba410112d2748559
- react-native-google-maps: b2668747ec289759993dc2411a7078afafa8adea
- react-native-maps: 326ddbaaea8f6044b1817fb028c40950c71cc38a
- Yoga: 86ce777665c8259b94ef8dbea76b84634237f4ea
+ React: 0c9191a8b0c843d7004f950ac6b5f6cba9d125c7
+ react-native-google-maps: d0b8772eb76e1615ea32c73bc9d573360b8c0817
+ react-native-maps: fe2e4680b4d3fcfd84d636ccedd470fe358d55e1
+ Yoga: 89c8738d42a0b46a113acb4e574336d61cba2985
-PODFILE CHECKSUM: 222d08e48f834b6a3de650b72786105af7a9d331
+PODFILE CHECKSUM: 8b3eb68ef6553bf1fcb8a467e0e63000b37ec692
COCOAPODS: 1.2.0
diff --git a/examples/ios/bundler b/examples/ios/bundler
new file mode 100755
index 000000000..905387619
--- /dev/null
+++ b/examples/ios/bundler
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# This file was generated by Bundler.
+#
+# The application 'bundler' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("bundler", "bundler")
diff --git a/examples/ios/fuzzy_match b/examples/ios/fuzzy_match
new file mode 100755
index 000000000..f71547393
--- /dev/null
+++ b/examples/ios/fuzzy_match
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# This file was generated by Bundler.
+#
+# The application 'fuzzy_match' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("fuzzy_match", "fuzzy_match")
diff --git a/examples/ios/pod b/examples/ios/pod
new file mode 100755
index 000000000..3c4a4d04c
--- /dev/null
+++ b/examples/ios/pod
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# This file was generated by Bundler.
+#
+# The application 'pod' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("cocoapods", "pod")
diff --git a/examples/ios/sandbox-pod b/examples/ios/sandbox-pod
new file mode 100755
index 000000000..c76cfd0a5
--- /dev/null
+++ b/examples/ios/sandbox-pod
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# This file was generated by Bundler.
+#
+# The application 'sandbox-pod' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("cocoapods", "sandbox-pod")
diff --git a/examples/ios/xcodeproj b/examples/ios/xcodeproj
new file mode 100755
index 000000000..3c3452c17
--- /dev/null
+++ b/examples/ios/xcodeproj
@@ -0,0 +1,17 @@
+#!/usr/bin/env ruby
+# frozen_string_literal: true
+#
+# This file was generated by Bundler.
+#
+# The application 'xcodeproj' is installed as part of a gem, and
+# this file is here to facilitate running it.
+#
+
+require "pathname"
+ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../../Gemfile",
+ Pathname.new(__FILE__).realpath)
+
+require "rubygems"
+require "bundler/setup"
+
+load Gem.bin_path("xcodeproj", "xcodeproj")
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index c21e471fc..e5fa88cc4 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.5-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.0-all.zip
diff --git a/lib/android/build.gradle b/lib/android/build.gradle
index 434e63e72..326ab4bfa 100644
--- a/lib/android/build.gradle
+++ b/lib/android/build.gradle
@@ -3,7 +3,7 @@ apply from: 'gradle-maven-push.gradle'
android {
compileSdkVersion 25
- buildToolsVersion "25.0.2"
+ buildToolsVersion "25.0.3"
defaultConfig {
minSdkVersion 16
diff --git a/lib/android/gradle.properties b/lib/android/gradle.properties
index 307005f30..e17f7611f 100644
--- a/lib/android/gradle.properties
+++ b/lib/android/gradle.properties
@@ -1,5 +1,5 @@
VERSION_CODE=4
-VERSION_NAME=0.15.2
+VERSION_NAME=0.15.3
GROUP=com.airbnb.android
POM_DESCRIPTION=React Native Map view component for Android
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCallout.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCallout.java
index c434c9c12..6f96e15da 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCallout.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCallout.java
@@ -5,19 +5,19 @@
import com.facebook.react.views.view.ReactViewGroup;
public class AirMapCallout extends ReactViewGroup {
- private boolean tooltip = false;
- public int width;
- public int height;
+ private boolean tooltip = false;
+ public int width;
+ public int height;
- public AirMapCallout(Context context) {
- super(context);
- }
+ public AirMapCallout(Context context) {
+ super(context);
+ }
- public void setTooltip(boolean tooltip) {
- this.tooltip = tooltip;
- }
+ public void setTooltip(boolean tooltip) {
+ this.tooltip = tooltip;
+ }
- public boolean getTooltip() {
- return this.tooltip;
- }
+ public boolean getTooltip() {
+ return this.tooltip;
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCalloutManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCalloutManager.java
index 359e6847b..b63ea29ff 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCalloutManager.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCalloutManager.java
@@ -12,45 +12,45 @@
public class AirMapCalloutManager extends ViewGroupManager {
- @Override
- public String getName() {
- return "AIRMapCallout";
- }
-
- @Override
- public AirMapCallout createViewInstance(ThemedReactContext context) {
- return new AirMapCallout(context);
- }
-
- @ReactProp(name = "tooltip", defaultBoolean = false)
- public void setTooltip(AirMapCallout view, boolean tooltip) {
- view.setTooltip(tooltip);
- }
-
- @Override
- @Nullable
- public Map getExportedCustomDirectEventTypeConstants() {
- return MapBuilder.of("onPress", MapBuilder.of("registrationName", "onPress"));
- }
-
- @Override
- public LayoutShadowNode createShadowNodeInstance() {
- // we use a custom shadow node that emits the width/height of the view
- // after layout with the updateExtraData method. Without this, we can't generate
- // a bitmap of the appropriate width/height of the rendered view.
- return new SizeReportingShadowNode();
- }
-
- @Override
- public void updateExtraData(AirMapCallout view, Object extraData) {
- // This method is called from the shadow node with the width/height of the rendered
- // marker view.
- //noinspection unchecked
- Map data = (Map) extraData;
- float width = data.get("width");
- float height = data.get("height");
- view.width = (int) width;
- view.height = (int) height;
- }
+ @Override
+ public String getName() {
+ return "AIRMapCallout";
+ }
+
+ @Override
+ public AirMapCallout createViewInstance(ThemedReactContext context) {
+ return new AirMapCallout(context);
+ }
+
+ @ReactProp(name = "tooltip", defaultBoolean = false)
+ public void setTooltip(AirMapCallout view, boolean tooltip) {
+ view.setTooltip(tooltip);
+ }
+
+ @Override
+ @Nullable
+ public Map getExportedCustomDirectEventTypeConstants() {
+ return MapBuilder.of("onPress", MapBuilder.of("registrationName", "onPress"));
+ }
+
+ @Override
+ public LayoutShadowNode createShadowNodeInstance() {
+ // we use a custom shadow node that emits the width/height of the view
+ // after layout with the updateExtraData method. Without this, we can't generate
+ // a bitmap of the appropriate width/height of the rendered view.
+ return new SizeReportingShadowNode();
+ }
+
+ @Override
+ public void updateExtraData(AirMapCallout view, Object extraData) {
+ // This method is called from the shadow node with the width/height of the rendered
+ // marker view.
+ //noinspection unchecked
+ Map data = (Map) extraData;
+ float width = data.get("width");
+ float height = data.get("height");
+ view.width = (int) width;
+ view.height = (int) height;
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCircle.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCircle.java
index e428b04f6..a70d9146a 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCircle.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCircle.java
@@ -9,92 +9,92 @@
public class AirMapCircle extends AirMapFeature {
- private CircleOptions circleOptions;
- private Circle circle;
-
- private LatLng center;
- private double radius;
- private int strokeColor;
- private int fillColor;
- private float strokeWidth;
- private float zIndex;
-
- public AirMapCircle(Context context) {
- super(context);
+ private CircleOptions circleOptions;
+ private Circle circle;
+
+ private LatLng center;
+ private double radius;
+ private int strokeColor;
+ private int fillColor;
+ private float strokeWidth;
+ private float zIndex;
+
+ public AirMapCircle(Context context) {
+ super(context);
+ }
+
+ public void setCenter(LatLng center) {
+ this.center = center;
+ if (circle != null) {
+ circle.setCenter(this.center);
}
+ }
- public void setCenter(LatLng center) {
- this.center = center;
- if (circle != null) {
- circle.setCenter(this.center);
- }
+ public void setRadius(double radius) {
+ this.radius = radius;
+ if (circle != null) {
+ circle.setRadius(this.radius);
}
+ }
- public void setRadius(double radius) {
- this.radius = radius;
- if (circle != null) {
- circle.setRadius(this.radius);
- }
+ public void setFillColor(int color) {
+ this.fillColor = color;
+ if (circle != null) {
+ circle.setFillColor(color);
}
+ }
- public void setFillColor(int color) {
- this.fillColor = color;
- if (circle != null) {
- circle.setFillColor(color);
- }
+ public void setStrokeColor(int color) {
+ this.strokeColor = color;
+ if (circle != null) {
+ circle.setStrokeColor(color);
}
+ }
- public void setStrokeColor(int color) {
- this.strokeColor = color;
- if (circle != null) {
- circle.setStrokeColor(color);
- }
+ public void setStrokeWidth(float width) {
+ this.strokeWidth = width;
+ if (circle != null) {
+ circle.setStrokeWidth(width);
}
+ }
- public void setStrokeWidth(float width) {
- this.strokeWidth = width;
- if (circle != null) {
- circle.setStrokeWidth(width);
- }
+ public void setZIndex(float zIndex) {
+ this.zIndex = zIndex;
+ if (circle != null) {
+ circle.setZIndex(zIndex);
}
+ }
- public void setZIndex(float zIndex) {
- this.zIndex = zIndex;
- if (circle != null) {
- circle.setZIndex(zIndex);
- }
- }
-
- public CircleOptions getCircleOptions() {
- if (circleOptions == null) {
- circleOptions = createCircleOptions();
- }
- return circleOptions;
- }
-
- private CircleOptions createCircleOptions() {
- CircleOptions options = new CircleOptions();
- options.center(center);
- options.radius(radius);
- options.fillColor(fillColor);
- options.strokeColor(strokeColor);
- options.strokeWidth(strokeWidth);
- options.zIndex(zIndex);
- return options;
- }
-
- @Override
- public Object getFeature() {
- return circle;
- }
-
- @Override
- public void addToMap(GoogleMap map) {
- circle = map.addCircle(getCircleOptions());
- }
-
- @Override
- public void removeFromMap(GoogleMap map) {
- circle.remove();
+ public CircleOptions getCircleOptions() {
+ if (circleOptions == null) {
+ circleOptions = createCircleOptions();
}
+ return circleOptions;
+ }
+
+ private CircleOptions createCircleOptions() {
+ CircleOptions options = new CircleOptions();
+ options.center(center);
+ options.radius(radius);
+ options.fillColor(fillColor);
+ options.strokeColor(strokeColor);
+ options.strokeWidth(strokeWidth);
+ options.zIndex(zIndex);
+ return options;
+ }
+
+ @Override
+ public Object getFeature() {
+ return circle;
+ }
+
+ @Override
+ public void addToMap(GoogleMap map) {
+ circle = map.addCircle(getCircleOptions());
+ }
+
+ @Override
+ public void removeFromMap(GoogleMap map) {
+ circle.remove();
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCircleManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCircleManager.java
index c0eaf8f14..c8eabf2d1 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCircleManager.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapCircleManager.java
@@ -14,59 +14,59 @@
import com.google.android.gms.maps.model.LatLng;
public class AirMapCircleManager extends ViewGroupManager {
- private final DisplayMetrics metrics;
+ private final DisplayMetrics metrics;
- public AirMapCircleManager(ReactApplicationContext reactContext) {
- super();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- metrics = new DisplayMetrics();
- ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay()
- .getRealMetrics(metrics);
- } else {
- metrics = reactContext.getResources().getDisplayMetrics();
- }
+ public AirMapCircleManager(ReactApplicationContext reactContext) {
+ super();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ metrics = new DisplayMetrics();
+ ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay()
+ .getRealMetrics(metrics);
+ } else {
+ metrics = reactContext.getResources().getDisplayMetrics();
}
+ }
- @Override
- public String getName() {
- return "AIRMapCircle";
- }
+ @Override
+ public String getName() {
+ return "AIRMapCircle";
+ }
- @Override
- public AirMapCircle createViewInstance(ThemedReactContext context) {
- return new AirMapCircle(context);
- }
+ @Override
+ public AirMapCircle createViewInstance(ThemedReactContext context) {
+ return new AirMapCircle(context);
+ }
- @ReactProp(name = "center")
- public void setCenter(AirMapCircle view, ReadableMap center) {
- view.setCenter(new LatLng(center.getDouble("latitude"), center.getDouble("longitude")));
- }
+ @ReactProp(name = "center")
+ public void setCenter(AirMapCircle view, ReadableMap center) {
+ view.setCenter(new LatLng(center.getDouble("latitude"), center.getDouble("longitude")));
+ }
- @ReactProp(name = "radius", defaultDouble = 0)
- public void setRadius(AirMapCircle view, double radius) {
- view.setRadius(radius);
- }
+ @ReactProp(name = "radius", defaultDouble = 0)
+ public void setRadius(AirMapCircle view, double radius) {
+ view.setRadius(radius);
+ }
- @ReactProp(name = "strokeWidth", defaultFloat = 1f)
- public void setStrokeWidth(AirMapCircle view, float widthInPoints) {
- float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS
- view.setStrokeWidth(widthInScreenPx);
- }
+ @ReactProp(name = "strokeWidth", defaultFloat = 1f)
+ public void setStrokeWidth(AirMapCircle view, float widthInPoints) {
+ float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS
+ view.setStrokeWidth(widthInScreenPx);
+ }
- @ReactProp(name = "fillColor", defaultInt = Color.RED, customType = "Color")
- public void setFillColor(AirMapCircle view, int color) {
- view.setFillColor(color);
- }
+ @ReactProp(name = "fillColor", defaultInt = Color.RED, customType = "Color")
+ public void setFillColor(AirMapCircle view, int color) {
+ view.setFillColor(color);
+ }
- @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color")
- public void setStrokeColor(AirMapCircle view, int color) {
- view.setStrokeColor(color);
- }
+ @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color")
+ public void setStrokeColor(AirMapCircle view, int color) {
+ view.setStrokeColor(color);
+ }
- @ReactProp(name = "zIndex", defaultFloat = 1.0f)
- public void setZIndex(AirMapCircle view, float zIndex) {
- view.setZIndex(zIndex);
- }
+ @ReactProp(name = "zIndex", defaultFloat = 1.0f)
+ public void setZIndex(AirMapCircle view, float zIndex) {
+ view.setZIndex(zIndex);
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapFeature.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapFeature.java
index 1c15ade5f..70484c1a4 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapFeature.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapFeature.java
@@ -6,13 +6,13 @@
import com.google.android.gms.maps.GoogleMap;
public abstract class AirMapFeature extends ReactViewGroup {
- public AirMapFeature(Context context) {
- super(context);
- }
+ public AirMapFeature(Context context) {
+ super(context);
+ }
- public abstract void addToMap(GoogleMap map);
+ public abstract void addToMap(GoogleMap map);
- public abstract void removeFromMap(GoogleMap map);
+ public abstract void removeFromMap(GoogleMap map);
- public abstract Object getFeature();
+ public abstract Object getFeature();
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapLiteManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapLiteManager.java
index 62495c5e4..619e36435 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapLiteManager.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapLiteManager.java
@@ -5,16 +5,16 @@
public class AirMapLiteManager extends AirMapManager {
- private static final String REACT_CLASS = "AIRMapLite";
+ private static final String REACT_CLASS = "AIRMapLite";
- @Override
- public String getName() {
- return REACT_CLASS;
- }
+ @Override
+ public String getName() {
+ return REACT_CLASS;
+ }
- public AirMapLiteManager(ReactApplicationContext context) {
- super(context);
- this.googleMapOptions = new GoogleMapOptions().liteMode(true);
- }
+ public AirMapLiteManager(ReactApplicationContext context) {
+ super(context);
+ this.googleMapOptions = new GoogleMapOptions().liteMode(true);
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java
index b6a975b77..e8f98a766 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapManager.java
@@ -4,7 +4,6 @@
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.WritableMap;
@@ -17,7 +16,6 @@
import com.facebook.react.uimanager.events.RCTEventEmitter;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMapOptions;
-import com.google.android.gms.maps.MapsInitializer;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.LatLngBounds;
import com.google.android.gms.maps.model.MapStyleOptions;
@@ -28,280 +26,290 @@
public class AirMapManager extends ViewGroupManager {
- private static final String REACT_CLASS = "AIRMap";
- private static final int ANIMATE_TO_REGION = 1;
- private static final int ANIMATE_TO_COORDINATE = 2;
- private static final int FIT_TO_ELEMENTS = 3;
- private static final int FIT_TO_SUPPLIED_MARKERS = 4;
- private static final int FIT_TO_COORDINATES = 5;
-
- private final Map MAP_TYPES = MapBuilder.of(
- "standard", GoogleMap.MAP_TYPE_NORMAL,
- "satellite", GoogleMap.MAP_TYPE_SATELLITE,
- "hybrid", GoogleMap.MAP_TYPE_HYBRID,
- "terrain", GoogleMap.MAP_TYPE_TERRAIN,
- "none", GoogleMap.MAP_TYPE_NONE
- );
-
- private final ReactApplicationContext appContext;
-
- protected GoogleMapOptions googleMapOptions;
-
- public AirMapManager(ReactApplicationContext context) {
- this.appContext = context;
- this.googleMapOptions = new GoogleMapOptions();
- }
-
- @Override
- public String getName() {
- return REACT_CLASS;
- }
-
- @Override
- protected AirMapView createViewInstance(ThemedReactContext context) {
- return new AirMapView(context, this.appContext, this, googleMapOptions);
- }
-
- private void emitMapError(ThemedReactContext context, String message, String type) {
- WritableMap error = Arguments.createMap();
- error.putString("message", message);
- error.putString("type", type);
-
- context
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
- .emit("onError", error);
- }
-
- @ReactProp(name = "region")
- public void setRegion(AirMapView view, ReadableMap region) {
- view.setRegion(region);
- }
-
- @ReactProp(name = "mapType")
- public void setMapType(AirMapView view, @Nullable String mapType) {
- int typeId = MAP_TYPES.get(mapType);
- view.map.setMapType(typeId);
- }
-
- @ReactProp(name = "customMapStyleString")
- public void setMapStyle(AirMapView view, @Nullable String customMapStyleString) {
- view.map.setMapStyle(new MapStyleOptions(customMapStyleString));
- }
-
- @ReactProp(name = "showsUserLocation", defaultBoolean = false)
- public void setShowsUserLocation(AirMapView view, boolean showUserLocation) {
- view.setShowsUserLocation(showUserLocation);
- }
-
- @ReactProp(name = "showsMyLocationButton", defaultBoolean = true)
- public void setShowsMyLocationButton(AirMapView view, boolean showMyLocationButton) {
- view.setShowsMyLocationButton(showMyLocationButton);
- }
-
- @ReactProp(name = "toolbarEnabled", defaultBoolean = true)
- public void setToolbarEnabled(AirMapView view, boolean toolbarEnabled) {
- view.setToolbarEnabled(toolbarEnabled);
- }
-
- // This is a private prop to improve performance of panDrag by disabling it when the callback is not set
- @ReactProp(name = "handlePanDrag", defaultBoolean = false)
- public void setHandlePanDrag(AirMapView view, boolean handlePanDrag) {
- view.setHandlePanDrag(handlePanDrag);
- }
-
- @ReactProp(name = "showsTraffic", defaultBoolean = false)
- public void setShowTraffic(AirMapView view, boolean showTraffic) {
- view.map.setTrafficEnabled(showTraffic);
- }
-
- @ReactProp(name = "showsBuildings", defaultBoolean = false)
- public void setShowBuildings(AirMapView view, boolean showBuildings) {
- view.map.setBuildingsEnabled(showBuildings);
- }
-
- @ReactProp(name = "showsIndoors", defaultBoolean = false)
- public void setShowIndoors(AirMapView view, boolean showIndoors) {
- view.map.setIndoorEnabled(showIndoors);
- }
-
- @ReactProp(name = "showsIndoorLevelPicker", defaultBoolean = false)
- public void setShowsIndoorLevelPicker(AirMapView view, boolean showsIndoorLevelPicker) {
- view.map.getUiSettings().setIndoorLevelPickerEnabled(showsIndoorLevelPicker);
- }
-
- @ReactProp(name = "showsCompass", defaultBoolean = false)
- public void setShowsCompass(AirMapView view, boolean showsCompass) {
- view.map.getUiSettings().setCompassEnabled(showsCompass);
- }
-
- @ReactProp(name = "scrollEnabled", defaultBoolean = false)
- public void setScrollEnabled(AirMapView view, boolean scrollEnabled) {
- view.map.getUiSettings().setScrollGesturesEnabled(scrollEnabled);
- }
-
- @ReactProp(name = "zoomEnabled", defaultBoolean = false)
- public void setZoomEnabled(AirMapView view, boolean zoomEnabled) {
- view.map.getUiSettings().setZoomGesturesEnabled(zoomEnabled);
- }
-
- @ReactProp(name = "rotateEnabled", defaultBoolean = false)
- public void setRotateEnabled(AirMapView view, boolean rotateEnabled) {
- view.map.getUiSettings().setRotateGesturesEnabled(rotateEnabled);
- }
-
- @ReactProp(name = "cacheEnabled", defaultBoolean = false)
- public void setCacheEnabled(AirMapView view, boolean cacheEnabled) {
- view.setCacheEnabled(cacheEnabled);
- }
-
- @ReactProp(name = "loadingEnabled", defaultBoolean = false)
- public void setLoadingEnabled(AirMapView view, boolean loadingEnabled) {
- view.enableMapLoading(loadingEnabled);
- }
-
- @ReactProp(name = "moveOnMarkerPress", defaultBoolean = true)
- public void setMoveOnMarkerPress(AirMapView view, boolean moveOnPress) {
- view.setMoveOnMarkerPress(moveOnPress);
- }
-
- @ReactProp(name = "loadingBackgroundColor", customType = "Color")
- public void setLoadingBackgroundColor(AirMapView view, @Nullable Integer loadingBackgroundColor) {
- view.setLoadingBackgroundColor(loadingBackgroundColor);
- }
-
- @ReactProp(name = "loadingIndicatorColor", customType = "Color")
- public void setLoadingIndicatorColor(AirMapView view, @Nullable Integer loadingIndicatorColor) {
- view.setLoadingIndicatorColor(loadingIndicatorColor);
- }
-
- @ReactProp(name = "pitchEnabled", defaultBoolean = false)
- public void setPitchEnabled(AirMapView view, boolean pitchEnabled) {
- view.map.getUiSettings().setTiltGesturesEnabled(pitchEnabled);
- }
-
- @Override
- public void receiveCommand(AirMapView view, int commandId, @Nullable ReadableArray args) {
- Integer duration;
- Double lat;
- Double lng;
- Double lngDelta;
- Double latDelta;
- ReadableMap region;
-
- switch (commandId) {
- case ANIMATE_TO_REGION:
- region = args.getMap(0);
- duration = args.getInt(1);
- lng = region.getDouble("longitude");
- lat = region.getDouble("latitude");
- lngDelta = region.getDouble("longitudeDelta");
- latDelta = region.getDouble("latitudeDelta");
- LatLngBounds bounds = new LatLngBounds(
- new LatLng(lat - latDelta / 2, lng - lngDelta / 2), // southwest
- new LatLng(lat + latDelta / 2, lng + lngDelta / 2) // northeast
- );
- view.animateToRegion(bounds, duration);
- break;
-
- case ANIMATE_TO_COORDINATE:
- region = args.getMap(0);
- duration = args.getInt(1);
- lng = region.getDouble("longitude");
- lat = region.getDouble("latitude");
- view.animateToCoordinate(new LatLng(lat, lng), duration);
- break;
-
- case FIT_TO_ELEMENTS:
- view.fitToElements(args.getBoolean(0));
- break;
-
- case FIT_TO_SUPPLIED_MARKERS:
- view.fitToSuppliedMarkers(args.getArray(0), args.getBoolean(1));
- break;
- case FIT_TO_COORDINATES:
- view.fitToCoordinates(args.getArray(0), args.getMap(1), args.getBoolean(2));
- break;
- }
- }
-
- @Override
- @Nullable
- public Map getExportedCustomDirectEventTypeConstants() {
- Map> map = MapBuilder.of(
- "onMapReady", MapBuilder.of("registrationName", "onMapReady"),
- "onPress", MapBuilder.of("registrationName", "onPress"),
- "onLongPress", MapBuilder.of("registrationName", "onLongPress"),
- "onMarkerPress", MapBuilder.of("registrationName", "onMarkerPress"),
- "onMarkerSelect", MapBuilder.of("registrationName", "onMarkerSelect"),
- "onMarkerDeselect", MapBuilder.of("registrationName", "onMarkerDeselect"),
- "onCalloutPress", MapBuilder.of("registrationName", "onCalloutPress")
- );
-
- map.putAll(MapBuilder.of(
- "onMarkerDragStart", MapBuilder.of("registrationName", "onMarkerDragStart"),
- "onMarkerDrag", MapBuilder.of("registrationName", "onMarkerDrag"),
- "onMarkerDragEnd", MapBuilder.of("registrationName", "onMarkerDragEnd"),
- "onPanDrag", MapBuilder.of("registrationName", "onPanDrag")
- ));
-
- return map;
- }
-
- @Override
- @Nullable
- public Map getCommandsMap() {
- return MapBuilder.of(
- "animateToRegion", ANIMATE_TO_REGION,
- "animateToCoordinate", ANIMATE_TO_COORDINATE,
- "fitToElements", FIT_TO_ELEMENTS,
- "fitToSuppliedMarkers", FIT_TO_SUPPLIED_MARKERS,
- "fitToCoordinates", FIT_TO_COORDINATES
+ private static final String REACT_CLASS = "AIRMap";
+ private static final int ANIMATE_TO_REGION = 1;
+ private static final int ANIMATE_TO_COORDINATE = 2;
+ private static final int FIT_TO_ELEMENTS = 3;
+ private static final int FIT_TO_SUPPLIED_MARKERS = 4;
+ private static final int FIT_TO_COORDINATES = 5;
+
+ private final Map MAP_TYPES = MapBuilder.of(
+ "standard", GoogleMap.MAP_TYPE_NORMAL,
+ "satellite", GoogleMap.MAP_TYPE_SATELLITE,
+ "hybrid", GoogleMap.MAP_TYPE_HYBRID,
+ "terrain", GoogleMap.MAP_TYPE_TERRAIN,
+ "none", GoogleMap.MAP_TYPE_NONE
+ );
+
+ private final ReactApplicationContext appContext;
+
+ protected GoogleMapOptions googleMapOptions;
+
+ public AirMapManager(ReactApplicationContext context) {
+ this.appContext = context;
+ this.googleMapOptions = new GoogleMapOptions();
+ }
+
+ @Override
+ public String getName() {
+ return REACT_CLASS;
+ }
+
+ @Override
+ protected AirMapView createViewInstance(ThemedReactContext context) {
+ return new AirMapView(context, this.appContext, this, googleMapOptions);
+ }
+
+ private void emitMapError(ThemedReactContext context, String message, String type) {
+ WritableMap error = Arguments.createMap();
+ error.putString("message", message);
+ error.putString("type", type);
+
+ context
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
+ .emit("onError", error);
+ }
+
+ @ReactProp(name = "region")
+ public void setRegion(AirMapView view, ReadableMap region) {
+ view.setRegion(region);
+ }
+
+ @ReactProp(name = "mapType")
+ public void setMapType(AirMapView view, @Nullable String mapType) {
+ int typeId = MAP_TYPES.get(mapType);
+ view.map.setMapType(typeId);
+ }
+
+ @ReactProp(name = "customMapStyleString")
+ public void setMapStyle(AirMapView view, @Nullable String customMapStyleString) {
+ view.map.setMapStyle(new MapStyleOptions(customMapStyleString));
+ }
+
+ @ReactProp(name = "showsUserLocation", defaultBoolean = false)
+ public void setShowsUserLocation(AirMapView view, boolean showUserLocation) {
+ view.setShowsUserLocation(showUserLocation);
+ }
+
+ @ReactProp(name = "showsMyLocationButton", defaultBoolean = true)
+ public void setShowsMyLocationButton(AirMapView view, boolean showMyLocationButton) {
+ view.setShowsMyLocationButton(showMyLocationButton);
+ }
+
+ @ReactProp(name = "toolbarEnabled", defaultBoolean = true)
+ public void setToolbarEnabled(AirMapView view, boolean toolbarEnabled) {
+ view.setToolbarEnabled(toolbarEnabled);
+ }
+
+ // This is a private prop to improve performance of panDrag by disabling it when the callback
+ // is not set
+ @ReactProp(name = "handlePanDrag", defaultBoolean = false)
+ public void setHandlePanDrag(AirMapView view, boolean handlePanDrag) {
+ view.setHandlePanDrag(handlePanDrag);
+ }
+
+ @ReactProp(name = "showsTraffic", defaultBoolean = false)
+ public void setShowTraffic(AirMapView view, boolean showTraffic) {
+ view.map.setTrafficEnabled(showTraffic);
+ }
+
+ @ReactProp(name = "showsBuildings", defaultBoolean = false)
+ public void setShowBuildings(AirMapView view, boolean showBuildings) {
+ view.map.setBuildingsEnabled(showBuildings);
+ }
+
+ @ReactProp(name = "showsIndoors", defaultBoolean = false)
+ public void setShowIndoors(AirMapView view, boolean showIndoors) {
+ view.map.setIndoorEnabled(showIndoors);
+ }
+
+ @ReactProp(name = "showsIndoorLevelPicker", defaultBoolean = false)
+ public void setShowsIndoorLevelPicker(AirMapView view, boolean showsIndoorLevelPicker) {
+ view.map.getUiSettings().setIndoorLevelPickerEnabled(showsIndoorLevelPicker);
+ }
+
+ @ReactProp(name = "showsCompass", defaultBoolean = false)
+ public void setShowsCompass(AirMapView view, boolean showsCompass) {
+ view.map.getUiSettings().setCompassEnabled(showsCompass);
+ }
+
+ @ReactProp(name = "scrollEnabled", defaultBoolean = false)
+ public void setScrollEnabled(AirMapView view, boolean scrollEnabled) {
+ view.map.getUiSettings().setScrollGesturesEnabled(scrollEnabled);
+ }
+
+ @ReactProp(name = "zoomEnabled", defaultBoolean = false)
+ public void setZoomEnabled(AirMapView view, boolean zoomEnabled) {
+ view.map.getUiSettings().setZoomGesturesEnabled(zoomEnabled);
+ }
+
+ @ReactProp(name = "rotateEnabled", defaultBoolean = false)
+ public void setRotateEnabled(AirMapView view, boolean rotateEnabled) {
+ view.map.getUiSettings().setRotateGesturesEnabled(rotateEnabled);
+ }
+
+ @ReactProp(name = "cacheEnabled", defaultBoolean = false)
+ public void setCacheEnabled(AirMapView view, boolean cacheEnabled) {
+ view.setCacheEnabled(cacheEnabled);
+ }
+
+ @ReactProp(name = "loadingEnabled", defaultBoolean = false)
+ public void setLoadingEnabled(AirMapView view, boolean loadingEnabled) {
+ view.enableMapLoading(loadingEnabled);
+ }
+
+ @ReactProp(name = "moveOnMarkerPress", defaultBoolean = true)
+ public void setMoveOnMarkerPress(AirMapView view, boolean moveOnPress) {
+ view.setMoveOnMarkerPress(moveOnPress);
+ }
+
+ @ReactProp(name = "loadingBackgroundColor", customType = "Color")
+ public void setLoadingBackgroundColor(AirMapView view, @Nullable Integer loadingBackgroundColor) {
+ view.setLoadingBackgroundColor(loadingBackgroundColor);
+ }
+
+ @ReactProp(name = "loadingIndicatorColor", customType = "Color")
+ public void setLoadingIndicatorColor(AirMapView view, @Nullable Integer loadingIndicatorColor) {
+ view.setLoadingIndicatorColor(loadingIndicatorColor);
+ }
+
+ @ReactProp(name = "pitchEnabled", defaultBoolean = false)
+ public void setPitchEnabled(AirMapView view, boolean pitchEnabled) {
+ view.map.getUiSettings().setTiltGesturesEnabled(pitchEnabled);
+ }
+
+ @ReactProp(name = "minZoomLevel")
+ public void setMinZoomLevel(AirMapView view, float minZoomLevel) {
+ view.map.setMinZoomPreference(minZoomLevel);
+ }
+
+ @ReactProp(name = "maxZoomLevel")
+ public void setMaxZoomLevel(AirMapView view, float maxZoomLevel) {
+ view.map.setMaxZoomPreference(maxZoomLevel);
+ }
+
+ @Override
+ public void receiveCommand(AirMapView view, int commandId, @Nullable ReadableArray args) {
+ Integer duration;
+ Double lat;
+ Double lng;
+ Double lngDelta;
+ Double latDelta;
+ ReadableMap region;
+
+ switch (commandId) {
+ case ANIMATE_TO_REGION:
+ region = args.getMap(0);
+ duration = args.getInt(1);
+ lng = region.getDouble("longitude");
+ lat = region.getDouble("latitude");
+ lngDelta = region.getDouble("longitudeDelta");
+ latDelta = region.getDouble("latitudeDelta");
+ LatLngBounds bounds = new LatLngBounds(
+ new LatLng(lat - latDelta / 2, lng - lngDelta / 2), // southwest
+ new LatLng(lat + latDelta / 2, lng + lngDelta / 2) // northeast
);
- }
-
- @Override
- public LayoutShadowNode createShadowNodeInstance() {
- // A custom shadow node is needed in order to pass back the width/height of the map to the
- // view manager so that it can start applying camera moves with bounds.
- return new SizeReportingShadowNode();
- }
-
- @Override
- public void addView(AirMapView parent, View child, int index) {
- parent.addFeature(child, index);
- }
-
- @Override
- public int getChildCount(AirMapView view) {
- return view.getFeatureCount();
- }
-
- @Override
- public View getChildAt(AirMapView view, int index) {
- return view.getFeatureAt(index);
- }
-
- @Override
- public void removeViewAt(AirMapView parent, int index) {
- parent.removeFeatureAt(index);
- }
-
- @Override
- public void updateExtraData(AirMapView view, Object extraData) {
- view.updateExtraData(extraData);
- }
-
- void pushEvent(ThemedReactContext context, View view, String name, WritableMap data) {
- context.getJSModule(RCTEventEmitter.class)
- .receiveEvent(view.getId(), name, data);
- }
-
-
+ view.animateToRegion(bounds, duration);
+ break;
+
+ case ANIMATE_TO_COORDINATE:
+ region = args.getMap(0);
+ duration = args.getInt(1);
+ lng = region.getDouble("longitude");
+ lat = region.getDouble("latitude");
+ view.animateToCoordinate(new LatLng(lat, lng), duration);
+ break;
+
+ case FIT_TO_ELEMENTS:
+ view.fitToElements(args.getBoolean(0));
+ break;
+
+ case FIT_TO_SUPPLIED_MARKERS:
+ view.fitToSuppliedMarkers(args.getArray(0), args.getBoolean(1));
+ break;
+ case FIT_TO_COORDINATES:
+ view.fitToCoordinates(args.getArray(0), args.getMap(1), args.getBoolean(2));
+ break;
+ }
+ }
+
+ @Override
+ @Nullable
+ public Map getExportedCustomDirectEventTypeConstants() {
+ Map> map = MapBuilder.of(
+ "onMapReady", MapBuilder.of("registrationName", "onMapReady"),
+ "onPress", MapBuilder.of("registrationName", "onPress"),
+ "onLongPress", MapBuilder.of("registrationName", "onLongPress"),
+ "onMarkerPress", MapBuilder.of("registrationName", "onMarkerPress"),
+ "onMarkerSelect", MapBuilder.of("registrationName", "onMarkerSelect"),
+ "onMarkerDeselect", MapBuilder.of("registrationName", "onMarkerDeselect"),
+ "onCalloutPress", MapBuilder.of("registrationName", "onCalloutPress")
+ );
- @Override
- public void onDropViewInstance(AirMapView view) {
- view.doDestroy();
- super.onDropViewInstance(view);
- }
+ map.putAll(MapBuilder.of(
+ "onMarkerDragStart", MapBuilder.of("registrationName", "onMarkerDragStart"),
+ "onMarkerDrag", MapBuilder.of("registrationName", "onMarkerDrag"),
+ "onMarkerDragEnd", MapBuilder.of("registrationName", "onMarkerDragEnd"),
+ "onPanDrag", MapBuilder.of("registrationName", "onPanDrag")
+ ));
+
+ return map;
+ }
+
+ @Override
+ @Nullable
+ public Map getCommandsMap() {
+ return MapBuilder.of(
+ "animateToRegion", ANIMATE_TO_REGION,
+ "animateToCoordinate", ANIMATE_TO_COORDINATE,
+ "fitToElements", FIT_TO_ELEMENTS,
+ "fitToSuppliedMarkers", FIT_TO_SUPPLIED_MARKERS,
+ "fitToCoordinates", FIT_TO_COORDINATES
+ );
+ }
+
+ @Override
+ public LayoutShadowNode createShadowNodeInstance() {
+ // A custom shadow node is needed in order to pass back the width/height of the map to the
+ // view manager so that it can start applying camera moves with bounds.
+ return new SizeReportingShadowNode();
+ }
+
+ @Override
+ public void addView(AirMapView parent, View child, int index) {
+ parent.addFeature(child, index);
+ }
+
+ @Override
+ public int getChildCount(AirMapView view) {
+ return view.getFeatureCount();
+ }
+
+ @Override
+ public View getChildAt(AirMapView view, int index) {
+ return view.getFeatureAt(index);
+ }
+
+ @Override
+ public void removeViewAt(AirMapView parent, int index) {
+ parent.removeFeatureAt(index);
+ }
+
+ @Override
+ public void updateExtraData(AirMapView view, Object extraData) {
+ view.updateExtraData(extraData);
+ }
+
+ void pushEvent(ThemedReactContext context, View view, String name, WritableMap data) {
+ context.getJSModule(RCTEventEmitter.class)
+ .receiveEvent(view.getId(), name, data);
+ }
+
+
+ @Override
+ public void onDropViewInstance(AirMapView view) {
+ view.doDestroy();
+ super.onDropViewInstance(view);
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapMarker.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapMarker.java
index 4041d91ac..52c4dcd08 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapMarker.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapMarker.java
@@ -36,395 +36,395 @@
public class AirMapMarker extends AirMapFeature {
- private MarkerOptions markerOptions;
- private Marker marker;
- private int width;
- private int height;
- private String identifier;
-
- private LatLng position;
- private String title;
- private String snippet;
-
- private boolean anchorIsSet;
- private float anchorX;
- private float anchorY;
-
- private AirMapCallout calloutView;
- private View wrappedCalloutView;
- private final Context context;
-
- private float markerHue = 0.0f; // should be between 0 and 360
- private BitmapDescriptor iconBitmapDescriptor;
- private Bitmap iconBitmap;
-
- private float rotation = 0.0f;
- private boolean flat = false;
- private boolean draggable = false;
- private int zIndex = 0;
- private float opacity = 1.0f;
-
- private float calloutAnchorX;
- private float calloutAnchorY;
- private boolean calloutAnchorIsSet;
-
- private boolean hasCustomMarkerView = false;
-
- private final DraweeHolder> logoHolder;
- private DataSource> dataSource;
- private final ControllerListener mLogoControllerListener =
- new BaseControllerListener() {
- @Override
- public void onFinalImageSet(
- String id,
- @Nullable final ImageInfo imageInfo,
- @Nullable Animatable animatable) {
- CloseableReference imageReference = null;
- try {
- imageReference = dataSource.getResult();
- if (imageReference != null) {
- CloseableImage image = imageReference.get();
- if (image != null && image instanceof CloseableStaticBitmap) {
- CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) image;
- Bitmap bitmap = closeableStaticBitmap.getUnderlyingBitmap();
- if (bitmap != null) {
- bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
- iconBitmap = bitmap;
- iconBitmapDescriptor = BitmapDescriptorFactory.fromBitmap(bitmap);
- }
- }
- }
- } finally {
- dataSource.close();
- if (imageReference != null) {
- CloseableReference.closeSafely(imageReference);
- }
- }
- update();
+ private MarkerOptions markerOptions;
+ private Marker marker;
+ private int width;
+ private int height;
+ private String identifier;
+
+ private LatLng position;
+ private String title;
+ private String snippet;
+
+ private boolean anchorIsSet;
+ private float anchorX;
+ private float anchorY;
+
+ private AirMapCallout calloutView;
+ private View wrappedCalloutView;
+ private final Context context;
+
+ private float markerHue = 0.0f; // should be between 0 and 360
+ private BitmapDescriptor iconBitmapDescriptor;
+ private Bitmap iconBitmap;
+
+ private float rotation = 0.0f;
+ private boolean flat = false;
+ private boolean draggable = false;
+ private int zIndex = 0;
+ private float opacity = 1.0f;
+
+ private float calloutAnchorX;
+ private float calloutAnchorY;
+ private boolean calloutAnchorIsSet;
+
+ private boolean hasCustomMarkerView = false;
+
+ private final DraweeHolder> logoHolder;
+ private DataSource> dataSource;
+ private final ControllerListener mLogoControllerListener =
+ new BaseControllerListener() {
+ @Override
+ public void onFinalImageSet(
+ String id,
+ @Nullable final ImageInfo imageInfo,
+ @Nullable Animatable animatable) {
+ CloseableReference imageReference = null;
+ try {
+ imageReference = dataSource.getResult();
+ if (imageReference != null) {
+ CloseableImage image = imageReference.get();
+ if (image != null && image instanceof CloseableStaticBitmap) {
+ CloseableStaticBitmap closeableStaticBitmap = (CloseableStaticBitmap) image;
+ Bitmap bitmap = closeableStaticBitmap.getUnderlyingBitmap();
+ if (bitmap != null) {
+ bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
+ iconBitmap = bitmap;
+ iconBitmapDescriptor = BitmapDescriptorFactory.fromBitmap(bitmap);
}
- };
-
- public AirMapMarker(Context context) {
- super(context);
- this.context = context;
- logoHolder = DraweeHolder.create(createDraweeHierarchy(), context);
- logoHolder.onAttach();
- }
-
- private GenericDraweeHierarchy createDraweeHierarchy() {
- return new GenericDraweeHierarchyBuilder(getResources())
- .setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
- .setFadeDuration(0)
- .build();
- }
-
- public void setCoordinate(ReadableMap coordinate) {
- position = new LatLng(coordinate.getDouble("latitude"), coordinate.getDouble("longitude"));
- if (marker != null) {
- marker.setPosition(position);
- }
- update();
- }
-
- public void setIdentifier(String identifier) {
- this.identifier = identifier;
- update();
- }
-
- public String getIdentifier() {
- return this.identifier;
- }
-
- public void setTitle(String title) {
- this.title = title;
- if (marker != null) {
- marker.setTitle(title);
- }
- update();
- }
-
- public void setSnippet(String snippet) {
- this.snippet = snippet;
- if (marker != null) {
- marker.setSnippet(snippet);
- }
- update();
- }
-
- public void setRotation(float rotation) {
- this.rotation = rotation;
- if (marker != null) {
- marker.setRotation(rotation);
- }
- update();
- }
-
- public void setFlat(boolean flat) {
- this.flat = flat;
- if (marker != null) {
- marker.setFlat(flat);
- }
- update();
- }
-
- public void setDraggable(boolean draggable) {
- this.draggable = draggable;
- if (marker != null) {
- marker.setDraggable(draggable);
- }
- update();
- }
-
- public void setZIndex(int zIndex) {
- this.zIndex = zIndex;
- if (marker != null) {
- marker.setZIndex(zIndex);
- }
- update();
- }
-
- public void setOpacity(float opacity) {
- this.opacity = opacity;
- if (marker != null) {
- marker.setAlpha(opacity);
- }
- update();
- }
-
- public void setMarkerHue(float markerHue) {
- this.markerHue = markerHue;
- update();
- }
-
- public void setAnchor(double x, double y) {
- anchorIsSet = true;
- anchorX = (float) x;
- anchorY = (float) y;
- if (marker != null) {
- marker.setAnchor(anchorX, anchorY);
- }
- update();
- }
-
- public void setCalloutAnchor(double x, double y) {
- calloutAnchorIsSet = true;
- calloutAnchorX = (float) x;
- calloutAnchorY = (float) y;
- if (marker != null) {
- marker.setInfoWindowAnchor(calloutAnchorX, calloutAnchorY);
- }
- update();
- }
-
- public void setImage(String uri) {
- if (uri == null) {
- iconBitmapDescriptor = null;
- update();
- } else if (uri.startsWith("http://") || uri.startsWith("https://") ||
- uri.startsWith("file://")) {
- ImageRequest imageRequest = ImageRequestBuilder
- .newBuilderWithSource(Uri.parse(uri))
- .build();
-
- ImagePipeline imagePipeline = Fresco.getImagePipeline();
- dataSource = imagePipeline.fetchDecodedImage(imageRequest, this);
- DraweeController controller = Fresco.newDraweeControllerBuilder()
- .setImageRequest(imageRequest)
- .setControllerListener(mLogoControllerListener)
- .setOldController(logoHolder.getController())
- .build();
- logoHolder.setController(controller);
- } else {
- iconBitmapDescriptor = getBitmapDescriptorByName(uri);
- update();
- }
- }
-
- public MarkerOptions getMarkerOptions() {
- if (markerOptions == null) {
- markerOptions = createMarkerOptions();
- }
- return markerOptions;
- }
-
- @Override
- public void addView(View child, int index) {
- super.addView(child, index);
- // if children are added, it means we are rendering a custom marker
- if (!(child instanceof AirMapCallout)) {
- hasCustomMarkerView = true;
- }
- update();
- }
-
- @Override
- public Object getFeature() {
- return marker;
- }
-
- @Override
- public void addToMap(GoogleMap map) {
- marker = map.addMarker(getMarkerOptions());
- }
-
- @Override
- public void removeFromMap(GoogleMap map) {
- marker.remove();
- marker = null;
- }
-
- private BitmapDescriptor getIcon() {
- if (hasCustomMarkerView) {
- // creating a bitmap from an arbitrary view
- if (iconBitmapDescriptor != null) {
- Bitmap viewBitmap = createDrawable();
- int width = Math.max(iconBitmap.getWidth(), viewBitmap.getWidth());
- int height = Math.max(iconBitmap.getHeight(), viewBitmap.getHeight());
- Bitmap combinedBitmap = Bitmap.createBitmap(width, height, iconBitmap.getConfig());
- Canvas canvas = new Canvas(combinedBitmap);
- canvas.drawBitmap(iconBitmap, 0, 0, null);
- canvas.drawBitmap(viewBitmap, 0, 0, null);
- return BitmapDescriptorFactory.fromBitmap(combinedBitmap);
- } else {
- return BitmapDescriptorFactory.fromBitmap(createDrawable());
+ }
}
- } else if (iconBitmapDescriptor != null) {
- // use local image as a marker
- return iconBitmapDescriptor;
- } else {
- // render the default marker pin
- return BitmapDescriptorFactory.defaultMarker(this.markerHue);
- }
- }
-
- private MarkerOptions createMarkerOptions() {
- MarkerOptions options = new MarkerOptions().position(position);
- if (anchorIsSet) options.anchor(anchorX, anchorY);
- if (calloutAnchorIsSet) options.infoWindowAnchor(calloutAnchorX, calloutAnchorY);
- options.title(title);
- options.snippet(snippet);
- options.rotation(rotation);
- options.flat(flat);
- options.draggable(draggable);
- options.zIndex(zIndex);
- options.alpha(opacity);
- options.icon(getIcon());
- return options;
- }
-
- public void update() {
- if (marker == null) {
- return;
- }
-
- marker.setIcon(getIcon());
-
- if (anchorIsSet) {
- marker.setAnchor(anchorX, anchorY);
- } else {
- marker.setAnchor(0.5f, 1.0f);
- }
-
- if (calloutAnchorIsSet) {
- marker.setInfoWindowAnchor(calloutAnchorX, calloutAnchorY);
- } else {
- marker.setInfoWindowAnchor(0.5f, 0);
- }
- }
-
- public void update(int width, int height) {
- this.width = width;
- this.height = height;
- update();
- }
-
- private Bitmap createDrawable() {
- int width = this.width <= 0 ? 100 : this.width;
- int height = this.height <= 0 ? 100 : this.height;
- this.buildDrawingCache();
- Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
-
- Canvas canvas = new Canvas(bitmap);
- this.draw(canvas);
-
- return bitmap;
- }
-
- public void setCalloutView(AirMapCallout view) {
- this.calloutView = view;
- }
-
- public AirMapCallout getCalloutView() {
- return this.calloutView;
- }
-
- public View getCallout() {
- if (this.calloutView == null) return null;
-
- if (this.wrappedCalloutView == null) {
- this.wrapCalloutView();
- }
-
- if (this.calloutView.getTooltip()) {
- return this.wrappedCalloutView;
- } else {
- return null;
- }
- }
-
- public View getInfoContents() {
- if (this.calloutView == null) return null;
-
- if (this.wrappedCalloutView == null) {
- this.wrapCalloutView();
- }
-
- if (this.calloutView.getTooltip()) {
- return null;
- } else {
- return this.wrappedCalloutView;
+ } finally {
+ dataSource.close();
+ if (imageReference != null) {
+ CloseableReference.closeSafely(imageReference);
+ }
+ }
+ update();
}
+ };
+
+ public AirMapMarker(Context context) {
+ super(context);
+ this.context = context;
+ logoHolder = DraweeHolder.create(createDraweeHierarchy(), context);
+ logoHolder.onAttach();
+ }
+
+ private GenericDraweeHierarchy createDraweeHierarchy() {
+ return new GenericDraweeHierarchyBuilder(getResources())
+ .setActualImageScaleType(ScalingUtils.ScaleType.FIT_CENTER)
+ .setFadeDuration(0)
+ .build();
+ }
+
+ public void setCoordinate(ReadableMap coordinate) {
+ position = new LatLng(coordinate.getDouble("latitude"), coordinate.getDouble("longitude"));
+ if (marker != null) {
+ marker.setPosition(position);
+ }
+ update();
+ }
+
+ public void setIdentifier(String identifier) {
+ this.identifier = identifier;
+ update();
+ }
+
+ public String getIdentifier() {
+ return this.identifier;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ if (marker != null) {
+ marker.setTitle(title);
+ }
+ update();
+ }
+
+ public void setSnippet(String snippet) {
+ this.snippet = snippet;
+ if (marker != null) {
+ marker.setSnippet(snippet);
+ }
+ update();
+ }
+
+ public void setRotation(float rotation) {
+ this.rotation = rotation;
+ if (marker != null) {
+ marker.setRotation(rotation);
+ }
+ update();
+ }
+
+ public void setFlat(boolean flat) {
+ this.flat = flat;
+ if (marker != null) {
+ marker.setFlat(flat);
+ }
+ update();
+ }
+
+ public void setDraggable(boolean draggable) {
+ this.draggable = draggable;
+ if (marker != null) {
+ marker.setDraggable(draggable);
+ }
+ update();
+ }
+
+ public void setZIndex(int zIndex) {
+ this.zIndex = zIndex;
+ if (marker != null) {
+ marker.setZIndex(zIndex);
+ }
+ update();
+ }
+
+ public void setOpacity(float opacity) {
+ this.opacity = opacity;
+ if (marker != null) {
+ marker.setAlpha(opacity);
+ }
+ update();
+ }
+
+ public void setMarkerHue(float markerHue) {
+ this.markerHue = markerHue;
+ update();
+ }
+
+ public void setAnchor(double x, double y) {
+ anchorIsSet = true;
+ anchorX = (float) x;
+ anchorY = (float) y;
+ if (marker != null) {
+ marker.setAnchor(anchorX, anchorY);
+ }
+ update();
+ }
+
+ public void setCalloutAnchor(double x, double y) {
+ calloutAnchorIsSet = true;
+ calloutAnchorX = (float) x;
+ calloutAnchorY = (float) y;
+ if (marker != null) {
+ marker.setInfoWindowAnchor(calloutAnchorX, calloutAnchorY);
+ }
+ update();
+ }
+
+ public void setImage(String uri) {
+ if (uri == null) {
+ iconBitmapDescriptor = null;
+ update();
+ } else if (uri.startsWith("http://") || uri.startsWith("https://") ||
+ uri.startsWith("file://")) {
+ ImageRequest imageRequest = ImageRequestBuilder
+ .newBuilderWithSource(Uri.parse(uri))
+ .build();
+
+ ImagePipeline imagePipeline = Fresco.getImagePipeline();
+ dataSource = imagePipeline.fetchDecodedImage(imageRequest, this);
+ DraweeController controller = Fresco.newDraweeControllerBuilder()
+ .setImageRequest(imageRequest)
+ .setControllerListener(mLogoControllerListener)
+ .setOldController(logoHolder.getController())
+ .build();
+ logoHolder.setController(controller);
+ } else {
+ iconBitmapDescriptor = getBitmapDescriptorByName(uri);
+ update();
+ }
+ }
+
+ public MarkerOptions getMarkerOptions() {
+ if (markerOptions == null) {
+ markerOptions = createMarkerOptions();
+ }
+ return markerOptions;
+ }
+
+ @Override
+ public void addView(View child, int index) {
+ super.addView(child, index);
+ // if children are added, it means we are rendering a custom marker
+ if (!(child instanceof AirMapCallout)) {
+ hasCustomMarkerView = true;
+ }
+ update();
+ }
+
+ @Override
+ public Object getFeature() {
+ return marker;
+ }
+
+ @Override
+ public void addToMap(GoogleMap map) {
+ marker = map.addMarker(getMarkerOptions());
+ }
+
+ @Override
+ public void removeFromMap(GoogleMap map) {
+ marker.remove();
+ marker = null;
+ }
+
+ private BitmapDescriptor getIcon() {
+ if (hasCustomMarkerView) {
+ // creating a bitmap from an arbitrary view
+ if (iconBitmapDescriptor != null) {
+ Bitmap viewBitmap = createDrawable();
+ int width = Math.max(iconBitmap.getWidth(), viewBitmap.getWidth());
+ int height = Math.max(iconBitmap.getHeight(), viewBitmap.getHeight());
+ Bitmap combinedBitmap = Bitmap.createBitmap(width, height, iconBitmap.getConfig());
+ Canvas canvas = new Canvas(combinedBitmap);
+ canvas.drawBitmap(iconBitmap, 0, 0, null);
+ canvas.drawBitmap(viewBitmap, 0, 0, null);
+ return BitmapDescriptorFactory.fromBitmap(combinedBitmap);
+ } else {
+ return BitmapDescriptorFactory.fromBitmap(createDrawable());
+ }
+ } else if (iconBitmapDescriptor != null) {
+ // use local image as a marker
+ return iconBitmapDescriptor;
+ } else {
+ // render the default marker pin
+ return BitmapDescriptorFactory.defaultMarker(this.markerHue);
+ }
+ }
+
+ private MarkerOptions createMarkerOptions() {
+ MarkerOptions options = new MarkerOptions().position(position);
+ if (anchorIsSet) options.anchor(anchorX, anchorY);
+ if (calloutAnchorIsSet) options.infoWindowAnchor(calloutAnchorX, calloutAnchorY);
+ options.title(title);
+ options.snippet(snippet);
+ options.rotation(rotation);
+ options.flat(flat);
+ options.draggable(draggable);
+ options.zIndex(zIndex);
+ options.alpha(opacity);
+ options.icon(getIcon());
+ return options;
+ }
+
+ public void update() {
+ if (marker == null) {
+ return;
+ }
+
+ marker.setIcon(getIcon());
+
+ if (anchorIsSet) {
+ marker.setAnchor(anchorX, anchorY);
+ } else {
+ marker.setAnchor(0.5f, 1.0f);
+ }
+
+ if (calloutAnchorIsSet) {
+ marker.setInfoWindowAnchor(calloutAnchorX, calloutAnchorY);
+ } else {
+ marker.setInfoWindowAnchor(0.5f, 0);
+ }
+ }
+
+ public void update(int width, int height) {
+ this.width = width;
+ this.height = height;
+ update();
+ }
+
+ private Bitmap createDrawable() {
+ int width = this.width <= 0 ? 100 : this.width;
+ int height = this.height <= 0 ? 100 : this.height;
+ this.buildDrawingCache();
+ Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+
+ Canvas canvas = new Canvas(bitmap);
+ this.draw(canvas);
+
+ return bitmap;
+ }
+
+ public void setCalloutView(AirMapCallout view) {
+ this.calloutView = view;
+ }
+
+ public AirMapCallout getCalloutView() {
+ return this.calloutView;
+ }
+
+ public View getCallout() {
+ if (this.calloutView == null) return null;
+
+ if (this.wrappedCalloutView == null) {
+ this.wrapCalloutView();
+ }
+
+ if (this.calloutView.getTooltip()) {
+ return this.wrappedCalloutView;
+ } else {
+ return null;
+ }
+ }
+
+ public View getInfoContents() {
+ if (this.calloutView == null) return null;
+
+ if (this.wrappedCalloutView == null) {
+ this.wrapCalloutView();
+ }
+
+ if (this.calloutView.getTooltip()) {
+ return null;
+ } else {
+ return this.wrappedCalloutView;
+ }
+ }
+
+ private void wrapCalloutView() {
+ // some hackery is needed to get the arbitrary infowindow view to render centered, and
+ // with only the width/height that it needs.
+ if (this.calloutView == null || this.calloutView.getChildCount() == 0) {
+ return;
}
- private void wrapCalloutView() {
- // some hackery is needed to get the arbitrary infowindow view to render centered, and
- // with only the width/height that it needs.
- if (this.calloutView == null || this.calloutView.getChildCount() == 0) {
- return;
- }
+ LinearLayout LL = new LinearLayout(context);
+ LL.setOrientation(LinearLayout.VERTICAL);
+ LL.setLayoutParams(new LinearLayout.LayoutParams(
+ this.calloutView.width,
+ this.calloutView.height,
+ 0f
+ ));
- LinearLayout LL = new LinearLayout(context);
- LL.setOrientation(LinearLayout.VERTICAL);
- LL.setLayoutParams(new LinearLayout.LayoutParams(
- this.calloutView.width,
- this.calloutView.height,
- 0f
- ));
+ LinearLayout LL2 = new LinearLayout(context);
+ LL2.setOrientation(LinearLayout.HORIZONTAL);
+ LL2.setLayoutParams(new LinearLayout.LayoutParams(
+ this.calloutView.width,
+ this.calloutView.height,
+ 0f
+ ));
- LinearLayout LL2 = new LinearLayout(context);
- LL2.setOrientation(LinearLayout.HORIZONTAL);
- LL2.setLayoutParams(new LinearLayout.LayoutParams(
- this.calloutView.width,
- this.calloutView.height,
- 0f
- ));
+ LL.addView(LL2);
+ LL2.addView(this.calloutView);
- LL.addView(LL2);
- LL2.addView(this.calloutView);
+ this.wrappedCalloutView = LL;
+ }
- this.wrappedCalloutView = LL;
- }
+ private int getDrawableResourceByName(String name) {
+ return getResources().getIdentifier(
+ name,
+ "drawable",
+ getContext().getPackageName());
+ }
- private int getDrawableResourceByName(String name) {
- return getResources().getIdentifier(
- name,
- "drawable",
- getContext().getPackageName());
- }
-
- private BitmapDescriptor getBitmapDescriptorByName(String name) {
- return BitmapDescriptorFactory.fromResource(getDrawableResourceByName(name));
- }
+ private BitmapDescriptor getBitmapDescriptorByName(String name) {
+ return BitmapDescriptorFactory.fromResource(getDrawableResourceByName(name));
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapMarkerManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapMarkerManager.java
index e035e1e14..3aef3148c 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapMarkerManager.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapMarkerManager.java
@@ -19,46 +19,46 @@
public class AirMapMarkerManager extends ViewGroupManager {
- private static final int SHOW_INFO_WINDOW = 1;
- private static final int HIDE_INFO_WINDOW = 2;
-
- public AirMapMarkerManager() {
- }
-
- @Override
- public String getName() {
- return "AIRMapMarker";
- }
-
- @Override
- public AirMapMarker createViewInstance(ThemedReactContext context) {
- return new AirMapMarker(context);
- }
-
- @ReactProp(name = "coordinate")
- public void setCoordinate(AirMapMarker view, ReadableMap map) {
- view.setCoordinate(map);
- }
-
- @ReactProp(name = "title")
- public void setTitle(AirMapMarker view, String title) {
- view.setTitle(title);
- }
-
- @ReactProp(name = "identifier")
- public void setIdentifier(AirMapMarker view, String identifier) {
- view.setIdentifier(identifier);
- }
-
- @ReactProp(name = "description")
- public void setDescription(AirMapMarker view, String description) {
- view.setSnippet(description);
- }
-
- // NOTE(lmr):
- // android uses normalized coordinate systems for this, and is provided through the
- // `anchor` property and `calloutAnchor` instead. Perhaps some work could be done
- // to normalize iOS and android to use just one of the systems.
+ private static final int SHOW_INFO_WINDOW = 1;
+ private static final int HIDE_INFO_WINDOW = 2;
+
+ public AirMapMarkerManager() {
+ }
+
+ @Override
+ public String getName() {
+ return "AIRMapMarker";
+ }
+
+ @Override
+ public AirMapMarker createViewInstance(ThemedReactContext context) {
+ return new AirMapMarker(context);
+ }
+
+ @ReactProp(name = "coordinate")
+ public void setCoordinate(AirMapMarker view, ReadableMap map) {
+ view.setCoordinate(map);
+ }
+
+ @ReactProp(name = "title")
+ public void setTitle(AirMapMarker view, String title) {
+ view.setTitle(title);
+ }
+
+ @ReactProp(name = "identifier")
+ public void setIdentifier(AirMapMarker view, String identifier) {
+ view.setIdentifier(identifier);
+ }
+
+ @ReactProp(name = "description")
+ public void setDescription(AirMapMarker view, String description) {
+ view.setSnippet(description);
+ }
+
+ // NOTE(lmr):
+ // android uses normalized coordinate systems for this, and is provided through the
+ // `anchor` property and `calloutAnchor` instead. Perhaps some work could be done
+ // to normalize iOS and android to use just one of the systems.
// @ReactProp(name = "centerOffset")
// public void setCenterOffset(AirMapMarker view, ReadableMap map) {
//
@@ -69,143 +69,143 @@ public void setDescription(AirMapMarker view, String description) {
//
// }
- @ReactProp(name = "anchor")
- public void setAnchor(AirMapMarker view, ReadableMap map) {
- // should default to (0.5, 1) (bottom middle)
- double x = map != null && map.hasKey("x") ? map.getDouble("x") : 0.5;
- double y = map != null && map.hasKey("y") ? map.getDouble("y") : 1.0;
- view.setAnchor(x, y);
- }
-
- @ReactProp(name = "calloutAnchor")
- public void setCalloutAnchor(AirMapMarker view, ReadableMap map) {
- // should default to (0.5, 0) (top middle)
- double x = map != null && map.hasKey("x") ? map.getDouble("x") : 0.5;
- double y = map != null && map.hasKey("y") ? map.getDouble("y") : 0.0;
- view.setCalloutAnchor(x, y);
- }
-
- @ReactProp(name = "image")
- public void setImage(AirMapMarker view, @Nullable String source) {
- view.setImage(source);
- }
+ @ReactProp(name = "anchor")
+ public void setAnchor(AirMapMarker view, ReadableMap map) {
+ // should default to (0.5, 1) (bottom middle)
+ double x = map != null && map.hasKey("x") ? map.getDouble("x") : 0.5;
+ double y = map != null && map.hasKey("y") ? map.getDouble("y") : 1.0;
+ view.setAnchor(x, y);
+ }
+
+ @ReactProp(name = "calloutAnchor")
+ public void setCalloutAnchor(AirMapMarker view, ReadableMap map) {
+ // should default to (0.5, 0) (top middle)
+ double x = map != null && map.hasKey("x") ? map.getDouble("x") : 0.5;
+ double y = map != null && map.hasKey("y") ? map.getDouble("y") : 0.0;
+ view.setCalloutAnchor(x, y);
+ }
+
+ @ReactProp(name = "image")
+ public void setImage(AirMapMarker view, @Nullable String source) {
+ view.setImage(source);
+ }
// public void setImage(AirMapMarker view, ReadableMap image) {
// view.setImage(image);
// }
- @ReactProp(name = "pinColor", defaultInt = Color.RED, customType = "Color")
- public void setPinColor(AirMapMarker view, int pinColor) {
- float[] hsv = new float[3];
- Color.colorToHSV(pinColor, hsv);
- // NOTE: android only supports a hue
- view.setMarkerHue(hsv[0]);
- }
-
- @ReactProp(name = "rotation", defaultFloat = 0.0f)
- public void setMarkerRotation(AirMapMarker view, float rotation) {
- view.setRotation(rotation);
- }
-
- @ReactProp(name = "flat", defaultBoolean = false)
- public void setFlat(AirMapMarker view, boolean flat) {
- view.setFlat(flat);
- }
-
- @ReactProp(name = "draggable", defaultBoolean = false)
- public void setDraggable(AirMapMarker view, boolean draggable) {
- view.setDraggable(draggable);
- }
-
- @Override
- @ReactProp(name = "zIndex", defaultFloat = 0.0f)
- public void setZIndex(AirMapMarker view, float zIndex) {
- super.setZIndex(view, zIndex);
- int integerZIndex = Math.round(zIndex);
- view.setZIndex(integerZIndex);
- }
-
- @Override
- @ReactProp(name = "opacity", defaultFloat = 1.0f)
- public void setOpacity(AirMapMarker view, float opacity) {
- super.setOpacity(view, opacity);
- view.setOpacity(opacity);
- }
-
- @Override
- public void addView(AirMapMarker parent, View child, int index) {
- // if an component is a child, then it is a callout view, NOT part of the
- // marker.
- if (child instanceof AirMapCallout) {
- parent.setCalloutView((AirMapCallout) child);
- } else {
- super.addView(parent, child, index);
- parent.update();
- }
- }
-
- @Override
- public void removeViewAt(AirMapMarker parent, int index) {
- super.removeViewAt(parent, index);
- parent.update();
- }
-
- @Override
- @Nullable
- public Map getCommandsMap() {
- return MapBuilder.of(
- "showCallout", SHOW_INFO_WINDOW,
- "hideCallout", HIDE_INFO_WINDOW
- );
- }
-
- @Override
- public void receiveCommand(AirMapMarker view, int commandId, @Nullable ReadableArray args) {
- switch (commandId) {
- case SHOW_INFO_WINDOW:
- ((Marker) view.getFeature()).showInfoWindow();
- break;
-
- case HIDE_INFO_WINDOW:
- ((Marker) view.getFeature()).hideInfoWindow();
- break;
- }
- }
-
- @Override
- @Nullable
- public Map getExportedCustomDirectEventTypeConstants() {
- Map> map = MapBuilder.of(
- "onPress", MapBuilder.of("registrationName", "onPress"),
- "onCalloutPress", MapBuilder.of("registrationName", "onCalloutPress"),
- "onDragStart", MapBuilder.of("registrationName", "onDragStart"),
- "onDrag", MapBuilder.of("registrationName", "onDrag"),
- "onDragEnd", MapBuilder.of("registrationName", "onDragEnd")
- );
-
- map.putAll(MapBuilder.of(
- "onDragStart", MapBuilder.of("registrationName", "onDragStart"),
- "onDrag", MapBuilder.of("registrationName", "onDrag"),
- "onDragEnd", MapBuilder.of("registrationName", "onDragEnd")
- ));
-
- return map;
- }
-
- @Override
- public LayoutShadowNode createShadowNodeInstance() {
- // we use a custom shadow node that emits the width/height of the view
- // after layout with the updateExtraData method. Without this, we can't generate
- // a bitmap of the appropriate width/height of the rendered view.
- return new SizeReportingShadowNode();
- }
-
- @Override
- public void updateExtraData(AirMapMarker view, Object extraData) {
- // This method is called from the shadow node with the width/height of the rendered
- // marker view.
- HashMap data = (HashMap) extraData;
- float width = data.get("width");
- float height = data.get("height");
- view.update((int) width, (int) height);
- }
+ @ReactProp(name = "pinColor", defaultInt = Color.RED, customType = "Color")
+ public void setPinColor(AirMapMarker view, int pinColor) {
+ float[] hsv = new float[3];
+ Color.colorToHSV(pinColor, hsv);
+ // NOTE: android only supports a hue
+ view.setMarkerHue(hsv[0]);
+ }
+
+ @ReactProp(name = "rotation", defaultFloat = 0.0f)
+ public void setMarkerRotation(AirMapMarker view, float rotation) {
+ view.setRotation(rotation);
+ }
+
+ @ReactProp(name = "flat", defaultBoolean = false)
+ public void setFlat(AirMapMarker view, boolean flat) {
+ view.setFlat(flat);
+ }
+
+ @ReactProp(name = "draggable", defaultBoolean = false)
+ public void setDraggable(AirMapMarker view, boolean draggable) {
+ view.setDraggable(draggable);
+ }
+
+ @Override
+ @ReactProp(name = "zIndex", defaultFloat = 0.0f)
+ public void setZIndex(AirMapMarker view, float zIndex) {
+ super.setZIndex(view, zIndex);
+ int integerZIndex = Math.round(zIndex);
+ view.setZIndex(integerZIndex);
+ }
+
+ @Override
+ @ReactProp(name = "opacity", defaultFloat = 1.0f)
+ public void setOpacity(AirMapMarker view, float opacity) {
+ super.setOpacity(view, opacity);
+ view.setOpacity(opacity);
+ }
+
+ @Override
+ public void addView(AirMapMarker parent, View child, int index) {
+ // if an component is a child, then it is a callout view, NOT part of the
+ // marker.
+ if (child instanceof AirMapCallout) {
+ parent.setCalloutView((AirMapCallout) child);
+ } else {
+ super.addView(parent, child, index);
+ parent.update();
+ }
+ }
+
+ @Override
+ public void removeViewAt(AirMapMarker parent, int index) {
+ super.removeViewAt(parent, index);
+ parent.update();
+ }
+
+ @Override
+ @Nullable
+ public Map getCommandsMap() {
+ return MapBuilder.of(
+ "showCallout", SHOW_INFO_WINDOW,
+ "hideCallout", HIDE_INFO_WINDOW
+ );
+ }
+
+ @Override
+ public void receiveCommand(AirMapMarker view, int commandId, @Nullable ReadableArray args) {
+ switch (commandId) {
+ case SHOW_INFO_WINDOW:
+ ((Marker) view.getFeature()).showInfoWindow();
+ break;
+
+ case HIDE_INFO_WINDOW:
+ ((Marker) view.getFeature()).hideInfoWindow();
+ break;
+ }
+ }
+
+ @Override
+ @Nullable
+ public Map getExportedCustomDirectEventTypeConstants() {
+ Map> map = MapBuilder.of(
+ "onPress", MapBuilder.of("registrationName", "onPress"),
+ "onCalloutPress", MapBuilder.of("registrationName", "onCalloutPress"),
+ "onDragStart", MapBuilder.of("registrationName", "onDragStart"),
+ "onDrag", MapBuilder.of("registrationName", "onDrag"),
+ "onDragEnd", MapBuilder.of("registrationName", "onDragEnd")
+ );
+
+ map.putAll(MapBuilder.of(
+ "onDragStart", MapBuilder.of("registrationName", "onDragStart"),
+ "onDrag", MapBuilder.of("registrationName", "onDrag"),
+ "onDragEnd", MapBuilder.of("registrationName", "onDragEnd")
+ ));
+
+ return map;
+ }
+
+ @Override
+ public LayoutShadowNode createShadowNodeInstance() {
+ // we use a custom shadow node that emits the width/height of the view
+ // after layout with the updateExtraData method. Without this, we can't generate
+ // a bitmap of the appropriate width/height of the rendered view.
+ return new SizeReportingShadowNode();
+ }
+
+ @Override
+ public void updateExtraData(AirMapMarker view, Object extraData) {
+ // This method is called from the shadow node with the width/height of the rendered
+ // marker view.
+ HashMap data = (HashMap) extraData;
+ float width = data.get("width");
+ float height = data.get("height");
+ view.update((int) width, (int) height);
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapModule.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapModule.java
index 2cd1ba686..1a096255e 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapModule.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapModule.java
@@ -1,128 +1,127 @@
package com.airbnb.android.react.maps;
import android.app.Activity;
-import android.util.DisplayMetrics;
-import android.util.Base64;
import android.graphics.Bitmap;
import android.net.Uri;
-import android.view.View;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.OutputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.Closeable;
-
-import javax.annotation.Nullable;
+import android.util.Base64;
+import android.util.DisplayMetrics;
+import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
-import com.facebook.react.bridge.ReadableMap;
-import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.ReactMethod;
-import com.facebook.react.uimanager.UIManagerModule;
-import com.facebook.react.uimanager.UIBlock;
+import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.uimanager.NativeViewHierarchyManager;
-
+import com.facebook.react.uimanager.UIBlock;
+import com.facebook.react.uimanager.UIManagerModule;
import com.google.android.gms.maps.GoogleMap;
-public class AirMapModule extends ReactContextBaseJavaModule {
-
- private static final String SNAPSHOT_RESULT_FILE = "file";
- private static final String SNAPSHOT_RESULT_BASE64 = "base64";
- private static final String SNAPSHOT_FORMAT_PNG = "png";
- private static final String SNAPSHOT_FORMAT_JPG = "jpg";
-
- public AirMapModule(ReactApplicationContext reactContext) {
- super(reactContext);
- }
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
- @Override
- public String getName() {
- return "AirMapModule";
- }
+import javax.annotation.Nullable;
- public Activity getActivity() {
- return getCurrentActivity();
- }
+public class AirMapModule extends ReactContextBaseJavaModule {
- public static void closeQuietly(Closeable closeable) {
- if (closeable == null) return;
- try {
- closeable.close();
- } catch (IOException ignored) {
- }
+ private static final String SNAPSHOT_RESULT_FILE = "file";
+ private static final String SNAPSHOT_RESULT_BASE64 = "base64";
+ private static final String SNAPSHOT_FORMAT_PNG = "png";
+ private static final String SNAPSHOT_FORMAT_JPG = "jpg";
+
+ public AirMapModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+ }
+
+ @Override
+ public String getName() {
+ return "AirMapModule";
+ }
+
+ public Activity getActivity() {
+ return getCurrentActivity();
+ }
+
+ public static void closeQuietly(Closeable closeable) {
+ if (closeable == null) return;
+ try {
+ closeable.close();
+ } catch (IOException ignored) {
}
+ }
- @ReactMethod
- public void takeSnapshot(final int tag, final ReadableMap options, final Promise promise) {
+ @ReactMethod
+ public void takeSnapshot(final int tag, final ReadableMap options, final Promise promise) {
- // Parse and verity options
- final ReactApplicationContext context = getReactApplicationContext();
- final String format = options.hasKey("format") ? options.getString("format") : "png";
- final Bitmap.CompressFormat compressFormat =
- format.equals(SNAPSHOT_FORMAT_PNG) ? Bitmap.CompressFormat.PNG :
+ // Parse and verity options
+ final ReactApplicationContext context = getReactApplicationContext();
+ final String format = options.hasKey("format") ? options.getString("format") : "png";
+ final Bitmap.CompressFormat compressFormat =
+ format.equals(SNAPSHOT_FORMAT_PNG) ? Bitmap.CompressFormat.PNG :
format.equals(SNAPSHOT_FORMAT_JPG) ? Bitmap.CompressFormat.JPEG : null;
- final double quality = options.hasKey("quality") ? options.getDouble("quality") : 1.0;
- final DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
- final Integer width = options.hasKey("width") ? (int)(displayMetrics.density * options.getDouble("width")) : 0;
- final Integer height = options.hasKey("height") ? (int)(displayMetrics.density * options.getDouble("height")) : 0;
- final String result = options.hasKey("result") ? options.getString("result") : "file";
-
- // Add UI-block so we can get a valid reference to the map-view
- UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
- uiManager.addUIBlock(new UIBlock() {
- public void execute (NativeViewHierarchyManager nvhm) {
- AirMapView view = (AirMapView) nvhm.resolveView(tag);
- if (view == null) {
- promise.reject("AirMapView not found");
- return;
- }
- if (view.map == null) {
- promise.reject("AirMapView.map is not valid");
- return;
- }
- view.map.snapshot(new GoogleMap.SnapshotReadyCallback() {
- public void onSnapshotReady(@Nullable Bitmap snapshot) {
+ final double quality = options.hasKey("quality") ? options.getDouble("quality") : 1.0;
+ final DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ final Integer width =
+ options.hasKey("width") ? (int) (displayMetrics.density * options.getDouble("width")) : 0;
+ final Integer height =
+ options.hasKey("height") ? (int) (displayMetrics.density * options.getDouble("height")) : 0;
+ final String result = options.hasKey("result") ? options.getString("result") : "file";
+
+ // Add UI-block so we can get a valid reference to the map-view
+ UIManagerModule uiManager = context.getNativeModule(UIManagerModule.class);
+ uiManager.addUIBlock(new UIBlock() {
+ public void execute(NativeViewHierarchyManager nvhm) {
+ AirMapView view = (AirMapView) nvhm.resolveView(tag);
+ if (view == null) {
+ promise.reject("AirMapView not found");
+ return;
+ }
+ if (view.map == null) {
+ promise.reject("AirMapView.map is not valid");
+ return;
+ }
+ view.map.snapshot(new GoogleMap.SnapshotReadyCallback() {
+ public void onSnapshotReady(@Nullable Bitmap snapshot) {
- // Convert image to requested width/height if neccesary
- if (snapshot == null) {
- promise.reject("Failed to generate bitmap, snapshot = null");
- return;
- }
- if ((width != 0) && (height != 0) && (width != snapshot.getWidth() || height != snapshot.getHeight())) {
- snapshot = Bitmap.createScaledBitmap(snapshot, width, height, true);
- }
+ // Convert image to requested width/height if necessary
+ if (snapshot == null) {
+ promise.reject("Failed to generate bitmap, snapshot = null");
+ return;
+ }
+ if ((width != 0) && (height != 0) &&
+ (width != snapshot.getWidth() || height != snapshot.getHeight())) {
+ snapshot = Bitmap.createScaledBitmap(snapshot, width, height, true);
+ }
- // Save the snapshot to disk
- if (result.equals(SNAPSHOT_RESULT_FILE)) {
- File tempFile;
- FileOutputStream outputStream;
- try {
- tempFile = File.createTempFile("AirMapSnapshot", "." + format, context.getCacheDir());
- outputStream = new FileOutputStream(tempFile);
- }
- catch (Exception e) {
- promise.reject(e);
- return;
- }
- snapshot.compress(compressFormat, (int)(100.0 * quality), outputStream);
- closeQuietly(outputStream);
- String uri = Uri.fromFile(tempFile).toString();
- promise.resolve(uri);
- }
- else if (result.equals(SNAPSHOT_RESULT_BASE64)) {
- ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- snapshot.compress(compressFormat, (int)(100.0 * quality), outputStream);
- closeQuietly(outputStream);
- byte[] bytes = outputStream.toByteArray();
- String data = Base64.encodeToString(bytes, Base64.NO_WRAP);
- promise.resolve(data);
- }
- }
- });
+ // Save the snapshot to disk
+ if (result.equals(SNAPSHOT_RESULT_FILE)) {
+ File tempFile;
+ FileOutputStream outputStream;
+ try {
+ tempFile =
+ File.createTempFile("AirMapSnapshot", "." + format, context.getCacheDir());
+ outputStream = new FileOutputStream(tempFile);
+ } catch (Exception e) {
+ promise.reject(e);
+ return;
+ }
+ snapshot.compress(compressFormat, (int) (100.0 * quality), outputStream);
+ closeQuietly(outputStream);
+ String uri = Uri.fromFile(tempFile).toString();
+ promise.resolve(uri);
+ } else if (result.equals(SNAPSHOT_RESULT_BASE64)) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ snapshot.compress(compressFormat, (int) (100.0 * quality), outputStream);
+ closeQuietly(outputStream);
+ byte[] bytes = outputStream.toByteArray();
+ String data = Base64.encodeToString(bytes, Base64.NO_WRAP);
+ promise.resolve(data);
}
+ }
});
- }
+ }
+ });
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygon.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygon.java
index 226bc241c..41257b32e 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygon.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygon.java
@@ -14,99 +14,99 @@
public class AirMapPolygon extends AirMapFeature {
- private PolygonOptions polygonOptions;
- private Polygon polygon;
-
- private List coordinates;
- private int strokeColor;
- private int fillColor;
- private float strokeWidth;
- private boolean geodesic;
- private float zIndex;
-
- public AirMapPolygon(Context context) {
- super(context);
+ private PolygonOptions polygonOptions;
+ private Polygon polygon;
+
+ private List coordinates;
+ private int strokeColor;
+ private int fillColor;
+ private float strokeWidth;
+ private boolean geodesic;
+ private float zIndex;
+
+ public AirMapPolygon(Context context) {
+ super(context);
+ }
+
+ public void setCoordinates(ReadableArray coordinates) {
+ // it's kind of a bummer that we can't run map() or anything on the ReadableArray
+ this.coordinates = new ArrayList<>(coordinates.size());
+ for (int i = 0; i < coordinates.size(); i++) {
+ ReadableMap coordinate = coordinates.getMap(i);
+ this.coordinates.add(i,
+ new LatLng(coordinate.getDouble("latitude"), coordinate.getDouble("longitude")));
}
-
- public void setCoordinates(ReadableArray coordinates) {
- // it's kind of a bummer that we can't run map() or anything on the ReadableArray
- this.coordinates = new ArrayList<>(coordinates.size());
- for (int i = 0; i < coordinates.size(); i++) {
- ReadableMap coordinate = coordinates.getMap(i);
- this.coordinates.add(i,
- new LatLng(coordinate.getDouble("latitude"), coordinate.getDouble("longitude")));
- }
- if (polygon != null) {
- polygon.setPoints(this.coordinates);
- }
- }
-
- public void setFillColor(int color) {
- this.fillColor = color;
- if (polygon != null) {
- polygon.setFillColor(color);
- }
- }
-
- public void setStrokeColor(int color) {
- this.strokeColor = color;
- if (polygon != null) {
- polygon.setStrokeColor(color);
- }
- }
-
- public void setStrokeWidth(float width) {
- this.strokeWidth = width;
- if (polygon != null) {
- polygon.setStrokeWidth(width);
- }
- }
-
- public void setGeodesic(boolean geodesic) {
- this.geodesic = geodesic;
- if (polygon != null) {
- polygon.setGeodesic(geodesic);
- }
+ if (polygon != null) {
+ polygon.setPoints(this.coordinates);
}
+ }
- public void setZIndex(float zIndex) {
- this.zIndex = zIndex;
- if (polygon != null) {
- polygon.setZIndex(zIndex);
- }
+ public void setFillColor(int color) {
+ this.fillColor = color;
+ if (polygon != null) {
+ polygon.setFillColor(color);
}
+ }
- public PolygonOptions getPolygonOptions() {
- if (polygonOptions == null) {
- polygonOptions = createPolygonOptions();
- }
- return polygonOptions;
+ public void setStrokeColor(int color) {
+ this.strokeColor = color;
+ if (polygon != null) {
+ polygon.setStrokeColor(color);
}
+ }
- private PolygonOptions createPolygonOptions() {
- PolygonOptions options = new PolygonOptions();
- options.addAll(coordinates);
- options.fillColor(fillColor);
- options.strokeColor(strokeColor);
- options.strokeWidth(strokeWidth);
- options.geodesic(geodesic);
- options.zIndex(zIndex);
- return options;
+ public void setStrokeWidth(float width) {
+ this.strokeWidth = width;
+ if (polygon != null) {
+ polygon.setStrokeWidth(width);
}
+ }
- @Override
- public Object getFeature() {
- return polygon;
+ public void setGeodesic(boolean geodesic) {
+ this.geodesic = geodesic;
+ if (polygon != null) {
+ polygon.setGeodesic(geodesic);
}
+ }
- @Override
- public void addToMap(GoogleMap map) {
- polygon = map.addPolygon(getPolygonOptions());
- polygon.setClickable(true);
+ public void setZIndex(float zIndex) {
+ this.zIndex = zIndex;
+ if (polygon != null) {
+ polygon.setZIndex(zIndex);
}
+ }
- @Override
- public void removeFromMap(GoogleMap map) {
- polygon.remove();
+ public PolygonOptions getPolygonOptions() {
+ if (polygonOptions == null) {
+ polygonOptions = createPolygonOptions();
}
+ return polygonOptions;
+ }
+
+ private PolygonOptions createPolygonOptions() {
+ PolygonOptions options = new PolygonOptions();
+ options.addAll(coordinates);
+ options.fillColor(fillColor);
+ options.strokeColor(strokeColor);
+ options.strokeWidth(strokeWidth);
+ options.geodesic(geodesic);
+ options.zIndex(zIndex);
+ return options;
+ }
+
+ @Override
+ public Object getFeature() {
+ return polygon;
+ }
+
+ @Override
+ public void addToMap(GoogleMap map) {
+ polygon = map.addPolygon(getPolygonOptions());
+ polygon.setClickable(true);
+ }
+
+ @Override
+ public void removeFromMap(GoogleMap map) {
+ polygon.remove();
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygonManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygonManager.java
index 3eaa0e550..6f1605758 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygonManager.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolygonManager.java
@@ -13,71 +13,71 @@
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp;
-import java.util.HashMap;
import java.util.Map;
+
import javax.annotation.Nullable;
public class AirMapPolygonManager extends ViewGroupManager {
- private final DisplayMetrics metrics;
+ private final DisplayMetrics metrics;
- public AirMapPolygonManager(ReactApplicationContext reactContext) {
- super();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- metrics = new DisplayMetrics();
- ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay()
- .getRealMetrics(metrics);
- } else {
- metrics = reactContext.getResources().getDisplayMetrics();
- }
+ public AirMapPolygonManager(ReactApplicationContext reactContext) {
+ super();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ metrics = new DisplayMetrics();
+ ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay()
+ .getRealMetrics(metrics);
+ } else {
+ metrics = reactContext.getResources().getDisplayMetrics();
}
+ }
- @Override
- public String getName() {
- return "AIRMapPolygon";
- }
+ @Override
+ public String getName() {
+ return "AIRMapPolygon";
+ }
- @Override
- public AirMapPolygon createViewInstance(ThemedReactContext context) {
- return new AirMapPolygon(context);
- }
+ @Override
+ public AirMapPolygon createViewInstance(ThemedReactContext context) {
+ return new AirMapPolygon(context);
+ }
- @ReactProp(name = "coordinates")
- public void setCoordinate(AirMapPolygon view, ReadableArray coordinates) {
- view.setCoordinates(coordinates);
- }
+ @ReactProp(name = "coordinates")
+ public void setCoordinate(AirMapPolygon view, ReadableArray coordinates) {
+ view.setCoordinates(coordinates);
+ }
- @ReactProp(name = "strokeWidth", defaultFloat = 1f)
- public void setStrokeWidth(AirMapPolygon view, float widthInPoints) {
- float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS
- view.setStrokeWidth(widthInScreenPx);
- }
+ @ReactProp(name = "strokeWidth", defaultFloat = 1f)
+ public void setStrokeWidth(AirMapPolygon view, float widthInPoints) {
+ float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS
+ view.setStrokeWidth(widthInScreenPx);
+ }
- @ReactProp(name = "fillColor", defaultInt = Color.RED, customType = "Color")
- public void setFillColor(AirMapPolygon view, int color) {
- view.setFillColor(color);
- }
+ @ReactProp(name = "fillColor", defaultInt = Color.RED, customType = "Color")
+ public void setFillColor(AirMapPolygon view, int color) {
+ view.setFillColor(color);
+ }
- @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color")
- public void setStrokeColor(AirMapPolygon view, int color) {
- view.setStrokeColor(color);
- }
+ @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color")
+ public void setStrokeColor(AirMapPolygon view, int color) {
+ view.setStrokeColor(color);
+ }
- @ReactProp(name = "geodesic", defaultBoolean = false)
- public void setGeodesic(AirMapPolygon view, boolean geodesic) {
- view.setGeodesic(geodesic);
- }
+ @ReactProp(name = "geodesic", defaultBoolean = false)
+ public void setGeodesic(AirMapPolygon view, boolean geodesic) {
+ view.setGeodesic(geodesic);
+ }
- @ReactProp(name = "zIndex", defaultFloat = 1.0f)
- public void setZIndex(AirMapPolygon view, float zIndex) {
- view.setZIndex(zIndex);
- }
+ @ReactProp(name = "zIndex", defaultFloat = 1.0f)
+ public void setZIndex(AirMapPolygon view, float zIndex) {
+ view.setZIndex(zIndex);
+ }
- @Override
- @Nullable
- public Map getExportedCustomDirectEventTypeConstants() {
- return MapBuilder.of(
- "onPress", MapBuilder.of("registrationName", "onPress")
- );
- }
+ @Override
+ @Nullable
+ public Map getExportedCustomDirectEventTypeConstants() {
+ return MapBuilder.of(
+ "onPress", MapBuilder.of("registrationName", "onPress")
+ );
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolyline.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolyline.java
index 9a15fdc99..488e2972f 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolyline.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolyline.java
@@ -14,89 +14,89 @@
public class AirMapPolyline extends AirMapFeature {
- private PolylineOptions polylineOptions;
- private Polyline polyline;
-
- private List coordinates;
- private int color;
- private float width;
- private boolean geodesic;
- private float zIndex;
-
- public AirMapPolyline(Context context) {
- super(context);
- }
-
- public void setCoordinates(ReadableArray coordinates) {
- this.coordinates = new ArrayList<>(coordinates.size());
- for (int i = 0; i < coordinates.size(); i++) {
- ReadableMap coordinate = coordinates.getMap(i);
- this.coordinates.add(i,
- new LatLng(coordinate.getDouble("latitude"), coordinate.getDouble("longitude")));
- }
- if (polyline != null) {
- polyline.setPoints(this.coordinates);
- }
- }
-
- public void setColor(int color) {
- this.color = color;
- if (polyline != null) {
- polyline.setColor(color);
- }
+ private PolylineOptions polylineOptions;
+ private Polyline polyline;
+
+ private List coordinates;
+ private int color;
+ private float width;
+ private boolean geodesic;
+ private float zIndex;
+
+ public AirMapPolyline(Context context) {
+ super(context);
+ }
+
+ public void setCoordinates(ReadableArray coordinates) {
+ this.coordinates = new ArrayList<>(coordinates.size());
+ for (int i = 0; i < coordinates.size(); i++) {
+ ReadableMap coordinate = coordinates.getMap(i);
+ this.coordinates.add(i,
+ new LatLng(coordinate.getDouble("latitude"), coordinate.getDouble("longitude")));
}
-
- public void setWidth(float width) {
- this.width = width;
- if (polyline != null) {
- polyline.setWidth(width);
- }
- }
-
- public void setZIndex(float zIndex) {
- this.zIndex = zIndex;
- if (polyline != null) {
- polyline.setZIndex(zIndex);
- }
- }
-
- public void setGeodesic(boolean geodesic) {
- this.geodesic = geodesic;
- if (polyline != null) {
- polyline.setGeodesic(geodesic);
- }
+ if (polyline != null) {
+ polyline.setPoints(this.coordinates);
}
+ }
- public PolylineOptions getPolylineOptions() {
- if (polylineOptions == null) {
- polylineOptions = createPolylineOptions();
- }
- return polylineOptions;
+ public void setColor(int color) {
+ this.color = color;
+ if (polyline != null) {
+ polyline.setColor(color);
}
+ }
- private PolylineOptions createPolylineOptions() {
- PolylineOptions options = new PolylineOptions();
- options.addAll(coordinates);
- options.color(color);
- options.width(width);
- options.geodesic(geodesic);
- options.zIndex(zIndex);
- return options;
+ public void setWidth(float width) {
+ this.width = width;
+ if (polyline != null) {
+ polyline.setWidth(width);
}
+ }
- @Override
- public Object getFeature() {
- return polyline;
+ public void setZIndex(float zIndex) {
+ this.zIndex = zIndex;
+ if (polyline != null) {
+ polyline.setZIndex(zIndex);
}
+ }
- @Override
- public void addToMap(GoogleMap map) {
- polyline = map.addPolyline(getPolylineOptions());
- polyline.setClickable(true);
+ public void setGeodesic(boolean geodesic) {
+ this.geodesic = geodesic;
+ if (polyline != null) {
+ polyline.setGeodesic(geodesic);
}
+ }
- @Override
- public void removeFromMap(GoogleMap map) {
- polyline.remove();
+ public PolylineOptions getPolylineOptions() {
+ if (polylineOptions == null) {
+ polylineOptions = createPolylineOptions();
}
+ return polylineOptions;
+ }
+
+ private PolylineOptions createPolylineOptions() {
+ PolylineOptions options = new PolylineOptions();
+ options.addAll(coordinates);
+ options.color(color);
+ options.width(width);
+ options.geodesic(geodesic);
+ options.zIndex(zIndex);
+ return options;
+ }
+
+ @Override
+ public Object getFeature() {
+ return polyline;
+ }
+
+ @Override
+ public void addToMap(GoogleMap map) {
+ polyline = map.addPolyline(getPolylineOptions());
+ polyline.setClickable(true);
+ }
+
+ @Override
+ public void removeFromMap(GoogleMap map) {
+ polyline.remove();
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolylineManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolylineManager.java
index c5afc61e0..be80acfbc 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolylineManager.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapPolylineManager.java
@@ -13,66 +13,66 @@
import com.facebook.react.uimanager.ViewGroupManager;
import com.facebook.react.uimanager.annotations.ReactProp;
-import java.util.HashMap;
import java.util.Map;
+
import javax.annotation.Nullable;
public class AirMapPolylineManager extends ViewGroupManager {
- private final DisplayMetrics metrics;
+ private final DisplayMetrics metrics;
- public AirMapPolylineManager(ReactApplicationContext reactContext) {
- super();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- metrics = new DisplayMetrics();
- ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay()
- .getRealMetrics(metrics);
- } else {
- metrics = reactContext.getResources().getDisplayMetrics();
- }
+ public AirMapPolylineManager(ReactApplicationContext reactContext) {
+ super();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ metrics = new DisplayMetrics();
+ ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay()
+ .getRealMetrics(metrics);
+ } else {
+ metrics = reactContext.getResources().getDisplayMetrics();
}
+ }
- @Override
- public String getName() {
- return "AIRMapPolyline";
- }
+ @Override
+ public String getName() {
+ return "AIRMapPolyline";
+ }
- @Override
- public AirMapPolyline createViewInstance(ThemedReactContext context) {
- return new AirMapPolyline(context);
- }
+ @Override
+ public AirMapPolyline createViewInstance(ThemedReactContext context) {
+ return new AirMapPolyline(context);
+ }
- @ReactProp(name = "coordinates")
- public void setCoordinate(AirMapPolyline view, ReadableArray coordinates) {
- view.setCoordinates(coordinates);
- }
+ @ReactProp(name = "coordinates")
+ public void setCoordinate(AirMapPolyline view, ReadableArray coordinates) {
+ view.setCoordinates(coordinates);
+ }
- @ReactProp(name = "strokeWidth", defaultFloat = 1f)
- public void setStrokeWidth(AirMapPolyline view, float widthInPoints) {
- float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS
- view.setWidth(widthInScreenPx);
- }
+ @ReactProp(name = "strokeWidth", defaultFloat = 1f)
+ public void setStrokeWidth(AirMapPolyline view, float widthInPoints) {
+ float widthInScreenPx = metrics.density * widthInPoints; // done for parity with iOS
+ view.setWidth(widthInScreenPx);
+ }
- @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color")
- public void setStrokeColor(AirMapPolyline view, int color) {
- view.setColor(color);
- }
+ @ReactProp(name = "strokeColor", defaultInt = Color.RED, customType = "Color")
+ public void setStrokeColor(AirMapPolyline view, int color) {
+ view.setColor(color);
+ }
- @ReactProp(name = "geodesic", defaultBoolean = false)
- public void setGeodesic(AirMapPolyline view, boolean geodesic) {
- view.setGeodesic(geodesic);
- }
+ @ReactProp(name = "geodesic", defaultBoolean = false)
+ public void setGeodesic(AirMapPolyline view, boolean geodesic) {
+ view.setGeodesic(geodesic);
+ }
- @ReactProp(name = "zIndex", defaultFloat = 1.0f)
- public void setZIndex(AirMapPolyline view, float zIndex) {
- view.setZIndex(zIndex);
- }
+ @ReactProp(name = "zIndex", defaultFloat = 1.0f)
+ public void setZIndex(AirMapPolyline view, float zIndex) {
+ view.setZIndex(zIndex);
+ }
- @Override
- @Nullable
- public Map getExportedCustomDirectEventTypeConstants() {
- return MapBuilder.of(
- "onPress", MapBuilder.of("registrationName", "onPress")
- );
- }
+ @Override
+ @Nullable
+ public Map getExportedCustomDirectEventTypeConstants() {
+ return MapBuilder.of(
+ "onPress", MapBuilder.of("registrationName", "onPress")
+ );
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTile.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTile.java
index 691c2fd3c..ae51a63b4 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTile.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTile.java
@@ -12,89 +12,90 @@
public class AirMapUrlTile extends AirMapFeature {
- class AIRMapUrlTileProvider extends UrlTileProvider
- {
- private String urlTemplate;
- public AIRMapUrlTileProvider(int width, int height, String urlTemplate) {
- super(width, height);
- this.urlTemplate = urlTemplate;
- }
- @Override
- public synchronized URL getTileUrl(int x, int y, int zoom) {
-
- String s = this.urlTemplate
- .replace("{x}", Integer.toString(x))
- .replace("{y}", Integer.toString(y))
- .replace("{z}", Integer.toString(zoom));
- URL url = null;
- try {
- url = new URL(s);
- } catch (MalformedURLException e) {
- throw new AssertionError(e);
- }
- return url;
- }
-
- public void setUrlTemplate(String urlTemplate) {
- this.urlTemplate = urlTemplate;
- }
- }
-
- private TileOverlayOptions tileOverlayOptions;
- private TileOverlay tileOverlay;
- private AIRMapUrlTileProvider tileProvider;
-
+ class AIRMapUrlTileProvider extends UrlTileProvider {
private String urlTemplate;
- private float zIndex;
- public AirMapUrlTile(Context context) {
- super(context);
+ public AIRMapUrlTileProvider(int width, int height, String urlTemplate) {
+ super(width, height);
+ this.urlTemplate = urlTemplate;
}
- public void setUrlTemplate(String urlTemplate) {
- this.urlTemplate = urlTemplate;
- if (tileProvider != null) {
- tileProvider.setUrlTemplate(urlTemplate);
- }
- if (tileOverlay != null) {
- tileOverlay.clearTileCache();
- }
+ @Override
+ public synchronized URL getTileUrl(int x, int y, int zoom) {
+
+ String s = this.urlTemplate
+ .replace("{x}", Integer.toString(x))
+ .replace("{y}", Integer.toString(y))
+ .replace("{z}", Integer.toString(zoom));
+ URL url = null;
+ try {
+ url = new URL(s);
+ } catch (MalformedURLException e) {
+ throw new AssertionError(e);
+ }
+ return url;
}
- public void setZIndex(float zIndex) {
- this.zIndex = zIndex;
- if (tileOverlay != null) {
- tileOverlay.setZIndex(zIndex);
- }
+ public void setUrlTemplate(String urlTemplate) {
+ this.urlTemplate = urlTemplate;
}
+ }
- public TileOverlayOptions getTileOverlayOptions() {
- if (tileOverlayOptions == null) {
- tileOverlayOptions = createTileOverlayOptions();
- }
- return tileOverlayOptions;
- }
+ private TileOverlayOptions tileOverlayOptions;
+ private TileOverlay tileOverlay;
+ private AIRMapUrlTileProvider tileProvider;
- private TileOverlayOptions createTileOverlayOptions() {
- TileOverlayOptions options = new TileOverlayOptions();
- options.zIndex(zIndex);
- this.tileProvider = new AIRMapUrlTileProvider(256, 256, this.urlTemplate);
- options.tileProvider(this.tileProvider);
- return options;
- }
+ private String urlTemplate;
+ private float zIndex;
- @Override
- public Object getFeature() {
- return tileOverlay;
+ public AirMapUrlTile(Context context) {
+ super(context);
+ }
+
+ public void setUrlTemplate(String urlTemplate) {
+ this.urlTemplate = urlTemplate;
+ if (tileProvider != null) {
+ tileProvider.setUrlTemplate(urlTemplate);
}
+ if (tileOverlay != null) {
+ tileOverlay.clearTileCache();
+ }
+ }
- @Override
- public void addToMap(GoogleMap map) {
- this.tileOverlay = map.addTileOverlay(getTileOverlayOptions());
+ public void setZIndex(float zIndex) {
+ this.zIndex = zIndex;
+ if (tileOverlay != null) {
+ tileOverlay.setZIndex(zIndex);
}
+ }
- @Override
- public void removeFromMap(GoogleMap map) {
- tileOverlay.remove();
+ public TileOverlayOptions getTileOverlayOptions() {
+ if (tileOverlayOptions == null) {
+ tileOverlayOptions = createTileOverlayOptions();
}
+ return tileOverlayOptions;
+ }
+
+ private TileOverlayOptions createTileOverlayOptions() {
+ TileOverlayOptions options = new TileOverlayOptions();
+ options.zIndex(zIndex);
+ this.tileProvider = new AIRMapUrlTileProvider(256, 256, this.urlTemplate);
+ options.tileProvider(this.tileProvider);
+ return options;
+ }
+
+ @Override
+ public Object getFeature() {
+ return tileOverlay;
+ }
+
+ @Override
+ public void addToMap(GoogleMap map) {
+ this.tileOverlay = map.addTileOverlay(getTileOverlayOptions());
+ }
+
+ @Override
+ public void removeFromMap(GoogleMap map) {
+ tileOverlay.remove();
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTileManager.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTileManager.java
index 7ea0726dc..68bf07342 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTileManager.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapUrlTileManager.java
@@ -11,38 +11,38 @@
import com.facebook.react.uimanager.annotations.ReactProp;
public class AirMapUrlTileManager extends ViewGroupManager {
- private DisplayMetrics metrics;
-
- public AirMapUrlTileManager(ReactApplicationContext reactContext) {
- super();
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- metrics = new DisplayMetrics();
- ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
- .getDefaultDisplay()
- .getRealMetrics(metrics);
- } else {
- metrics = reactContext.getResources().getDisplayMetrics();
- }
- }
-
- @Override
- public String getName() {
- return "AIRMapUrlTile";
- }
-
- @Override
- public AirMapUrlTile createViewInstance(ThemedReactContext context) {
- return new AirMapUrlTile(context);
- }
-
- @ReactProp(name = "urlTemplate")
- public void setUrlTemplate(AirMapUrlTile view, String urlTemplate) {
- view.setUrlTemplate(urlTemplate);
- }
-
- @ReactProp(name = "zIndex", defaultFloat = -1.0f)
- public void setZIndex(AirMapUrlTile view, float zIndex) {
- view.setZIndex(zIndex);
+ private DisplayMetrics metrics;
+
+ public AirMapUrlTileManager(ReactApplicationContext reactContext) {
+ super();
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ metrics = new DisplayMetrics();
+ ((WindowManager) reactContext.getSystemService(Context.WINDOW_SERVICE))
+ .getDefaultDisplay()
+ .getRealMetrics(metrics);
+ } else {
+ metrics = reactContext.getResources().getDisplayMetrics();
}
+ }
+
+ @Override
+ public String getName() {
+ return "AIRMapUrlTile";
+ }
+
+ @Override
+ public AirMapUrlTile createViewInstance(ThemedReactContext context) {
+ return new AirMapUrlTile(context);
+ }
+
+ @ReactProp(name = "urlTemplate")
+ public void setUrlTemplate(AirMapUrlTile view, String urlTemplate) {
+ view.setUrlTemplate(urlTemplate);
+ }
+
+ @ReactProp(name = "zIndex", defaultFloat = -1.0f)
+ public void setZIndex(AirMapUrlTile view, float zIndex) {
+ view.setZIndex(zIndex);
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java
index a4610efff..f69e05295 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/AirMapView.java
@@ -1,6 +1,5 @@
package com.airbnb.android.react.maps;
-import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.ColorStateList;
@@ -55,808 +54,816 @@
import static android.support.v4.content.PermissionChecker.checkSelfPermission;
public class AirMapView extends MapView implements GoogleMap.InfoWindowAdapter,
- GoogleMap.OnMarkerDragListener, OnMapReadyCallback {
- public GoogleMap map;
- private ProgressBar mapLoadingProgressBar;
- private RelativeLayout mapLoadingLayout;
- private ImageView cacheImageView;
- private Boolean isMapLoaded = false;
- private Integer loadingBackgroundColor = null;
- private Integer loadingIndicatorColor = null;
- private final int baseMapPadding = 50;
-
- private LatLngBounds boundsToMove;
- private boolean showUserLocation = false;
- private boolean isMonitoringRegion = false;
- private boolean isTouchDown = false;
- private boolean handlePanDrag = false;
- private boolean moveOnMarkerPress = true;
- private boolean cacheEnabled = false;
-
- private static final String[] PERMISSIONS = new String[] {
- "android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_COARSE_LOCATION"};
-
- private final List features = new ArrayList<>();
- private final Map markerMap = new HashMap<>();
- private final Map polylineMap = new HashMap<>();
- private final Map polygonMap = new HashMap<>();
- private final ScaleGestureDetector scaleDetector;
- private final GestureDetectorCompat gestureDetector;
- private final AirMapManager manager;
- private LifecycleEventListener lifecycleListener;
- private boolean paused = false;
- private boolean destroyed = false;
- private final ThemedReactContext context;
- private final EventDispatcher eventDispatcher;
-
- private static boolean contextHasBug(Context context) {
- return context == null ||
- context.getResources() == null ||
- context.getResources().getConfiguration() == null;
- }
-
- // We do this to fix this bug:
- // https://github.com/airbnb/react-native-maps/issues/271
- //
- // which conflicts with another bug regarding the passed in context:
- // https://github.com/airbnb/react-native-maps/issues/1147
- //
- // Doing this allows us to avoid both bugs.
- private static Context getNonBuggyContext(ThemedReactContext reactContext,
- ReactApplicationContext appContext) {
- Context superContext = reactContext;
- if (!contextHasBug(appContext.getCurrentActivity())) {
- superContext = appContext.getCurrentActivity();
- } else if (contextHasBug(superContext)) {
- // we have the bug! let's try to find a better context to use
- if (!contextHasBug(reactContext.getCurrentActivity())) {
- superContext = reactContext.getCurrentActivity();
- } else if (!contextHasBug(reactContext.getApplicationContext())) {
- superContext = reactContext.getApplicationContext();
- } else {
- // ¯\_(ツ)_/¯
- }
- }
- return superContext;
- }
-
- public AirMapView(ThemedReactContext reactContext, ReactApplicationContext appContext, AirMapManager manager,
- GoogleMapOptions googleMapOptions) {
- super(getNonBuggyContext(reactContext, appContext), googleMapOptions);
-
- this.manager = manager;
- this.context = reactContext;
-
- super.onCreate(null);
- // TODO(lmr): what about onStart????
- super.onResume();
- super.getMapAsync(this);
-
- final AirMapView view = this;
- scaleDetector =
- new ScaleGestureDetector(reactContext, new ScaleGestureDetector.SimpleOnScaleGestureListener() {
- @Override
- public boolean onScaleBegin(ScaleGestureDetector detector) {
- view.startMonitoringRegion();
- return true; // stop recording this gesture. let mapview handle it.
- }
- });
-
- gestureDetector =
- new GestureDetectorCompat(reactContext, new GestureDetector.SimpleOnGestureListener() {
- @Override
- public boolean onDoubleTap(MotionEvent e) {
- view.startMonitoringRegion();
- return false;
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
- float distanceY) {
- if (handlePanDrag) {
- onPanDrag(e2);
- }
- view.startMonitoringRegion();
- return false;
- }
- });
-
- this.addOnLayoutChangeListener(new OnLayoutChangeListener() {
- @Override public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- if (!paused) {
- AirMapView.this.cacheView();
- }
- }
- });
-
- eventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
- }
-
- @Override
- public void onMapReady(final GoogleMap map) {
- if (destroyed) {
- return;
- }
- this.map = map;
- this.map.setInfoWindowAdapter(this);
- this.map.setOnMarkerDragListener(this);
-
- manager.pushEvent(context, this, "onMapReady", new WritableNativeMap());
-
- final AirMapView view = this;
-
- map.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
- @Override
- public boolean onMarkerClick(Marker marker) {
- WritableMap event;
- AirMapMarker airMapMarker = markerMap.get(marker);
-
- event = makeClickEventData(marker.getPosition());
- event.putString("action", "marker-press");
- event.putString("id", airMapMarker.getIdentifier());
- manager.pushEvent(context, view, "onMarkerPress", event);
-
- event = makeClickEventData(marker.getPosition());
- event.putString("action", "marker-press");
- event.putString("id", airMapMarker.getIdentifier());
- manager.pushEvent(context, markerMap.get(marker), "onPress", event);
-
- // Return false to open the callout info window and center on the marker
- // https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap.OnMarkerClickListener
- if (view.moveOnMarkerPress) {
- return false;
- } else {
- marker.showInfoWindow();
- return true;
- }
- }
- });
-
- map.setOnPolygonClickListener(new GoogleMap.OnPolygonClickListener() {
- @Override
- public void onPolygonClick(Polygon polygon) {
- WritableMap event = makeClickEventData(polygon.getPoints().get(0));
- event.putString("action", "polygon-press");
- manager.pushEvent(context, polygonMap.get(polygon), "onPress", event);
- }
- });
-
- map.setOnPolylineClickListener(new GoogleMap.OnPolylineClickListener() {
- @Override
- public void onPolylineClick(Polyline polyline) {
- WritableMap event = makeClickEventData(polyline.getPoints().get(0));
- event.putString("action", "polyline-press");
- manager.pushEvent(context, polylineMap.get(polyline), "onPress", event);
- }
- });
-
- map.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
- @Override
- public void onInfoWindowClick(Marker marker) {
- WritableMap event;
-
- event = makeClickEventData(marker.getPosition());
- event.putString("action", "callout-press");
- manager.pushEvent(context, view, "onCalloutPress", event);
-
- event = makeClickEventData(marker.getPosition());
- event.putString("action", "callout-press");
- AirMapMarker markerView = markerMap.get(marker);
- manager.pushEvent(context, markerView, "onCalloutPress", event);
-
- event = makeClickEventData(marker.getPosition());
- event.putString("action", "callout-press");
- AirMapCallout infoWindow = markerView.getCalloutView();
- if (infoWindow != null) manager.pushEvent(context, infoWindow, "onPress", event);
- }
- });
-
- map.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
- @Override
- public void onMapClick(LatLng point) {
- WritableMap event = makeClickEventData(point);
- event.putString("action", "press");
- manager.pushEvent(context, view, "onPress", event);
- }
- });
-
- map.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() {
- @Override
- public void onMapLongClick(LatLng point) {
- WritableMap event = makeClickEventData(point);
- event.putString("action", "long-press");
- manager.pushEvent(context, view, "onLongPress", makeClickEventData(point));
- }
- });
-
- map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
- @Override
- public void onCameraChange(CameraPosition position) {
- LatLngBounds bounds = map.getProjection().getVisibleRegion().latLngBounds;
- LatLng center = position.target;
- lastBoundsEmitted = bounds;
- eventDispatcher.dispatchEvent(new RegionChangeEvent(getId(), bounds, center, isTouchDown));
- view.stopMonitoringRegion();
- }
- });
-
- map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
- @Override public void onMapLoaded() {
- isMapLoaded = true;
- AirMapView.this.cacheView();
- }
- });
-
- // We need to be sure to disable location-tracking when app enters background, in-case some
- // other module
- // has acquired a wake-lock and is controlling location-updates, otherwise, location-manager
- // will be left
- // updating location constantly, killing the battery, even though some other location-mgmt
- // module may
- // desire to shut-down location-services.
- lifecycleListener = new LifecycleEventListener() {
- @Override
- public void onHostResume() {
- if (hasPermissions()) {
- //noinspection MissingPermission
- map.setMyLocationEnabled(showUserLocation);
- }
- synchronized (AirMapView.this) {
- AirMapView.this.onResume();
- paused = false;
+ GoogleMap.OnMarkerDragListener, OnMapReadyCallback {
+ public GoogleMap map;
+ private ProgressBar mapLoadingProgressBar;
+ private RelativeLayout mapLoadingLayout;
+ private ImageView cacheImageView;
+ private Boolean isMapLoaded = false;
+ private Integer loadingBackgroundColor = null;
+ private Integer loadingIndicatorColor = null;
+ private final int baseMapPadding = 50;
+
+ private LatLngBounds boundsToMove;
+ private boolean showUserLocation = false;
+ private boolean isMonitoringRegion = false;
+ private boolean isTouchDown = false;
+ private boolean handlePanDrag = false;
+ private boolean moveOnMarkerPress = true;
+ private boolean cacheEnabled = false;
+
+ private static final String[] PERMISSIONS = new String[]{
+ "android.permission.ACCESS_FINE_LOCATION", "android.permission.ACCESS_COARSE_LOCATION"};
+
+ private final List features = new ArrayList<>();
+ private final Map markerMap = new HashMap<>();
+ private final Map polylineMap = new HashMap<>();
+ private final Map polygonMap = new HashMap<>();
+ private final ScaleGestureDetector scaleDetector;
+ private final GestureDetectorCompat gestureDetector;
+ private final AirMapManager manager;
+ private LifecycleEventListener lifecycleListener;
+ private boolean paused = false;
+ private boolean destroyed = false;
+ private final ThemedReactContext context;
+ private final EventDispatcher eventDispatcher;
+
+ private static boolean contextHasBug(Context context) {
+ return context == null ||
+ context.getResources() == null ||
+ context.getResources().getConfiguration() == null;
+ }
+
+ // We do this to fix this bug:
+ // https://github.com/airbnb/react-native-maps/issues/271
+ //
+ // which conflicts with another bug regarding the passed in context:
+ // https://github.com/airbnb/react-native-maps/issues/1147
+ //
+ // Doing this allows us to avoid both bugs.
+ private static Context getNonBuggyContext(ThemedReactContext reactContext,
+ ReactApplicationContext appContext) {
+ Context superContext = reactContext;
+ if (!contextHasBug(appContext.getCurrentActivity())) {
+ superContext = appContext.getCurrentActivity();
+ } else if (contextHasBug(superContext)) {
+ // we have the bug! let's try to find a better context to use
+ if (!contextHasBug(reactContext.getCurrentActivity())) {
+ superContext = reactContext.getCurrentActivity();
+ } else if (!contextHasBug(reactContext.getApplicationContext())) {
+ superContext = reactContext.getApplicationContext();
+ } else {
+ // ¯\_(ツ)_/¯
+ }
+ }
+ return superContext;
+ }
+
+ public AirMapView(ThemedReactContext reactContext, ReactApplicationContext appContext,
+ AirMapManager manager,
+ GoogleMapOptions googleMapOptions) {
+ super(getNonBuggyContext(reactContext, appContext), googleMapOptions);
+
+ this.manager = manager;
+ this.context = reactContext;
+
+ super.onCreate(null);
+ // TODO(lmr): what about onStart????
+ super.onResume();
+ super.getMapAsync(this);
+
+ final AirMapView view = this;
+ scaleDetector =
+ new ScaleGestureDetector(reactContext,
+ new ScaleGestureDetector.SimpleOnScaleGestureListener() {
+ @Override
+ public boolean onScaleBegin(ScaleGestureDetector detector) {
+ view.startMonitoringRegion();
+ return true; // stop recording this gesture. let mapview handle it.
+ }
+ });
+
+ gestureDetector =
+ new GestureDetectorCompat(reactContext, new GestureDetector.SimpleOnGestureListener() {
+ @Override
+ public boolean onDoubleTap(MotionEvent e) {
+ view.startMonitoringRegion();
+ return false;
}
- }
- @Override
- public void onHostPause() {
- if (hasPermissions()) {
- //noinspection MissingPermission
- map.setMyLocationEnabled(false);
- }
- synchronized (AirMapView.this) {
- AirMapView.this.onPause();
- paused = true;
+ @Override
+ public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
+ float distanceY) {
+ if (handlePanDrag) {
+ onPanDrag(e2);
}
- }
-
- @Override
- public void onHostDestroy() {
- AirMapView.this.doDestroy();
- }
- };
-
- context.addLifecycleEventListener(lifecycleListener);
- }
-
- private boolean hasPermissions() {
- return checkSelfPermission(getContext(), PERMISSIONS[0]) == PackageManager.PERMISSION_GRANTED ||
- checkSelfPermission(getContext(), PERMISSIONS[1]) == PackageManager.PERMISSION_GRANTED;
- }
-
-
-
- /*
- onDestroy is final method so I can't override it.
- */
- public synchronized void doDestroy() {
- if (destroyed) {
- return;
- }
- destroyed = true;
+ view.startMonitoringRegion();
+ return false;
+ }
+ });
- if (lifecycleListener != null && context != null) {
- context.removeLifecycleEventListener(lifecycleListener);
- lifecycleListener = null;
- }
+ this.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+ @Override public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
if (!paused) {
- onPause();
- paused = true;
- }
- onDestroy();
- }
-
- public void setRegion(ReadableMap region) {
- if (region == null) return;
-
- Double lng = region.getDouble("longitude");
- Double lat = region.getDouble("latitude");
- Double lngDelta = region.getDouble("longitudeDelta");
- Double latDelta = region.getDouble("latitudeDelta");
- LatLngBounds bounds = new LatLngBounds(
- new LatLng(lat - latDelta / 2, lng - lngDelta / 2), // southwest
- new LatLng(lat + latDelta / 2, lng + lngDelta / 2) // northeast
- );
- if (super.getHeight() <= 0 || super.getWidth() <= 0) {
- // in this case, our map has not been laid out yet, so we save the bounds in a local
- // variable, and make a guess of zoomLevel 10. Not to worry, though: as soon as layout
- // occurs, we will move the camera to the saved bounds. Note that if we tried to move
- // to the bounds now, it would trigger an exception.
- map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lng), 10));
- boundsToMove = bounds;
- } else {
- map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0));
- boundsToMove = null;
- }
- }
-
- public void setShowsUserLocation(boolean showUserLocation) {
- this.showUserLocation = showUserLocation; // hold onto this for lifecycle handling
- if (hasPermissions()) {
- //noinspection MissingPermission
- map.setMyLocationEnabled(showUserLocation);
- }
- }
-
- public void setShowsMyLocationButton(boolean showMyLocationButton) {
- if (hasPermissions()) {
- map.getUiSettings().setMyLocationButtonEnabled(showMyLocationButton);
- }
- }
-
- public void setToolbarEnabled(boolean toolbarEnabled) {
- if (hasPermissions()) {
- map.getUiSettings().setMapToolbarEnabled(toolbarEnabled);
- }
- }
-
- public void setCacheEnabled(boolean cacheEnabled) {
- this.cacheEnabled = cacheEnabled;
- this.cacheView();
- }
-
- public void enableMapLoading(boolean loadingEnabled) {
- if (loadingEnabled && !this.isMapLoaded) {
- this.getMapLoadingLayoutView().setVisibility(View.VISIBLE);
- }
- }
-
- public void setMoveOnMarkerPress(boolean moveOnPress) {
- this.moveOnMarkerPress = moveOnPress;
- }
-
- public void setLoadingBackgroundColor(Integer loadingBackgroundColor) {
- this.loadingBackgroundColor = loadingBackgroundColor;
-
- if (this.mapLoadingLayout != null) {
- if (loadingBackgroundColor == null) {
- this.mapLoadingLayout.setBackgroundColor(Color.WHITE);
- } else {
- this.mapLoadingLayout.setBackgroundColor(this.loadingBackgroundColor);
- }
- }
- }
-
- public void setLoadingIndicatorColor(Integer loadingIndicatorColor) {
- this.loadingIndicatorColor = loadingIndicatorColor;
- if (this.mapLoadingProgressBar != null) {
- Integer color = loadingIndicatorColor;
- if (color == null) {
- color = Color.parseColor("#606060");
- }
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- ColorStateList progressTintList = ColorStateList.valueOf(loadingIndicatorColor);
- ColorStateList secondaryProgressTintList = ColorStateList.valueOf(loadingIndicatorColor);
- ColorStateList indeterminateTintList = ColorStateList.valueOf(loadingIndicatorColor);
-
- this.mapLoadingProgressBar.setProgressTintList(progressTintList);
- this.mapLoadingProgressBar.setSecondaryProgressTintList(secondaryProgressTintList);
- this.mapLoadingProgressBar.setIndeterminateTintList(indeterminateTintList);
- } else {
- PorterDuff.Mode mode = PorterDuff.Mode.SRC_IN;
- if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
- mode = PorterDuff.Mode.MULTIPLY;
- }
- if (this.mapLoadingProgressBar.getIndeterminateDrawable() != null)
- this.mapLoadingProgressBar.getIndeterminateDrawable().setColorFilter(color, mode);
- if (this.mapLoadingProgressBar.getProgressDrawable() != null)
- this.mapLoadingProgressBar.getProgressDrawable().setColorFilter(color, mode);
- }
- }
- }
-
- public void setHandlePanDrag(boolean handlePanDrag) {
- this.handlePanDrag = handlePanDrag;
- }
-
- public void addFeature(View child, int index) {
- // Our desired API is to pass up annotations/overlays as children to the mapview component.
- // This is where we intercept them and do the appropriate underlying mapview action.
-
- if (child instanceof AirMapMarker) {
- AirMapMarker annotation = (AirMapMarker) child;
- annotation.addToMap(map);
- features.add(index, annotation);
- Marker marker = (Marker) annotation.getFeature();
- markerMap.put(marker, annotation);
- } else if (child instanceof AirMapPolyline) {
- AirMapPolyline polylineView = (AirMapPolyline) child;
- polylineView.addToMap(map);
- features.add(index, polylineView);
- Polyline polyline = (Polyline) polylineView.getFeature();
- polylineMap.put(polyline, polylineView);
- } else if (child instanceof AirMapPolygon) {
- AirMapPolygon polygonView = (AirMapPolygon) child;
- polygonView.addToMap(map);
- features.add(index, polygonView);
- Polygon polygon = (Polygon) polygonView.getFeature();
- polygonMap.put(polygon, polygonView);
- } else if (child instanceof AirMapCircle) {
- AirMapCircle circleView = (AirMapCircle) child;
- circleView.addToMap(map);
- features.add(index, circleView);
- } else if (child instanceof AirMapUrlTile) {
- AirMapUrlTile urlTileView = (AirMapUrlTile) child;
- urlTileView.addToMap(map);
- features.add(index, urlTileView);
- } else if (child instanceof AirMapCanvasUrlTile) {
- AirMapCanvasUrlTile canvasUrlTileView = (AirMapCanvasUrlTile) child;
- canvasUrlTileView.addToMap(map);
- features.add(index, canvasUrlTileView);
- } else if (child instanceof AirMapCanvasInteractionUrlTile) {
- AirMapCanvasInteractionUrlTile canvasInteractionUrlTileView = (AirMapCanvasInteractionUrlTile) child;
- canvasInteractionUrlTileView.addToMap(map);
- features.add(index, canvasInteractionUrlTileView);
- } else {
- ViewGroup children = (ViewGroup) child;
- for (int i = 0; i < children.getChildCount(); i++) {
- addFeature(children.getChildAt(i), index);
- }
- }
- }
-
- public int getFeatureCount() {
- return features.size();
- }
-
- public View getFeatureAt(int index) {
- return features.get(index);
- }
-
- public void removeFeatureAt(int index) {
- AirMapFeature feature = features.remove(index);
- if (feature instanceof AirMapMarker) {
- markerMap.remove(feature.getFeature());
+ AirMapView.this.cacheView();
}
- feature.removeFromMap(map);
- }
-
- public WritableMap makeClickEventData(LatLng point) {
- WritableMap event = new WritableNativeMap();
-
- WritableMap coordinate = new WritableNativeMap();
- coordinate.putDouble("latitude", point.latitude);
- coordinate.putDouble("longitude", point.longitude);
- event.putMap("coordinate", coordinate);
-
- Projection projection = map.getProjection();
- Point screenPoint = projection.toScreenLocation(point);
-
- WritableMap position = new WritableNativeMap();
- position.putDouble("x", screenPoint.x);
- position.putDouble("y", screenPoint.y);
- event.putMap("position", position);
-
- return event;
- }
-
- public void updateExtraData(Object extraData) {
- // if boundsToMove is not null, we now have the MapView's width/height, so we can apply
- // a proper camera move
- if (boundsToMove != null) {
- HashMap data = (HashMap) extraData;
- float width = data.get("width");
- float height = data.get("height");
- map.moveCamera(
- CameraUpdateFactory.newLatLngBounds(
- boundsToMove,
- (int) width,
- (int) height,
- 0
- )
- );
- boundsToMove = null;
- }
- }
-
- public void animateToRegion(LatLngBounds bounds, int duration) {
- if (map != null) {
- startMonitoringRegion();
- map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0), duration, null);
- }
- }
-
- public void animateToCoordinate(LatLng coordinate, int duration) {
- if (map != null) {
- startMonitoringRegion();
- map.animateCamera(CameraUpdateFactory.newLatLng(coordinate), duration, null);
- }
- }
-
- public void fitToElements(boolean animated) {
- LatLngBounds.Builder builder = new LatLngBounds.Builder();
+ }
+ });
- boolean addedPosition = false;
+ eventDispatcher = reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
+ }
- for (AirMapFeature feature : features) {
- if (feature instanceof AirMapMarker) {
- Marker marker = (Marker) feature.getFeature();
- builder.include(marker.getPosition());
- addedPosition = true;
- }
- // TODO(lmr): may want to include shapes / etc.
- }
- if (addedPosition) {
- LatLngBounds bounds = builder.build();
- CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, baseMapPadding);
- if (animated) {
- startMonitoringRegion();
- map.animateCamera(cu);
- } else {
- map.moveCamera(cu);
- }
- }
+ @Override
+ public void onMapReady(final GoogleMap map) {
+ if (destroyed) {
+ return;
}
+ this.map = map;
+ this.map.setInfoWindowAdapter(this);
+ this.map.setOnMarkerDragListener(this);
- public void fitToSuppliedMarkers(ReadableArray markerIDsArray, boolean animated) {
- LatLngBounds.Builder builder = new LatLngBounds.Builder();
-
- String[] markerIDs = new String[markerIDsArray.size()];
- for (int i = 0; i < markerIDsArray.size(); i++) {
- markerIDs[i] = markerIDsArray.getString(i);
- }
-
- boolean addedPosition = false;
+ manager.pushEvent(context, this, "onMapReady", new WritableNativeMap());
- List markerIDList = Arrays.asList(markerIDs);
+ final AirMapView view = this;
- for (AirMapFeature feature : features) {
- if (feature instanceof AirMapMarker) {
- String identifier = ((AirMapMarker)feature).getIdentifier();
- Marker marker = (Marker)feature.getFeature();
- if (markerIDList.contains(identifier)) {
- builder.include(marker.getPosition());
- addedPosition = true;
- }
- }
- }
-
- if (addedPosition) {
- LatLngBounds bounds = builder.build();
- CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, baseMapPadding);
- if (animated) {
- startMonitoringRegion();
- map.animateCamera(cu);
- } else {
- map.moveCamera(cu);
- }
- }
- }
+ map.setOnMarkerClickListener(new GoogleMap.OnMarkerClickListener() {
+ @Override
+ public boolean onMarkerClick(Marker marker) {
+ WritableMap event;
+ AirMapMarker airMapMarker = markerMap.get(marker);
- public void fitToCoordinates(ReadableArray coordinatesArray, ReadableMap edgePadding, boolean animated) {
- LatLngBounds.Builder builder = new LatLngBounds.Builder();
-
- for (int i = 0; i < coordinatesArray.size(); i++) {
- ReadableMap latLng = coordinatesArray.getMap(i);
- Double lat = latLng.getDouble("latitude");
- Double lng = latLng.getDouble("longitude");
- builder.include(new LatLng(lat, lng));
- }
-
- LatLngBounds bounds = builder.build();
- CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, baseMapPadding);
-
- if (edgePadding != null) {
- map.setPadding(edgePadding.getInt("left"), edgePadding.getInt("top"), edgePadding.getInt("right"), edgePadding.getInt("bottom"));
- }
+ event = makeClickEventData(marker.getPosition());
+ event.putString("action", "marker-press");
+ event.putString("id", airMapMarker.getIdentifier());
+ manager.pushEvent(context, view, "onMarkerPress", event);
- if (animated) {
- startMonitoringRegion();
- map.animateCamera(cu);
+ event = makeClickEventData(marker.getPosition());
+ event.putString("action", "marker-press");
+ event.putString("id", airMapMarker.getIdentifier());
+ manager.pushEvent(context, markerMap.get(marker), "onPress", event);
+
+ // Return false to open the callout info window and center on the marker
+ // https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap
+ // .OnMarkerClickListener
+ if (view.moveOnMarkerPress) {
+ return false;
} else {
- map.moveCamera(cu);
- }
- map.setPadding(0, 0, 0, 0); // Without this, the Google logo is moved up by the value of edgePadding.bottom
- }
-
- // InfoWindowAdapter interface
-
- @Override
- public View getInfoWindow(Marker marker) {
- AirMapMarker markerView = markerMap.get(marker);
- return markerView.getCallout();
- }
-
- @Override
- public View getInfoContents(Marker marker) {
- AirMapMarker markerView = markerMap.get(marker);
- return markerView.getInfoContents();
- }
-
- @Override
- public boolean dispatchTouchEvent(MotionEvent ev) {
- scaleDetector.onTouchEvent(ev);
- gestureDetector.onTouchEvent(ev);
-
- int action = MotionEventCompat.getActionMasked(ev);
-
- switch (action) {
- case (MotionEvent.ACTION_DOWN):
- this.getParent().requestDisallowInterceptTouchEvent(
- map != null && map.getUiSettings().isScrollGesturesEnabled());
- isTouchDown = true;
- break;
- case (MotionEvent.ACTION_MOVE):
- startMonitoringRegion();
- break;
- case (MotionEvent.ACTION_UP):
- // Clear this regardless, since isScrollGesturesEnabled() may have been updated
- this.getParent().requestDisallowInterceptTouchEvent(false);
- isTouchDown = false;
- break;
- }
- super.dispatchTouchEvent(ev);
- return true;
- }
-
- // Timer Implementation
-
- public void startMonitoringRegion() {
- if (isMonitoringRegion) return;
- timerHandler.postDelayed(timerRunnable, 100);
- isMonitoringRegion = true;
- }
+ marker.showInfoWindow();
+ return true;
+ }
+ }
+ });
+
+ map.setOnPolygonClickListener(new GoogleMap.OnPolygonClickListener() {
+ @Override
+ public void onPolygonClick(Polygon polygon) {
+ WritableMap event = makeClickEventData(polygon.getPoints().get(0));
+ event.putString("action", "polygon-press");
+ manager.pushEvent(context, polygonMap.get(polygon), "onPress", event);
+ }
+ });
+
+ map.setOnPolylineClickListener(new GoogleMap.OnPolylineClickListener() {
+ @Override
+ public void onPolylineClick(Polyline polyline) {
+ WritableMap event = makeClickEventData(polyline.getPoints().get(0));
+ event.putString("action", "polyline-press");
+ manager.pushEvent(context, polylineMap.get(polyline), "onPress", event);
+ }
+ });
+
+ map.setOnInfoWindowClickListener(new GoogleMap.OnInfoWindowClickListener() {
+ @Override
+ public void onInfoWindowClick(Marker marker) {
+ WritableMap event;
- public void stopMonitoringRegion() {
- if (!isMonitoringRegion) return;
- timerHandler.removeCallbacks(timerRunnable);
- isMonitoringRegion = false;
- }
-
- private LatLngBounds lastBoundsEmitted;
-
- Handler timerHandler = new Handler();
- Runnable timerRunnable = new Runnable() {
-
- @Override
- public void run() {
-
- Projection projection = map.getProjection();
- VisibleRegion region = (projection != null) ? projection.getVisibleRegion() : null;
- LatLngBounds bounds = (region != null) ? region.latLngBounds : null;
-
- if ((bounds != null) &&
- (lastBoundsEmitted == null || LatLngBoundsUtils.BoundsAreDifferent(bounds, lastBoundsEmitted))) {
- LatLng center = map.getCameraPosition().target;
- lastBoundsEmitted = bounds;
- eventDispatcher.dispatchEvent(new RegionChangeEvent(getId(), bounds, center, true));
- }
-
- timerHandler.postDelayed(this, 100);
- }
- };
-
- @Override
- public void onMarkerDragStart(Marker marker) {
- WritableMap event = makeClickEventData(marker.getPosition());
- manager.pushEvent(context, this, "onMarkerDragStart", event);
-
- AirMapMarker markerView = markerMap.get(marker);
event = makeClickEventData(marker.getPosition());
- manager.pushEvent(context, markerView, "onDragStart", event);
- }
-
- @Override
- public void onMarkerDrag(Marker marker) {
- WritableMap event = makeClickEventData(marker.getPosition());
- manager.pushEvent(context, this, "onMarkerDrag", event);
+ event.putString("action", "callout-press");
+ manager.pushEvent(context, view, "onCalloutPress", event);
- AirMapMarker markerView = markerMap.get(marker);
event = makeClickEventData(marker.getPosition());
- manager.pushEvent(context, markerView, "onDrag", event);
- }
-
- @Override
- public void onMarkerDragEnd(Marker marker) {
- WritableMap event = makeClickEventData(marker.getPosition());
- manager.pushEvent(context, this, "onMarkerDragEnd", event);
-
+ event.putString("action", "callout-press");
AirMapMarker markerView = markerMap.get(marker);
- event = makeClickEventData(marker.getPosition());
- manager.pushEvent(context, markerView, "onDragEnd", event);
- }
+ manager.pushEvent(context, markerView, "onCalloutPress", event);
- private ProgressBar getMapLoadingProgressBar() {
- if (this.mapLoadingProgressBar == null) {
- this.mapLoadingProgressBar = new ProgressBar(getContext());
- this.mapLoadingProgressBar.setIndeterminate(true);
+ event = makeClickEventData(marker.getPosition());
+ event.putString("action", "callout-press");
+ AirMapCallout infoWindow = markerView.getCalloutView();
+ if (infoWindow != null) manager.pushEvent(context, infoWindow, "onPress", event);
+ }
+ });
+
+ map.setOnMapClickListener(new GoogleMap.OnMapClickListener() {
+ @Override
+ public void onMapClick(LatLng point) {
+ WritableMap event = makeClickEventData(point);
+ event.putString("action", "press");
+ manager.pushEvent(context, view, "onPress", event);
+ }
+ });
+
+ map.setOnMapLongClickListener(new GoogleMap.OnMapLongClickListener() {
+ @Override
+ public void onMapLongClick(LatLng point) {
+ WritableMap event = makeClickEventData(point);
+ event.putString("action", "long-press");
+ manager.pushEvent(context, view, "onLongPress", makeClickEventData(point));
+ }
+ });
+
+ map.setOnCameraChangeListener(new GoogleMap.OnCameraChangeListener() {
+ @Override
+ public void onCameraChange(CameraPosition position) {
+ LatLngBounds bounds = map.getProjection().getVisibleRegion().latLngBounds;
+ LatLng center = position.target;
+ lastBoundsEmitted = bounds;
+ eventDispatcher.dispatchEvent(new RegionChangeEvent(getId(), bounds, center, isTouchDown));
+ view.stopMonitoringRegion();
+ }
+ });
+
+ map.setOnMapLoadedCallback(new GoogleMap.OnMapLoadedCallback() {
+ @Override public void onMapLoaded() {
+ isMapLoaded = true;
+ AirMapView.this.cacheView();
+ }
+ });
+
+ // We need to be sure to disable location-tracking when app enters background, in-case some
+ // other module
+ // has acquired a wake-lock and is controlling location-updates, otherwise, location-manager
+ // will be left
+ // updating location constantly, killing the battery, even though some other location-mgmt
+ // module may
+ // desire to shut-down location-services.
+ lifecycleListener = new LifecycleEventListener() {
+ @Override
+ public void onHostResume() {
+ if (hasPermissions()) {
+ //noinspection MissingPermission
+ map.setMyLocationEnabled(showUserLocation);
}
- if (this.loadingIndicatorColor != null) {
- this.setLoadingIndicatorColor(this.loadingIndicatorColor);
+ synchronized (AirMapView.this) {
+ AirMapView.this.onResume();
+ paused = false;
}
- return this.mapLoadingProgressBar;
- }
-
- private RelativeLayout getMapLoadingLayoutView() {
- if (this.mapLoadingLayout == null) {
- this.mapLoadingLayout = new RelativeLayout(getContext());
- this.mapLoadingLayout.setBackgroundColor(Color.LTGRAY);
- this.addView(this.mapLoadingLayout,
- new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.MATCH_PARENT));
+ }
- RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
- RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
- params.addRule(RelativeLayout.CENTER_IN_PARENT);
- this.mapLoadingLayout.addView(this.getMapLoadingProgressBar(), params);
-
- this.mapLoadingLayout.setVisibility(View.INVISIBLE);
+ @Override
+ public void onHostPause() {
+ if (hasPermissions()) {
+ //noinspection MissingPermission
+ map.setMyLocationEnabled(false);
}
- this.setLoadingBackgroundColor(this.loadingBackgroundColor);
- return this.mapLoadingLayout;
- }
-
- private ImageView getCacheImageView() {
- if (this.cacheImageView == null) {
- this.cacheImageView = new ImageView(getContext());
- this.addView(this.cacheImageView,
- new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
- this.cacheImageView.setVisibility(View.INVISIBLE);
+ synchronized (AirMapView.this) {
+ if (!destroyed) {
+ AirMapView.this.onPause();
+ }
+ paused = true;
}
- return this.cacheImageView;
- }
+ }
- private void removeCacheImageView() {
- if (this.cacheImageView != null) {
- ((ViewGroup)this.cacheImageView.getParent()).removeView(this.cacheImageView);
- this.cacheImageView = null;
- }
- }
+ @Override
+ public void onHostDestroy() {
+ AirMapView.this.doDestroy();
+ }
+ };
- private void removeMapLoadingProgressBar() {
- if (this.mapLoadingProgressBar != null) {
- ((ViewGroup)this.mapLoadingProgressBar.getParent()).removeView(this.mapLoadingProgressBar);
- this.mapLoadingProgressBar = null;
- }
- }
+ context.addLifecycleEventListener(lifecycleListener);
+ }
+
+ private boolean hasPermissions() {
+ return checkSelfPermission(getContext(), PERMISSIONS[0]) == PackageManager.PERMISSION_GRANTED ||
+ checkSelfPermission(getContext(), PERMISSIONS[1]) == PackageManager.PERMISSION_GRANTED;
+ }
+
+
+ /*
+ onDestroy is final method so I can't override it.
+ */
+ public synchronized void doDestroy() {
+ if (destroyed) {
+ return;
+ }
+ destroyed = true;
+
+ if (lifecycleListener != null && context != null) {
+ context.removeLifecycleEventListener(lifecycleListener);
+ lifecycleListener = null;
+ }
+ if (!paused) {
+ onPause();
+ paused = true;
+ }
+ onDestroy();
+ }
+
+ public void setRegion(ReadableMap region) {
+ if (region == null) return;
+
+ Double lng = region.getDouble("longitude");
+ Double lat = region.getDouble("latitude");
+ Double lngDelta = region.getDouble("longitudeDelta");
+ Double latDelta = region.getDouble("latitudeDelta");
+ LatLngBounds bounds = new LatLngBounds(
+ new LatLng(lat - latDelta / 2, lng - lngDelta / 2), // southwest
+ new LatLng(lat + latDelta / 2, lng + lngDelta / 2) // northeast
+ );
+ if (super.getHeight() <= 0 || super.getWidth() <= 0) {
+ // in this case, our map has not been laid out yet, so we save the bounds in a local
+ // variable, and make a guess of zoomLevel 10. Not to worry, though: as soon as layout
+ // occurs, we will move the camera to the saved bounds. Note that if we tried to move
+ // to the bounds now, it would trigger an exception.
+ map.moveCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(lat, lng), 10));
+ boundsToMove = bounds;
+ } else {
+ map.moveCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0));
+ boundsToMove = null;
+ }
+ }
+
+ public void setShowsUserLocation(boolean showUserLocation) {
+ this.showUserLocation = showUserLocation; // hold onto this for lifecycle handling
+ if (hasPermissions()) {
+ //noinspection MissingPermission
+ map.setMyLocationEnabled(showUserLocation);
+ }
+ }
+
+ public void setShowsMyLocationButton(boolean showMyLocationButton) {
+ if (hasPermissions()) {
+ map.getUiSettings().setMyLocationButtonEnabled(showMyLocationButton);
+ }
+ }
+
+ public void setToolbarEnabled(boolean toolbarEnabled) {
+ if (hasPermissions()) {
+ map.getUiSettings().setMapToolbarEnabled(toolbarEnabled);
+ }
+ }
+
+ public void setCacheEnabled(boolean cacheEnabled) {
+ this.cacheEnabled = cacheEnabled;
+ this.cacheView();
+ }
+
+ public void enableMapLoading(boolean loadingEnabled) {
+ if (loadingEnabled && !this.isMapLoaded) {
+ this.getMapLoadingLayoutView().setVisibility(View.VISIBLE);
+ }
+ }
+
+ public void setMoveOnMarkerPress(boolean moveOnPress) {
+ this.moveOnMarkerPress = moveOnPress;
+ }
+
+ public void setLoadingBackgroundColor(Integer loadingBackgroundColor) {
+ this.loadingBackgroundColor = loadingBackgroundColor;
+
+ if (this.mapLoadingLayout != null) {
+ if (loadingBackgroundColor == null) {
+ this.mapLoadingLayout.setBackgroundColor(Color.WHITE);
+ } else {
+ this.mapLoadingLayout.setBackgroundColor(this.loadingBackgroundColor);
+ }
+ }
+ }
+
+ public void setLoadingIndicatorColor(Integer loadingIndicatorColor) {
+ this.loadingIndicatorColor = loadingIndicatorColor;
+ if (this.mapLoadingProgressBar != null) {
+ Integer color = loadingIndicatorColor;
+ if (color == null) {
+ color = Color.parseColor("#606060");
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ ColorStateList progressTintList = ColorStateList.valueOf(loadingIndicatorColor);
+ ColorStateList secondaryProgressTintList = ColorStateList.valueOf(loadingIndicatorColor);
+ ColorStateList indeterminateTintList = ColorStateList.valueOf(loadingIndicatorColor);
+
+ this.mapLoadingProgressBar.setProgressTintList(progressTintList);
+ this.mapLoadingProgressBar.setSecondaryProgressTintList(secondaryProgressTintList);
+ this.mapLoadingProgressBar.setIndeterminateTintList(indeterminateTintList);
+ } else {
+ PorterDuff.Mode mode = PorterDuff.Mode.SRC_IN;
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.GINGERBREAD_MR1) {
+ mode = PorterDuff.Mode.MULTIPLY;
+ }
+ if (this.mapLoadingProgressBar.getIndeterminateDrawable() != null)
+ this.mapLoadingProgressBar.getIndeterminateDrawable().setColorFilter(color, mode);
+ if (this.mapLoadingProgressBar.getProgressDrawable() != null)
+ this.mapLoadingProgressBar.getProgressDrawable().setColorFilter(color, mode);
+ }
+ }
+ }
+
+ public void setHandlePanDrag(boolean handlePanDrag) {
+ this.handlePanDrag = handlePanDrag;
+ }
+
+ public void addFeature(View child, int index) {
+ // Our desired API is to pass up annotations/overlays as children to the mapview component.
+ // This is where we intercept them and do the appropriate underlying mapview action.
+
+ if (child instanceof AirMapMarker) {
+ AirMapMarker annotation = (AirMapMarker) child;
+ annotation.addToMap(map);
+ features.add(index, annotation);
+ Marker marker = (Marker) annotation.getFeature();
+ markerMap.put(marker, annotation);
+ } else if (child instanceof AirMapPolyline) {
+ AirMapPolyline polylineView = (AirMapPolyline) child;
+ polylineView.addToMap(map);
+ features.add(index, polylineView);
+ Polyline polyline = (Polyline) polylineView.getFeature();
+ polylineMap.put(polyline, polylineView);
+ } else if (child instanceof AirMapPolygon) {
+ AirMapPolygon polygonView = (AirMapPolygon) child;
+ polygonView.addToMap(map);
+ features.add(index, polygonView);
+ Polygon polygon = (Polygon) polygonView.getFeature();
+ polygonMap.put(polygon, polygonView);
+ } else if (child instanceof AirMapCircle) {
+ AirMapCircle circleView = (AirMapCircle) child;
+ circleView.addToMap(map);
+ features.add(index, circleView);
+ } else if (child instanceof AirMapUrlTile) {
+ AirMapUrlTile urlTileView = (AirMapUrlTile) child;
+ urlTileView.addToMap(map);
+ features.add(index, urlTileView);
+ } else if (child instanceof AirMapCanvasUrlTile) {
+ AirMapCanvasUrlTile canvasUrlTileView = (AirMapCanvasUrlTile) child;
+ canvasUrlTileView.addToMap(map);
+ features.add(index, canvasUrlTileView);
+ } else if (child instanceof AirMapCanvasInteractionUrlTile) {
+ AirMapCanvasInteractionUrlTile canvasInteractionUrlTileView = (AirMapCanvasInteractionUrlTile) child;
+ canvasInteractionUrlTileView.addToMap(map);
+ features.add(index, canvasInteractionUrlTileView);
+ } else {
+ ViewGroup children = (ViewGroup) child;
+ for (int i = 0; i < children.getChildCount(); i++) {
+ addFeature(children.getChildAt(i), index);
+ }
+ }
+ }
+
+ public int getFeatureCount() {
+ return features.size();
+ }
+
+ public View getFeatureAt(int index) {
+ return features.get(index);
+ }
+
+ public void removeFeatureAt(int index) {
+ AirMapFeature feature = features.remove(index);
+ if (feature instanceof AirMapMarker) {
+ markerMap.remove(feature.getFeature());
+ }
+ feature.removeFromMap(map);
+ }
+
+ public WritableMap makeClickEventData(LatLng point) {
+ WritableMap event = new WritableNativeMap();
+
+ WritableMap coordinate = new WritableNativeMap();
+ coordinate.putDouble("latitude", point.latitude);
+ coordinate.putDouble("longitude", point.longitude);
+ event.putMap("coordinate", coordinate);
+
+ Projection projection = map.getProjection();
+ Point screenPoint = projection.toScreenLocation(point);
+
+ WritableMap position = new WritableNativeMap();
+ position.putDouble("x", screenPoint.x);
+ position.putDouble("y", screenPoint.y);
+ event.putMap("position", position);
+
+ return event;
+ }
+
+ public void updateExtraData(Object extraData) {
+ // if boundsToMove is not null, we now have the MapView's width/height, so we can apply
+ // a proper camera move
+ if (boundsToMove != null) {
+ HashMap data = (HashMap) extraData;
+ float width = data.get("width");
+ float height = data.get("height");
+ map.moveCamera(
+ CameraUpdateFactory.newLatLngBounds(
+ boundsToMove,
+ (int) width,
+ (int) height,
+ 0
+ )
+ );
+ boundsToMove = null;
+ }
+ }
+
+ public void animateToRegion(LatLngBounds bounds, int duration) {
+ if (map != null) {
+ startMonitoringRegion();
+ map.animateCamera(CameraUpdateFactory.newLatLngBounds(bounds, 0), duration, null);
+ }
+ }
+
+ public void animateToCoordinate(LatLng coordinate, int duration) {
+ if (map != null) {
+ startMonitoringRegion();
+ map.animateCamera(CameraUpdateFactory.newLatLng(coordinate), duration, null);
+ }
+ }
+
+ public void fitToElements(boolean animated) {
+ LatLngBounds.Builder builder = new LatLngBounds.Builder();
+
+ boolean addedPosition = false;
+
+ for (AirMapFeature feature : features) {
+ if (feature instanceof AirMapMarker) {
+ Marker marker = (Marker) feature.getFeature();
+ builder.include(marker.getPosition());
+ addedPosition = true;
+ }
+ // TODO(lmr): may want to include shapes / etc.
+ }
+ if (addedPosition) {
+ LatLngBounds bounds = builder.build();
+ CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, baseMapPadding);
+ if (animated) {
+ startMonitoringRegion();
+ map.animateCamera(cu);
+ } else {
+ map.moveCamera(cu);
+ }
+ }
+ }
+
+ public void fitToSuppliedMarkers(ReadableArray markerIDsArray, boolean animated) {
+ LatLngBounds.Builder builder = new LatLngBounds.Builder();
+
+ String[] markerIDs = new String[markerIDsArray.size()];
+ for (int i = 0; i < markerIDsArray.size(); i++) {
+ markerIDs[i] = markerIDsArray.getString(i);
+ }
+
+ boolean addedPosition = false;
+
+ List markerIDList = Arrays.asList(markerIDs);
+
+ for (AirMapFeature feature : features) {
+ if (feature instanceof AirMapMarker) {
+ String identifier = ((AirMapMarker) feature).getIdentifier();
+ Marker marker = (Marker) feature.getFeature();
+ if (markerIDList.contains(identifier)) {
+ builder.include(marker.getPosition());
+ addedPosition = true;
+ }
+ }
+ }
+
+ if (addedPosition) {
+ LatLngBounds bounds = builder.build();
+ CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, baseMapPadding);
+ if (animated) {
+ startMonitoringRegion();
+ map.animateCamera(cu);
+ } else {
+ map.moveCamera(cu);
+ }
+ }
+ }
+
+ public void fitToCoordinates(ReadableArray coordinatesArray, ReadableMap edgePadding,
+ boolean animated) {
+ LatLngBounds.Builder builder = new LatLngBounds.Builder();
+
+ for (int i = 0; i < coordinatesArray.size(); i++) {
+ ReadableMap latLng = coordinatesArray.getMap(i);
+ Double lat = latLng.getDouble("latitude");
+ Double lng = latLng.getDouble("longitude");
+ builder.include(new LatLng(lat, lng));
+ }
+
+ LatLngBounds bounds = builder.build();
+ CameraUpdate cu = CameraUpdateFactory.newLatLngBounds(bounds, baseMapPadding);
+
+ if (edgePadding != null) {
+ map.setPadding(edgePadding.getInt("left"), edgePadding.getInt("top"),
+ edgePadding.getInt("right"), edgePadding.getInt("bottom"));
+ }
+
+ if (animated) {
+ startMonitoringRegion();
+ map.animateCamera(cu);
+ } else {
+ map.moveCamera(cu);
+ }
+ map.setPadding(0, 0, 0,
+ 0); // Without this, the Google logo is moved up by the value of edgePadding.bottom
+ }
+
+ // InfoWindowAdapter interface
- private void removeMapLoadingLayoutView() {
- this.removeMapLoadingProgressBar();
- if (this.mapLoadingLayout != null) {
- ((ViewGroup)this.mapLoadingLayout.getParent()).removeView(this.mapLoadingLayout);
- this.mapLoadingLayout = null;
- }
+ @Override
+ public View getInfoWindow(Marker marker) {
+ AirMapMarker markerView = markerMap.get(marker);
+ return markerView.getCallout();
+ }
+
+ @Override
+ public View getInfoContents(Marker marker) {
+ AirMapMarker markerView = markerMap.get(marker);
+ return markerView.getInfoContents();
+ }
+
+ @Override
+ public boolean dispatchTouchEvent(MotionEvent ev) {
+ scaleDetector.onTouchEvent(ev);
+ gestureDetector.onTouchEvent(ev);
+
+ int action = MotionEventCompat.getActionMasked(ev);
+
+ switch (action) {
+ case (MotionEvent.ACTION_DOWN):
+ this.getParent().requestDisallowInterceptTouchEvent(
+ map != null && map.getUiSettings().isScrollGesturesEnabled());
+ isTouchDown = true;
+ break;
+ case (MotionEvent.ACTION_MOVE):
+ startMonitoringRegion();
+ break;
+ case (MotionEvent.ACTION_UP):
+ // Clear this regardless, since isScrollGesturesEnabled() may have been updated
+ this.getParent().requestDisallowInterceptTouchEvent(false);
+ isTouchDown = false;
+ break;
}
+ super.dispatchTouchEvent(ev);
+ return true;
+ }
+
+ // Timer Implementation
- private void cacheView() {
- if (this.cacheEnabled) {
- final ImageView cacheImageView = this.getCacheImageView();
- final RelativeLayout mapLoadingLayout = this.getMapLoadingLayoutView();
- cacheImageView.setVisibility(View.INVISIBLE);
- mapLoadingLayout.setVisibility(View.VISIBLE);
- if (this.isMapLoaded) {
- this.map.snapshot(new GoogleMap.SnapshotReadyCallback() {
- @Override public void onSnapshotReady(Bitmap bitmap) {
- cacheImageView.setImageBitmap(bitmap);
- cacheImageView.setVisibility(View.VISIBLE);
- mapLoadingLayout.setVisibility(View.INVISIBLE);
- }
- });
- }
- }
- else {
- this.removeCacheImageView();
- if (this.isMapLoaded) {
- this.removeMapLoadingLayoutView();
- }
- }
- }
+ public void startMonitoringRegion() {
+ if (isMonitoringRegion) return;
+ timerHandler.postDelayed(timerRunnable, 100);
+ isMonitoringRegion = true;
+ }
+
+ public void stopMonitoringRegion() {
+ if (!isMonitoringRegion) return;
+ timerHandler.removeCallbacks(timerRunnable);
+ isMonitoringRegion = false;
+ }
+
+ private LatLngBounds lastBoundsEmitted;
+
+ Handler timerHandler = new Handler();
+ Runnable timerRunnable = new Runnable() {
- public void onPanDrag(MotionEvent ev) {
- Point point = new Point((int) ev.getX(), (int) ev.getY());
- LatLng coords = this.map.getProjection().fromScreenLocation(point);
- WritableMap event = makeClickEventData(coords);
- manager.pushEvent(context, this, "onPanDrag", event);
- }
+ @Override
+ public void run() {
+
+ Projection projection = map.getProjection();
+ VisibleRegion region = (projection != null) ? projection.getVisibleRegion() : null;
+ LatLngBounds bounds = (region != null) ? region.latLngBounds : null;
+
+ if ((bounds != null) &&
+ (lastBoundsEmitted == null ||
+ LatLngBoundsUtils.BoundsAreDifferent(bounds, lastBoundsEmitted))) {
+ LatLng center = map.getCameraPosition().target;
+ lastBoundsEmitted = bounds;
+ eventDispatcher.dispatchEvent(new RegionChangeEvent(getId(), bounds, center, true));
+ }
+
+ timerHandler.postDelayed(this, 100);
+ }
+ };
+
+ @Override
+ public void onMarkerDragStart(Marker marker) {
+ WritableMap event = makeClickEventData(marker.getPosition());
+ manager.pushEvent(context, this, "onMarkerDragStart", event);
+
+ AirMapMarker markerView = markerMap.get(marker);
+ event = makeClickEventData(marker.getPosition());
+ manager.pushEvent(context, markerView, "onDragStart", event);
+ }
+
+ @Override
+ public void onMarkerDrag(Marker marker) {
+ WritableMap event = makeClickEventData(marker.getPosition());
+ manager.pushEvent(context, this, "onMarkerDrag", event);
+
+ AirMapMarker markerView = markerMap.get(marker);
+ event = makeClickEventData(marker.getPosition());
+ manager.pushEvent(context, markerView, "onDrag", event);
+ }
+
+ @Override
+ public void onMarkerDragEnd(Marker marker) {
+ WritableMap event = makeClickEventData(marker.getPosition());
+ manager.pushEvent(context, this, "onMarkerDragEnd", event);
+
+ AirMapMarker markerView = markerMap.get(marker);
+ event = makeClickEventData(marker.getPosition());
+ manager.pushEvent(context, markerView, "onDragEnd", event);
+ }
+
+ private ProgressBar getMapLoadingProgressBar() {
+ if (this.mapLoadingProgressBar == null) {
+ this.mapLoadingProgressBar = new ProgressBar(getContext());
+ this.mapLoadingProgressBar.setIndeterminate(true);
+ }
+ if (this.loadingIndicatorColor != null) {
+ this.setLoadingIndicatorColor(this.loadingIndicatorColor);
+ }
+ return this.mapLoadingProgressBar;
+ }
+
+ private RelativeLayout getMapLoadingLayoutView() {
+ if (this.mapLoadingLayout == null) {
+ this.mapLoadingLayout = new RelativeLayout(getContext());
+ this.mapLoadingLayout.setBackgroundColor(Color.LTGRAY);
+ this.addView(this.mapLoadingLayout,
+ new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+
+ RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(
+ RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
+ params.addRule(RelativeLayout.CENTER_IN_PARENT);
+ this.mapLoadingLayout.addView(this.getMapLoadingProgressBar(), params);
+
+ this.mapLoadingLayout.setVisibility(View.INVISIBLE);
+ }
+ this.setLoadingBackgroundColor(this.loadingBackgroundColor);
+ return this.mapLoadingLayout;
+ }
+
+ private ImageView getCacheImageView() {
+ if (this.cacheImageView == null) {
+ this.cacheImageView = new ImageView(getContext());
+ this.addView(this.cacheImageView,
+ new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT));
+ this.cacheImageView.setVisibility(View.INVISIBLE);
+ }
+ return this.cacheImageView;
+ }
+
+ private void removeCacheImageView() {
+ if (this.cacheImageView != null) {
+ ((ViewGroup) this.cacheImageView.getParent()).removeView(this.cacheImageView);
+ this.cacheImageView = null;
+ }
+ }
+
+ private void removeMapLoadingProgressBar() {
+ if (this.mapLoadingProgressBar != null) {
+ ((ViewGroup) this.mapLoadingProgressBar.getParent()).removeView(this.mapLoadingProgressBar);
+ this.mapLoadingProgressBar = null;
+ }
+ }
+
+ private void removeMapLoadingLayoutView() {
+ this.removeMapLoadingProgressBar();
+ if (this.mapLoadingLayout != null) {
+ ((ViewGroup) this.mapLoadingLayout.getParent()).removeView(this.mapLoadingLayout);
+ this.mapLoadingLayout = null;
+ }
+ }
+
+ private void cacheView() {
+ if (this.cacheEnabled) {
+ final ImageView cacheImageView = this.getCacheImageView();
+ final RelativeLayout mapLoadingLayout = this.getMapLoadingLayoutView();
+ cacheImageView.setVisibility(View.INVISIBLE);
+ mapLoadingLayout.setVisibility(View.VISIBLE);
+ if (this.isMapLoaded) {
+ this.map.snapshot(new GoogleMap.SnapshotReadyCallback() {
+ @Override public void onSnapshotReady(Bitmap bitmap) {
+ cacheImageView.setImageBitmap(bitmap);
+ cacheImageView.setVisibility(View.VISIBLE);
+ mapLoadingLayout.setVisibility(View.INVISIBLE);
+ }
+ });
+ }
+ } else {
+ this.removeCacheImageView();
+ if (this.isMapLoaded) {
+ this.removeMapLoadingLayoutView();
+ }
+ }
+ }
+
+ public void onPanDrag(MotionEvent ev) {
+ Point point = new Point((int) ev.getX(), (int) ev.getY());
+ LatLng coords = this.map.getProjection().fromScreenLocation(point);
+ WritableMap event = makeClickEventData(coords);
+ manager.pushEvent(context, this, "onPanDrag", event);
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/LatLngBoundsUtils.java b/lib/android/src/main/java/com/airbnb/android/react/maps/LatLngBoundsUtils.java
index ed1058c88..d32e0dc72 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/LatLngBoundsUtils.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/LatLngBoundsUtils.java
@@ -4,44 +4,44 @@
import com.google.android.gms.maps.model.LatLngBounds;
public class LatLngBoundsUtils {
- public static boolean BoundsAreDifferent(LatLngBounds a, LatLngBounds b) {
- LatLng centerA = a.getCenter();
- double latA = centerA.latitude;
- double lngA = centerA.longitude;
- double latDeltaA = a.northeast.latitude - a.southwest.latitude;
- double lngDeltaA = a.northeast.longitude - a.southwest.longitude;
-
- LatLng centerB = b.getCenter();
- double latB = centerB.latitude;
- double lngB = centerB.longitude;
- double latDeltaB = b.northeast.latitude - b.southwest.latitude;
- double lngDeltaB = b.northeast.longitude - b.southwest.longitude;
-
- double latEps = LatitudeEpsilon(a, b);
- double lngEps = LongitudeEpsilon(a, b);
-
- return
- different(latA, latB, latEps) ||
- different(lngA, lngB, lngEps) ||
- different(latDeltaA, latDeltaB, latEps) ||
- different(lngDeltaA, lngDeltaB, lngEps);
- }
-
- private static boolean different(double a, double b, double epsilon) {
- return Math.abs(a - b) > epsilon;
- }
-
- private static double LatitudeEpsilon(LatLngBounds a, LatLngBounds b) {
- double sizeA = a.northeast.latitude - a.southwest.latitude; // something mod 180?
- double sizeB = b.northeast.latitude - b.southwest.latitude; // something mod 180?
- double size = Math.min(Math.abs(sizeA), Math.abs(sizeB));
- return size / 2560;
- }
-
- private static double LongitudeEpsilon(LatLngBounds a, LatLngBounds b) {
- double sizeA = a.northeast.longitude - a.southwest.longitude;
- double sizeB = b.northeast.longitude - b.southwest.longitude;
- double size = Math.min(Math.abs(sizeA), Math.abs(sizeB));
- return size / 2560;
- }
+ public static boolean BoundsAreDifferent(LatLngBounds a, LatLngBounds b) {
+ LatLng centerA = a.getCenter();
+ double latA = centerA.latitude;
+ double lngA = centerA.longitude;
+ double latDeltaA = a.northeast.latitude - a.southwest.latitude;
+ double lngDeltaA = a.northeast.longitude - a.southwest.longitude;
+
+ LatLng centerB = b.getCenter();
+ double latB = centerB.latitude;
+ double lngB = centerB.longitude;
+ double latDeltaB = b.northeast.latitude - b.southwest.latitude;
+ double lngDeltaB = b.northeast.longitude - b.southwest.longitude;
+
+ double latEps = LatitudeEpsilon(a, b);
+ double lngEps = LongitudeEpsilon(a, b);
+
+ return
+ different(latA, latB, latEps) ||
+ different(lngA, lngB, lngEps) ||
+ different(latDeltaA, latDeltaB, latEps) ||
+ different(lngDeltaA, lngDeltaB, lngEps);
+ }
+
+ private static boolean different(double a, double b, double epsilon) {
+ return Math.abs(a - b) > epsilon;
+ }
+
+ private static double LatitudeEpsilon(LatLngBounds a, LatLngBounds b) {
+ double sizeA = a.northeast.latitude - a.southwest.latitude; // something mod 180?
+ double sizeB = b.northeast.latitude - b.southwest.latitude; // something mod 180?
+ double size = Math.min(Math.abs(sizeA), Math.abs(sizeB));
+ return size / 2560;
+ }
+
+ private static double LongitudeEpsilon(LatLngBounds a, LatLngBounds b) {
+ double sizeA = a.northeast.longitude - a.southwest.longitude;
+ double sizeB = b.northeast.longitude - b.southwest.longitude;
+ double size = Math.min(Math.abs(sizeA), Math.abs(sizeB));
+ return size / 2560;
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java b/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java
index 5284e1581..db17b99ed 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/MapsPackage.java
@@ -13,45 +13,43 @@
import java.util.List;
public class MapsPackage implements ReactPackage {
- public MapsPackage(Activity activity) {
- } // backwards compatibility
-
- public MapsPackage() {
- }
-
- @Override
- public List createNativeModules(ReactApplicationContext reactContext) {
- return Arrays.asList(new AirMapModule(reactContext));
- }
-
- @Override
- public List> createJSModules() {
- return Collections.emptyList();
- }
-
- @Override
- public List createViewManagers(ReactApplicationContext reactContext) {
- AirMapCalloutManager calloutManager = new AirMapCalloutManager();
- AirMapMarkerManager annotationManager = new AirMapMarkerManager();
- AirMapPolylineManager polylineManager = new AirMapPolylineManager(reactContext);
- AirMapPolygonManager polygonManager = new AirMapPolygonManager(reactContext);
- AirMapCircleManager circleManager = new AirMapCircleManager(reactContext);
- AirMapManager mapManager = new AirMapManager(reactContext);
- AirMapLiteManager mapLiteManager = new AirMapLiteManager(reactContext);
- AirMapUrlTileManager tileManager = new AirMapUrlTileManager(reactContext);
- AirMapCanvasUrlTileManager canvasTileManager = new AirMapCanvasUrlTileManager(reactContext);
- AirMapCanvasInteractionUrlTileManager canvasInteractionTileManager = new AirMapCanvasInteractionUrlTileManager(reactContext);
-
- return Arrays.asList(
- calloutManager,
- annotationManager,
- polylineManager,
- polygonManager,
- circleManager,
- mapManager,
- mapLiteManager,
- tileManager,
- canvasTileManager,
- canvasInteractionTileManager);
- }
+ public MapsPackage(Activity activity) {
+ } // backwards compatibility
+
+ public MapsPackage() {
+ }
+
+ @Override
+ public List createNativeModules(ReactApplicationContext reactContext) {
+ return Arrays.asList(new AirMapModule(reactContext));
+ }
+
+ @Override
+ public List> createJSModules() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List createViewManagers(ReactApplicationContext reactContext) {
+ AirMapCalloutManager calloutManager = new AirMapCalloutManager();
+ AirMapMarkerManager annotationManager = new AirMapMarkerManager();
+ AirMapPolylineManager polylineManager = new AirMapPolylineManager(reactContext);
+ AirMapPolygonManager polygonManager = new AirMapPolygonManager(reactContext);
+ AirMapCircleManager circleManager = new AirMapCircleManager(reactContext);
+ AirMapManager mapManager = new AirMapManager(reactContext);
+ AirMapLiteManager mapLiteManager = new AirMapLiteManager(reactContext);
+ AirMapUrlTileManager tileManager = new AirMapUrlTileManager(reactContext);
+ AirMapCanvasInteractionUrlTileManager canvasInteractionTileManager = new AirMapCanvasInteractionUrlTileManager(reactContext);
+
+ return Arrays.asList(
+ calloutManager,
+ annotationManager,
+ polylineManager,
+ polygonManager,
+ circleManager,
+ mapManager,
+ mapLiteManager,
+ tileManager,
+ canvasInteractionTileManager);
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/RegionChangeEvent.java b/lib/android/src/main/java/com/airbnb/android/react/maps/RegionChangeEvent.java
index 28a3b322b..43b1f678e 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/RegionChangeEvent.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/RegionChangeEvent.java
@@ -8,40 +8,40 @@
import com.google.android.gms.maps.model.LatLngBounds;
public class RegionChangeEvent extends Event {
- private final LatLngBounds bounds;
- private final LatLng center;
- private final boolean continuous;
-
- public RegionChangeEvent(int id, LatLngBounds bounds, LatLng center, boolean continuous) {
- super(id);
- this.bounds = bounds;
- this.center = center;
- this.continuous = continuous;
- }
-
- @Override
- public String getEventName() {
- return "topChange";
- }
-
- @Override
- public boolean canCoalesce() {
- return false;
- }
-
- @Override
- public void dispatch(RCTEventEmitter rctEventEmitter) {
-
- WritableMap event = new WritableNativeMap();
- event.putBoolean("continuous", continuous);
-
- WritableMap region = new WritableNativeMap();
- region.putDouble("latitude", center.latitude);
- region.putDouble("longitude", center.longitude);
- region.putDouble("latitudeDelta", bounds.northeast.latitude - bounds.southwest.latitude);
- region.putDouble("longitudeDelta", bounds.northeast.longitude - bounds.southwest.longitude);
- event.putMap("region", region);
-
- rctEventEmitter.receiveEvent(getViewTag(), getEventName(), event);
- }
+ private final LatLngBounds bounds;
+ private final LatLng center;
+ private final boolean continuous;
+
+ public RegionChangeEvent(int id, LatLngBounds bounds, LatLng center, boolean continuous) {
+ super(id);
+ this.bounds = bounds;
+ this.center = center;
+ this.continuous = continuous;
+ }
+
+ @Override
+ public String getEventName() {
+ return "topChange";
+ }
+
+ @Override
+ public boolean canCoalesce() {
+ return false;
+ }
+
+ @Override
+ public void dispatch(RCTEventEmitter rctEventEmitter) {
+
+ WritableMap event = new WritableNativeMap();
+ event.putBoolean("continuous", continuous);
+
+ WritableMap region = new WritableNativeMap();
+ region.putDouble("latitude", center.latitude);
+ region.putDouble("longitude", center.longitude);
+ region.putDouble("latitudeDelta", bounds.northeast.latitude - bounds.southwest.latitude);
+ region.putDouble("longitudeDelta", bounds.northeast.longitude - bounds.southwest.longitude);
+ event.putMap("region", region);
+
+ rctEventEmitter.receiveEvent(getViewTag(), getEventName(), event);
+ }
}
diff --git a/lib/android/src/main/java/com/airbnb/android/react/maps/SizeReportingShadowNode.java b/lib/android/src/main/java/com/airbnb/android/react/maps/SizeReportingShadowNode.java
index 40ace480f..bf6c29d65 100644
--- a/lib/android/src/main/java/com/airbnb/android/react/maps/SizeReportingShadowNode.java
+++ b/lib/android/src/main/java/com/airbnb/android/react/maps/SizeReportingShadowNode.java
@@ -18,14 +18,14 @@
// which sends the width/height of the view after layout occurs.
public class SizeReportingShadowNode extends LayoutShadowNode {
- @Override
- public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
- super.onCollectExtraUpdates(uiViewOperationQueue);
+ @Override
+ public void onCollectExtraUpdates(UIViewOperationQueue uiViewOperationQueue) {
+ super.onCollectExtraUpdates(uiViewOperationQueue);
- Map data = new HashMap<>();
- data.put("width", getLayoutWidth());
- data.put("height", getLayoutHeight());
+ Map data = new HashMap<>();
+ data.put("width", getLayoutWidth());
+ data.put("height", getLayoutHeight());
- uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), data);
- }
+ uiViewOperationQueue.enqueueUpdateExtraData(getReactTag(), data);
+ }
}
diff --git a/lib/components/MapCallout.js b/lib/components/MapCallout.js
index cf4bb9cef..226b52fe2 100644
--- a/lib/components/MapCallout.js
+++ b/lib/components/MapCallout.js
@@ -1,7 +1,8 @@
-import React, { PropTypes } from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {
- View,
StyleSheet,
+ ViewPropTypes,
} from 'react-native';
import decorateMapComponent, {
SUPPORTED,
@@ -9,7 +10,7 @@ import decorateMapComponent, {
} from './decorateMapComponent';
const propTypes = {
- ...View.propTypes,
+ ...ViewPropTypes,
tooltip: PropTypes.bool,
onPress: PropTypes.func,
};
diff --git a/lib/components/MapCircle.js b/lib/components/MapCircle.js
index aab1ba8f1..acf066b24 100644
--- a/lib/components/MapCircle.js
+++ b/lib/components/MapCircle.js
@@ -1,6 +1,7 @@
-import React, { PropTypes } from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {
- View,
+ ViewPropTypes,
} from 'react-native';
import decorateMapComponent, {
USES_DEFAULT_IMPLEMENTATION,
@@ -8,7 +9,7 @@ import decorateMapComponent, {
} from './decorateMapComponent';
const propTypes = {
- ...View.propTypes,
+ ...ViewPropTypes,
/**
* The coordinate of the center of the circle
diff --git a/lib/components/MapMarker.js b/lib/components/MapMarker.js
index be54e42db..6e2b8585d 100644
--- a/lib/components/MapMarker.js
+++ b/lib/components/MapMarker.js
@@ -1,11 +1,12 @@
-import React, { PropTypes } from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {
- View,
StyleSheet,
Platform,
NativeModules,
Animated,
findNodeHandle,
+ ViewPropTypes,
} from 'react-native';
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
@@ -22,7 +23,7 @@ const viewConfig = {
};
const propTypes = {
- ...View.propTypes,
+ ...ViewPropTypes,
// TODO(lmr): get rid of these?
identifier: PropTypes.string,
diff --git a/lib/components/MapPolygon.js b/lib/components/MapPolygon.js
index 6901979db..27f2aa322 100644
--- a/lib/components/MapPolygon.js
+++ b/lib/components/MapPolygon.js
@@ -1,6 +1,7 @@
-import React, { PropTypes } from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {
- View,
+ ViewPropTypes,
} from 'react-native';
import decorateMapComponent, {
USES_DEFAULT_IMPLEMENTATION,
@@ -8,7 +9,7 @@ import decorateMapComponent, {
} from './decorateMapComponent';
const propTypes = {
- ...View.propTypes,
+ ...ViewPropTypes,
/**
* An array of coordinates to describe the polygon
diff --git a/lib/components/MapPolyline.js b/lib/components/MapPolyline.js
index aa79f096b..af1573eff 100644
--- a/lib/components/MapPolyline.js
+++ b/lib/components/MapPolyline.js
@@ -1,6 +1,7 @@
-import React, { PropTypes } from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {
- View,
+ ViewPropTypes,
} from 'react-native';
import decorateMapComponent, {
USES_DEFAULT_IMPLEMENTATION,
@@ -8,7 +9,7 @@ import decorateMapComponent, {
} from './decorateMapComponent';
const propTypes = {
- ...View.propTypes,
+ ...ViewPropTypes,
/**
* An array of coordinates to describe the polygon
diff --git a/lib/components/MapUrlTile.js b/lib/components/MapUrlTile.js
index cf2770334..f61c1e0d3 100644
--- a/lib/components/MapUrlTile.js
+++ b/lib/components/MapUrlTile.js
@@ -1,7 +1,8 @@
-import React, { PropTypes } from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {
- View,
+ ViewPropTypes,
} from 'react-native';
import decorateMapComponent, {
@@ -10,7 +11,7 @@ import decorateMapComponent, {
} from './decorateMapComponent';
const propTypes = {
- ...View.propTypes,
+ ...ViewPropTypes,
/**
* The url template of the tile server. The patterns {x} {y} {z} will be replaced at runtime
diff --git a/lib/components/MapView.js b/lib/components/MapView.js
index 1b416687b..7b0b6fb0f 100644
--- a/lib/components/MapView.js
+++ b/lib/components/MapView.js
@@ -1,13 +1,14 @@
-import React, { PropTypes } from 'react';
+import PropTypes from 'prop-types';
+import React from 'react';
import {
EdgeInsetsPropType,
Platform,
- View,
Animated,
requireNativeComponent,
NativeModules,
ColorPropType,
findNodeHandle,
+ ViewPropTypes,
} from 'react-native';
import MapMarker from './MapMarker';
import MapPolyline from './MapPolyline';
@@ -47,7 +48,7 @@ const viewConfig = {
};
const propTypes = {
- ...View.propTypes,
+ ...ViewPropTypes,
/**
* When provider is "google", we will use GoogleMaps.
* Any value other than "google" will default to using
@@ -61,7 +62,7 @@ const propTypes = {
* Used to style and layout the `MapView`. See `StyleSheet.js` and
* `ViewStylePropTypes.js` for more info.
*/
- style: View.propTypes.style,
+ style: ViewPropTypes.style,
/**
* A json object that describes the style of the map. This is transformed to a string
@@ -386,6 +387,16 @@ const propTypes = {
*/
onMarkerDragEnd: PropTypes.func,
+ /**
+ * Minimum zoom value for the map, must be between 0 and 20
+ */
+ minZoomLevel: PropTypes.number,
+
+ /**
+ * Maximum zoom value for the map, must be between 0 and 20
+ */
+ maxZoomLevel: PropTypes.number,
+
};
class MapView extends React.Component {
diff --git a/lib/components/decorateMapComponent.js b/lib/components/decorateMapComponent.js
index e655c4c33..168d4f122 100644
--- a/lib/components/decorateMapComponent.js
+++ b/lib/components/decorateMapComponent.js
@@ -1,4 +1,4 @@
-import { PropTypes } from 'react';
+import PropTypes from 'prop-types';
import {
requireNativeComponent,
NativeModules,
diff --git a/lib/ios/AirGoogleMaps/AIRGMSPolyline.h b/lib/ios/AirGoogleMaps/AIRGMSPolyline.h
index 64a3afb99..d7ee19783 100644
--- a/lib/ios/AirGoogleMaps/AIRGMSPolyline.h
+++ b/lib/ios/AirGoogleMaps/AIRGMSPolyline.h
@@ -6,7 +6,7 @@
//
#import
-#import "UIView+React.h"
+#import
@class AIRGoogleMapPolyline;
diff --git a/lib/ios/AirGoogleMaps/AIRGoogleMap.m b/lib/ios/AirGoogleMaps/AIRGoogleMap.m
index ef73067b6..f87d34c63 100644
--- a/lib/ios/AirGoogleMaps/AIRGoogleMap.m
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMap.m
@@ -300,6 +300,13 @@ - (BOOL)showsMyLocationButton {
return self.settings.myLocationButton;
}
+- (void)setMinZoomLevel:(CGFloat)minZoomLevel {
+ [self setMinZoom:minZoomLevel maxZoom:self.maxZoom ];
+}
+
+- (void)setMaxZoomLevel:(CGFloat)maxZoomLevel {
+ [self setMinZoom:self.minZoom maxZoom:maxZoomLevel ];
+}
+ (MKCoordinateRegion) makeGMSCameraPositionFromMap:(GMSMapView *)map andGMSCameraPosition:(GMSCameraPosition *)position {
// solution from here: http://stackoverflow.com/a/16587735/1102215
diff --git a/lib/ios/AirGoogleMaps/AIRGoogleMapManager.m b/lib/ios/AirGoogleMaps/AIRGoogleMapManager.m
index 785d58d4d..c482305b8 100644
--- a/lib/ios/AirGoogleMaps/AIRGoogleMapManager.m
+++ b/lib/ios/AirGoogleMaps/AIRGoogleMapManager.m
@@ -26,6 +26,7 @@
#import "RCTConvert+AirMap.h"
#import
+#import
static NSString *const RCTMapViewKey = @"MapView";
@@ -65,6 +66,8 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(onRegionChange, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onRegionChangeComplete, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(mapType, GMSMapViewType)
+RCT_EXPORT_VIEW_PROPERTY(minZoomLevel, CGFloat)
+RCT_EXPORT_VIEW_PROPERTY(maxZoomLevel, CGFloat)
RCT_EXPORT_METHOD(animateToRegion:(nonnull NSNumber *)reactTag
withRegion:(MKCoordinateRegion)region
@@ -75,10 +78,31 @@ - (UIView *)view
if (![view isKindOfClass:[AIRGoogleMap class]]) {
RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
} else {
- [AIRGoogleMap animateWithDuration:duration/1000 animations:^{
- GMSCameraPosition* camera = [AIRGoogleMap makeGMSCameraPositionFromMap:(AIRGoogleMap *)view andMKCoordinateRegion:region];
- [(AIRGoogleMap *)view animateToCameraPosition:camera];
- }];
+ // Core Animation must be used to control the animation's duration
+ // See http://stackoverflow.com/a/15663039/171744
+ [CATransaction begin];
+ [CATransaction setAnimationDuration:duration/1000];
+ AIRGoogleMap *mapView = (AIRGoogleMap *)view;
+ GMSCameraPosition *camera = [AIRGoogleMap makeGMSCameraPositionFromMap:mapView andMKCoordinateRegion:region];
+ [mapView animateToCameraPosition:camera];
+ [CATransaction commit];
+ }
+ }];
+}
+
+RCT_EXPORT_METHOD(animateToCoordinate:(nonnull NSNumber *)reactTag
+ withRegion:(CLLocationCoordinate2D)latlng
+ withDuration:(CGFloat)duration)
+{
+ [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary *viewRegistry) {
+ id view = viewRegistry[reactTag];
+ if (![view isKindOfClass:[AIRGoogleMap class]]) {
+ RCTLogError(@"Invalid view returned from registry, expecting AIRGoogleMap, got: %@", view);
+ } else {
+ [CATransaction begin];
+ [CATransaction setAnimationDuration:duration/1000];
+ [(AIRGoogleMap *)view animateToLocation:latlng];
+ [CATransaction commit];
}
}];
}
diff --git a/lib/ios/AirMaps/AIRMap.h b/lib/ios/AirMaps/AIRMap.h
index 18c9a0bc0..4a88617e6 100644
--- a/lib/ios/AirMaps/AIRMap.h
+++ b/lib/ios/AirMaps/AIRMap.h
@@ -37,6 +37,8 @@ extern const CGFloat AIRMapZoomBoundBuffer;
@property (nonatomic, assign) UIEdgeInsets legalLabelInsets;
@property (nonatomic, strong) NSTimer *regionChangeObserveTimer;
@property (nonatomic, assign) MKCoordinateRegion initialRegion;
+@property (nonatomic, assign) CGFloat minZoomLevel;
+@property (nonatomic, assign) CGFloat maxZoomLevel;
@property (nonatomic, assign) CLLocationCoordinate2D pendingCenter;
@property (nonatomic, assign) MKCoordinateSpan pendingSpan;
diff --git a/lib/ios/AirMaps/AIRMapManager.h b/lib/ios/AirMaps/AIRMapManager.h
index cc9a8c75b..29df98bfc 100644
--- a/lib/ios/AirMaps/AIRMapManager.h
+++ b/lib/ios/AirMaps/AIRMapManager.h
@@ -8,7 +8,23 @@
*/
#import
+#import "AIRMap.h"
+
+#define MERCATOR_RADIUS 85445659.44705395
+#define MERCATOR_OFFSET 268435456
+#define MAX_GOOGLE_LEVELS 20
@interface AIRMapManager : RCTViewManager
+
+- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
+ zoomLevel:(double)zoomLevel
+ animated:(BOOL)animated
+ mapView:(AIRMap *)mapView;
+
+- (MKCoordinateRegion)coordinateRegionWithMapView:(AIRMap *)mapView
+ centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
+ andZoomLevel:(double)zoomLevel;
+- (double) zoomLevel:(AIRMap *)mapView;
+
@end
diff --git a/lib/ios/AirMaps/AIRMapManager.m b/lib/ios/AirMaps/AIRMapManager.m
index 619142bd6..b1e4298be 100644
--- a/lib/ios/AirMaps/AIRMapManager.m
+++ b/lib/ios/AirMaps/AIRMapManager.m
@@ -97,6 +97,9 @@ - (UIView *)view
RCT_EXPORT_VIEW_PROPERTY(onMarkerDragEnd, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onCalloutPress, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(initialRegion, MKCoordinateRegion)
+RCT_EXPORT_VIEW_PROPERTY(minZoomLevel, CGFloat)
+RCT_EXPORT_VIEW_PROPERTY(maxZoomLevel, CGFloat)
+
RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, AIRMap)
{
@@ -625,11 +628,19 @@ - (void)mapView:(AIRMap *)mapView regionWillChangeAnimated:(__unused BOOL)animat
- (void)mapView:(AIRMap *)mapView regionDidChangeAnimated:(__unused BOOL)animated
{
+ CGFloat zoomLevel = [self zoomLevel:mapView];
[mapView.regionChangeObserveTimer invalidate];
mapView.regionChangeObserveTimer = nil;
[self _regionChanged:mapView];
+ if (mapView.minZoomLevel && zoomLevel < mapView.minZoomLevel) {
+ [self setCenterCoordinate:[mapView centerCoordinate] zoomLevel:mapView.minZoomLevel animated:TRUE mapView:mapView];
+ }
+ else if (mapView.maxZoomLevel && zoomLevel > mapView.maxZoomLevel) {
+ [self setCenterCoordinate:[mapView centerCoordinate] zoomLevel:mapView.maxZoomLevel animated:TRUE mapView:mapView];
+ }
+
// Don't send region did change events until map has
// started rendering, as these won't represent the final location
if (mapView.hasStartedRendering) {
@@ -665,6 +676,7 @@ - (void)_regionChanged:(AIRMap *)mapView
BOOL needZoom = NO;
CGFloat newLongitudeDelta = 0.0f;
MKCoordinateRegion region = mapView.region;
+ CGFloat zoomLevel = [self zoomLevel:mapView];
// On iOS 7, it's possible that we observe invalid locations during initialization of the map.
// Filter those out.
if (!CLLocationCoordinate2DIsValid(region.center)) {
@@ -759,4 +771,161 @@ - (double)metersFromPixel:(NSUInteger)px atPoint:(CGPoint)pt forMap:(AIRMap *)ma
return MKMetersBetweenMapPoints(MKMapPointForCoordinate(coordA), MKMapPointForCoordinate(coordB));
}
++ (double)longitudeToPixelSpaceX:(double)longitude
+{
+ return round(MERCATOR_OFFSET + MERCATOR_RADIUS * longitude * M_PI / 180.0);
+}
+
++ (double)latitudeToPixelSpaceY:(double)latitude
+{
+ if (latitude == 90.0) {
+ return 0;
+ } else if (latitude == -90.0) {
+ return MERCATOR_OFFSET * 2;
+ } else {
+ return round(MERCATOR_OFFSET - MERCATOR_RADIUS * logf((1 + sinf(latitude * M_PI / 180.0)) / (1 - sinf(latitude * M_PI / 180.0))) / 2.0);
+ }
+}
+
++ (double)pixelSpaceXToLongitude:(double)pixelX
+{
+ return ((round(pixelX) - MERCATOR_OFFSET) / MERCATOR_RADIUS) * 180.0 / M_PI;
+}
+
++ (double)pixelSpaceYToLatitude:(double)pixelY
+{
+ return (M_PI / 2.0 - 2.0 * atan(exp((round(pixelY) - MERCATOR_OFFSET) / MERCATOR_RADIUS))) * 180.0 / M_PI;
+}
+
+#pragma mark -
+#pragma mark Helper methods
+
+- (MKCoordinateSpan)coordinateSpanWithMapView:(AIRMap *)mapView
+ centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
+ andZoomLevel:(double)zoomLevel
+{
+ // convert center coordiate to pixel space
+ double centerPixelX = [AIRMapManager longitudeToPixelSpaceX:centerCoordinate.longitude];
+ double centerPixelY = [AIRMapManager latitudeToPixelSpaceY:centerCoordinate.latitude];
+
+ // determine the scale value from the zoom level
+ double zoomExponent = 20 - zoomLevel;
+ double zoomScale = pow(2, zoomExponent);
+
+ // scale the map’s size in pixel space
+ CGSize mapSizeInPixels = mapView.bounds.size;
+ double scaledMapWidth = mapSizeInPixels.width * zoomScale;
+ double scaledMapHeight = mapSizeInPixels.height * zoomScale;
+
+ // figure out the position of the top-left pixel
+ double topLeftPixelX = centerPixelX - (scaledMapWidth / 2);
+ double topLeftPixelY = centerPixelY - (scaledMapHeight / 2);
+
+ // find delta between left and right longitudes
+ CLLocationDegrees minLng = [AIRMapManager pixelSpaceXToLongitude:topLeftPixelX];
+ CLLocationDegrees maxLng = [AIRMapManager pixelSpaceXToLongitude:topLeftPixelX + scaledMapWidth];
+ CLLocationDegrees longitudeDelta = maxLng - minLng;
+
+ // find delta between top and bottom latitudes
+ CLLocationDegrees minLat = [AIRMapManager pixelSpaceYToLatitude:topLeftPixelY];
+ CLLocationDegrees maxLat = [AIRMapManager pixelSpaceYToLatitude:topLeftPixelY + scaledMapHeight];
+ CLLocationDegrees latitudeDelta = -1 * (maxLat - minLat);
+
+ // create and return the lat/lng span
+ MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
+ return span;
+}
+
+#pragma mark -
+#pragma mark Public methods
+
+- (void)setCenterCoordinate:(CLLocationCoordinate2D)centerCoordinate
+ zoomLevel:(double)zoomLevel
+ animated:(BOOL)animated
+ mapView:(AIRMap *)mapView
+{
+ // clamp large numbers to 28
+ zoomLevel = MIN(zoomLevel, 28);
+
+ // use the zoom level to compute the region
+ MKCoordinateSpan span = [self coordinateSpanWithMapView:mapView centerCoordinate:centerCoordinate andZoomLevel:zoomLevel];
+ MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);
+
+ // set the region like normal
+ [mapView setRegion:region animated:animated];
+}
+
+//KMapView cannot display tiles that cross the pole (as these would involve wrapping the map from top to bottom, something that a Mercator projection just cannot do).
+-(MKCoordinateRegion)coordinateRegionWithMapView:(AIRMap *)mapView
+ centerCoordinate:(CLLocationCoordinate2D)centerCoordinate
+ andZoomLevel:(double)zoomLevel
+{
+ // clamp lat/long values to appropriate ranges
+ centerCoordinate.latitude = MIN(MAX(-90.0, centerCoordinate.latitude), 90.0);
+ centerCoordinate.longitude = fmod(centerCoordinate.longitude, 180.0);
+
+ // convert center coordiate to pixel space
+ double centerPixelX = [AIRMapManager longitudeToPixelSpaceX:centerCoordinate.longitude];
+ double centerPixelY = [AIRMapManager latitudeToPixelSpaceY:centerCoordinate.latitude];
+
+ // determine the scale value from the zoom level
+ double zoomExponent = 20 - zoomLevel;
+ double zoomScale = pow(2, zoomExponent);
+
+ // scale the map’s size in pixel space
+ CGSize mapSizeInPixels = mapView.bounds.size;
+ double scaledMapWidth = mapSizeInPixels.width * zoomScale;
+ double scaledMapHeight = mapSizeInPixels.height * zoomScale;
+
+ // figure out the position of the left pixel
+ double topLeftPixelX = centerPixelX - (scaledMapWidth / 2);
+
+ // find delta between left and right longitudes
+ CLLocationDegrees minLng = [AIRMapManager pixelSpaceXToLongitude:topLeftPixelX];
+ CLLocationDegrees maxLng = [AIRMapManager pixelSpaceXToLongitude:topLeftPixelX + scaledMapWidth];
+ CLLocationDegrees longitudeDelta = maxLng - minLng;
+
+ // if we’re at a pole then calculate the distance from the pole towards the equator
+ // as MKMapView doesn’t like drawing boxes over the poles
+ double topPixelY = centerPixelY - (scaledMapHeight / 2);
+ double bottomPixelY = centerPixelY + (scaledMapHeight / 2);
+ BOOL adjustedCenterPoint = NO;
+ if (topPixelY > MERCATOR_OFFSET * 2) {
+ topPixelY = centerPixelY - scaledMapHeight;
+ bottomPixelY = MERCATOR_OFFSET * 2;
+ adjustedCenterPoint = YES;
+ }
+
+ // find delta between top and bottom latitudes
+ CLLocationDegrees minLat = [AIRMapManager pixelSpaceYToLatitude:topPixelY];
+ CLLocationDegrees maxLat = [AIRMapManager pixelSpaceYToLatitude:bottomPixelY];
+ CLLocationDegrees latitudeDelta = -1 * (maxLat - minLat);
+
+ // create and return the lat/lng span
+ MKCoordinateSpan span = MKCoordinateSpanMake(latitudeDelta, longitudeDelta);
+ MKCoordinateRegion region = MKCoordinateRegionMake(centerCoordinate, span);
+ // once again, MKMapView doesn’t like drawing boxes over the poles
+ // so adjust the center coordinate to the center of the resulting region
+ if (adjustedCenterPoint) {
+ region.center.latitude = [AIRMapManager pixelSpaceYToLatitude:((bottomPixelY + topPixelY) / 2.0)];
+ }
+
+ return region;
+}
+
+- (double) zoomLevel:(AIRMap *)mapView {
+ MKCoordinateRegion region = mapView.region;
+
+ double centerPixelX = [AIRMapManager longitudeToPixelSpaceX: region.center.longitude];
+ double topLeftPixelX = [AIRMapManager longitudeToPixelSpaceX: region.center.longitude - region.span.longitudeDelta / 2];
+
+ double scaledMapWidth = (centerPixelX - topLeftPixelX) * 2;
+ CGSize mapSizeInPixels = mapView.bounds.size;
+ double zoomScale = scaledMapWidth / mapSizeInPixels.width;
+ double zoomExponent = log(zoomScale) / log(2);
+ double zoomLevel = 20 - zoomExponent;
+
+ return zoomLevel;
+}
+
@end
diff --git a/package.json b/package.json
index 772551c11..9ff2a7d83 100644
--- a/package.json
+++ b/package.json
@@ -3,7 +3,7 @@
"description": "React Native Mapview component for iOS + Android",
"main": "index.js",
"author": "Leland Richardson ",
- "version": "0.15.2",
+ "version": "0.15.3",
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"run:packager": "./node_modules/react-native/packager/packager.sh",
@@ -32,8 +32,9 @@
"mapkit"
],
"peerDependencies": {
- "react": ">=15.4.0",
- "react-native": ">=0.40"
+ "react": ">=15.4.0 || ^16.0.0-alpha",
+ "react-native": ">=0.40",
+ "prop-types": "^15.5.10"
},
"devDependencies": {
"babel-eslint": "^6.1.2",
@@ -48,8 +49,9 @@
"eslint-plugin-react": "^6.1.2",
"gitbook-cli": "^2.3.0",
"lodash": "^4.17.2",
- "react": "~15.4.1",
- "react-native": "^0.42.0"
+ "prop-types": "^15.5.10",
+ "react": "^16.0.0-alpha.12",
+ "react-native": "^0.45.1"
},
"rnpm": {
"android": {