diff --git a/.github/stale.yml b/.github/stale.yml
new file mode 100644
index 000000000..3b0f14a32
--- /dev/null
+++ b/.github/stale.yml
@@ -0,0 +1,17 @@
+# Number of days of inactivity before an issue becomes stale
+daysUntilStale: 60
+# Number of days of inactivity before a stale issue is closed
+daysUntilClose: 7
+# Issues with these labels will never be considered stale
+exemptLabels:
+ - pinned
+ - security
+# Label to use when marking an issue as stale
+staleLabel: stale
+# Comment to post when marking an issue as stale. Set to `false` to disable
+markComment: >
+ This issue has been automatically marked as stale because it has not had
+ recent activity. It will be closed if no further activity occurs. Thank you
+ for your contributions.
+# Comment to post when closing a stale issue. Set to `false` to disable
+closeComment: false
\ No newline at end of file
diff --git a/.github/workflows/flutter_ci.yml b/.github/workflows/flutter_ci.yml
index af062a63b..cf1a18f55 100644
--- a/.github/workflows/flutter_ci.yml
+++ b/.github/workflows/flutter_ci.yml
@@ -8,31 +8,73 @@ jobs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v1
- - uses: actions/setup-java@v1
- with:
- java-version: '12.x'
- - uses: subosito/flutter-action@v1
- - run: flutter pub get
- - name: Lint analysis
- run: cd example && flutter analyze
+ - uses: actions/checkout@v1
+ - uses: actions/setup-java@v1
+ with:
+ java-version: "12.x"
+ - uses: subosito/flutter-action@v1
+ with:
+ flutter-version: "2.10.5"
+ - run: flutter pub get
+ - name: Lint analysis
+ run: cd example && flutter analyze
+
+ check-dart-formatting:
+ name: "Check Dart formatting"
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v1
+ - uses: subosito/flutter-action@v1
+ - name: Check Dart formatting
+ run: dart format --set-exit-if-changed .
+
+ check-swift-formatting:
+ name: "Check Swift formatting"
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v1
+ - name: get SwiftFormat
+ run: ./install_formatting_tools.sh
+ - name: Check Swift formatting
+ run: ./swiftformat --swiftversion 4.2 --maxwidth 100 --lint ios
+
+ check-java-formatting:
+ name: "Check Java formatting"
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v1
+ - name: get google-java-format
+ run: ./install_formatting_tools.sh
+ - name: Check Java formatting
+ run: >
+ java
+ --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
+ --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
+ --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
+ --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
+ --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
+ -jar google-java-format-1.13.0-all-deps.jar --set-exit-if-changed -n $(find . -type f -name "*.java")
build-android:
environment: ANDROID_CI_DOWNLOADS_TOKEN
name: "Build Android apk"
runs-on: ubuntu-latest
-
steps:
- - uses: actions/checkout@v1
- - uses: actions/setup-java@v1
- with:
- java-version: '12.x'
- - uses: subosito/flutter-action@v1
- - run: flutter pub get
- - name: Build example APK
- run: cd example && flutter build apk
- env:
- SDK_REGISTRY_TOKEN: ${{ secrets.SDK_REGISTRY_ANDROID}}
+ - uses: actions/checkout@v1
+ - uses: actions/setup-java@v1
+ with:
+ java-version: "12.x"
+ - uses: subosito/flutter-action@v2
+ with:
+ flutter-version: "2.10.5"
+ - run: flutter pub get
+ - name: Build example APK
+ run: cd example && flutter build apk
+ env:
+ SDK_REGISTRY_TOKEN: ${{ secrets.SDK_REGISTRY_ANDROID}}
build-iOS:
environment: ANDROID_CI_DOWNLOADS_TOKEN
@@ -43,32 +85,33 @@ jobs:
- uses: actions/checkout@v1
- uses: actions/setup-java@v1
with:
- java-version: '12.x'
- - uses: subosito/flutter-action@v1
+ java-version: "12.x"
+ - uses: subosito/flutter-action@v2
+ with:
+ flutter-version: "2.10.5"
- run: flutter pub get
- name: build iOS package
run: |
echo "machine api.mapbox.com
login mapbox
password $SDK_REGISTRY_TOKEN" >> ~/.netrc
+ chmod 600 ~/.netrc
cd ./example
flutter build ios --release --no-codesign
env:
SDK_REGISTRY_TOKEN: ${{ secrets.SDK_REGISTRY_IOS}}
-
+
build-web:
name: "Build web"
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v1
- - uses: actions/setup-java@v1
- with:
- java-version: '12.x'
- - uses: subosito/flutter-action@v1
- with:
- channel: beta
- - run: flutter config --enable-web
- - run: flutter pub get
- - name: Build web
- run: cd example && flutter build web
+ - uses: actions/checkout@v1
+ - uses: actions/setup-java@v1
+ with:
+ java-version: "12.x"
+ - uses: subosito/flutter-action@v1
+ - run: flutter config --enable-web
+ - run: flutter pub get
+ - name: Build web
+ run: cd example && flutter build web
diff --git a/.gitignore b/.gitignore
index b7d74c826..e8639a336 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,11 +4,13 @@
*.log
*.pyc
*.swp
+*.cxx
.DS_Store
.atom/
.buildlog/
.history
.svn/
+.fvm/
# IntelliJ related
*.iml
@@ -98,10 +100,15 @@ unlinked_spec.ds
**/macos/Flutter/Flutter-Debug.xcconfig
**/macos/Flutter/Flutter-Release.xcconfig
**/macos/Flutter/Flutter-Profile.xcconfig
+__MACOSX/
# Coverage
coverage/
+# Binaries
+google-java-format-1.13.0-all-deps.jar
+swiftformat
+
# Symbols
app.*.symbols
@@ -112,3 +119,4 @@ app.*.symbols
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
!/dev/ci/**/Gemfile.lock
+
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f553615a2..dcc46455e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,89 @@
-## 0.12.0, April 12, 2020
+## 0.16.0, May 19, 2022
+* Fix type issues in query rendered features in rect [#862](https://github.com/flutter-mapbox-gl/maps/pull/862)
+* Annotation manager moved to dart [#779](https://github.com/flutter-mapbox-gl/maps/pull/779)
+* Add java formatting [#863](https://github.com/flutter-mapbox-gl/maps/pull/863)
+* Fix urls parsing [#868](https://github.com/flutter-mapbox-gl/maps/pull/868)
+* Fix for MissingPluginException when using downloadOfflineRegion [#864](https://github.com/flutter-mapbox-gl/maps/pull/864)
+* Fix issue with map disposal on web [#895](https://github.com/flutter-mapbox-gl/maps/pull/895)
+* Fix for rescale issues on web [#896](https://github.com/flutter-mapbox-gl/maps/pull/896)
+* Fix android build issues [#904](https://github.com/flutter-mapbox-gl/maps/pull/904)
+* Upgraded mapbox gl js to 2.7.0 [#889](https://github.com/flutter-mapbox-gl/maps/pull/889)
+* Add updateContentInsets on Android [#903](https://github.com/flutter-mapbox-gl/maps/pull/903)
+* Fix MapController's queryRendered* methods not considering layerIds [#870](https://github.com/flutter-mapbox-gl/maps/pull/870)
+* Adding function in annotation manager to remove multiple annotations [#931](https://github.com/flutter-mapbox-gl/maps/pull/931)
+* Update "Setting up" section of README [#918](https://github.com/flutter-mapbox-gl/maps/pull/918)
+* Add support for layer zoom limits [#934](https://github.com/flutter-mapbox-gl/maps/pull/934)
+* Add locationComponent#getLastLocation [#922](https://github.com/flutter-mapbox-gl/maps/pull/922)
+* Add and default to Hybrid composition on Android [#916](https://github.com/flutter-mapbox-gl/maps/pull/916)
+* Fix location puck getting hidden [#956](https://github.com/flutter-mapbox-gl/maps/pull/956)
+* Don't call locationComponent if it's null [#966](https://github.com/flutter-mapbox-gl/maps/pull/966)
+* Do nothing and correctly return if layer and source to remove are not there [](https://github.com/flutter-mapbox-gl/maps/pull/961)
+* Fixed LocationTracking issue delayed permissions [#958](https://github.com/flutter-mapbox-gl/maps/pull/958)
+* Fix for LocationComponent update issue [#969](https://github.com/flutter-mapbox-gl/maps/pull/969)
+* Features with non string ids will not update properly [#970](https://github.com/flutter-mapbox-gl/maps/pull/970)
+* Update added shapes by layer when setting a feature [#972](https://github.com/flutter-mapbox-gl/maps/pull/972)
+* Allows modifying http headers [#977](https://github.com/flutter-mapbox-gl/maps/pull/977)
+* Additional documentation [#986](https://github.com/flutter-mapbox-gl/maps/pull/986)
+* Disabled hybrid composition do to various issues [#992](https://github.com/flutter-mapbox-gl/maps/pull/992)
+* Implement layer filtering [#997](https://github.com/flutter-mapbox-gl/maps/pull/997)
+* Drag event types support added [#987](https://github.com/flutter-mapbox-gl/maps/pull/987)
+* Remove duplicated code [#1026](https://github.com/flutter-mapbox-gl/maps/pull/1026)
+* Support filtering on addLayer [#1024](https://github.com/flutter-mapbox-gl/maps/pull/1024)
+* Document layer zoom limits [#1028](https://github.com/flutter-mapbox-gl/maps/pull/1028)
+
+## 0.15.0, January 13, 2022
+* Callbacks added to onFeatureTapped will now also get the position (`Point`) and the location (`LatLng`) of the click passed when called [#798](https://github.com/flutter-mapbox-gl/maps/pull/798)
+* Fixed layer based feature selection [#765](https://github.com/flutter-mapbox-gl/maps/pull/765)
+* Implement the changePosition function for place_fill example [#778](https://github.com/flutter-mapbox-gl/maps/pull/778)
+* Invoke onPause method of MapView in onPause lifecycle [#782](https://github.com/flutter-mapbox-gl/maps/pull/782)
+* Remove layer before adding layer if layer is added in place example [#766](https://github.com/flutter-mapbox-gl/maps/pull/766)
+* Speed property is null when onUserLocationUpdated is called [#767](https://github.com/flutter-mapbox-gl/maps/pull/767)
+* Improve iOS OnStyleReady reliability [#775](https://github.com/flutter-mapbox-gl/maps/pull/775)
+* Handle line color and geometry [#776](https://github.com/flutter-mapbox-gl/maps/pull/776)
+* Fix web issues with style loaded, feature tap, add promoteId, pointer change issue [#785](https://github.com/flutter-mapbox-gl/maps/pull/785)
+* Fix more issues with style loading [#787](https://github.com/flutter-mapbox-gl/maps/pull/787)
+* Updated settings gradle to new version [#789](https://github.com/flutter-mapbox-gl/maps/pull/789)
+* Remove the callbacks in dispose of example click_annotations dart [#791](https://github.com/flutter-mapbox-gl/maps/pull/791)
+* Add check for Dart formatting [#803](https://github.com/flutter-mapbox-gl/maps/pull/803)
+* Add check for Swift formatting [#804](https://github.com/flutter-mapbox-gl/maps/pull/804)
+* Fixed race condition with map#waitForMap [#808](https://github.com/flutter-mapbox-gl/maps/pull/808)
+* Add option to not use annotations on android [#820](https://github.com/flutter-mapbox-gl/maps/pull/820)
+* Add linepattern in line.dart [#825](https://github.com/flutter-mapbox-gl/maps/pull/825)
+* Respect native scale when adding symbols on iOS [#835](https://github.com/flutter-mapbox-gl/maps/pull/835)
+* Remove unnecessary print of style height and width [#847](https://github.com/flutter-mapbox-gl/maps/pull/847)
+* Android embedding fixes - migrate to maven [#852](https://github.com/flutter-mapbox-gl/maps/pull/852)
+* Full style source support [#797](https://github.com/flutter-mapbox-gl/maps/pull/797)
+* Gesture fixes [#851](https://github.com/flutter-mapbox-gl/maps/pull/851)
+* Fixed issue with return type of remove source on web [#854](https://github.com/flutter-mapbox-gl/maps/pull/854)
+
+## 0.14.0, November 13, 2021
+* Remove memory leaks by disposing internal components [#706](https://github.com/tobrun/flutter-mapbox-gl/pull/706)
+* Improved annotation click order [#748](https://github.com/tobrun/flutter-mapbox-gl/pull/748)
+* Add support for Layers, properties and expressions backed by GeoJsonSource [#723](https://github.com/tobrun/flutter-mapbox-gl/pull/723)
+* Add attribution button gravity, position normally [#731](https://github.com/tobrun/flutter-mapbox-gl/pull/731)
+* Add documentation for setMapLanguage [#740](https://github.com/tobrun/flutter-mapbox-gl/pull/740)
+* Make sure onStyleLoaded callback is invoked when map is loaded and ready [#690](https://github.com/tobrun/flutter-mapbox-gl/pull/690)
+* Enable onMapIdle callback for android [#729](https://github.com/tobrun/flutter-mapbox-gl/pull/729)
+* Set attribution margin to use left margin [#714](https://github.com/tobrun/flutter-mapbox-gl/pull/714)
+* Getting the ACCESS_TOKEN from env [#726](https://github.com/tobrun/flutter-mapbox-gl/pull/726)
+* Fixed crashes with offline manager [#724](https://github.com/tobrun/flutter-mapbox-gl/pull/724)
+* Add divider for example list [#712](https://github.com/tobrun/flutter-mapbox-gl/pull/712)
+* Fix respecting annotationConsumeTapEvents on iOS [#716](https://github.com/tobrun/flutter-mapbox-gl/pull/716)
+* Add getSymbolLatLng and getLineLatLngs for web [#720](https://github.com/tobrun/flutter-mapbox-gl/pull/720)
+* Fix typo in downloads token property name according to docs [#721](https://github.com/tobrun/flutter-mapbox-gl/pull/721)
+* Remove MapboxGlPlatform.getInstance [#710](https://github.com/tobrun/flutter-mapbox-gl/pull/710)
+
+## 0.13.0, October 21, 2021
+* Migrate to null-safety [#607](https://github.com/tobrun/flutter-mapbox-gl/pull/607)
+* Add missing removeLines removeCircles and removeFills [#622](https://github.com/tobrun/flutter-mapbox-gl/pull/622)
+* Add support for colors with alpha [#561](https://github.com/tobrun/flutter-mapbox-gl/pull/561)
+* Support override of attribution click action (iOS) [#605](https://github.com/tobrun/flutter-mapbox-gl/pull/605)
+* Update to Mapbox-Android-SDK 9.6.2 [#674](https://github.com/tobrun/flutter-mapbox-gl/pull/674)
+* Fix Warning: Operand of null-aware operation '!' has type 'Locale' which excludes null [#676](https://github.com/tobrun/flutter-mapbox-gl/pull/676)
+* Make build work with instructions in docs (android) [#698](https://github.com/tobrun/flutter-mapbox-gl/pull/698)
+* Fix requestMyLocationLatLng in the platform interface [#697](https://github.com/tobrun/flutter-mapbox-gl/pull/697)
+
+## 0.12.0, April 12, 2021
* Update to Mapbox-Android-SDK 9.6.0 [#489](https://github.com/tobrun/flutter-mapbox-gl/pull/489)
* Update to Mapbox-iOS-SDK 6.3.0 [#513](https://github.com/tobrun/flutter-mapbox-gl/pull/513)
* Batch creation/removal for circles, fills and lines [#576](https://github.com/tobrun/flutter-mapbox-gl/pull/576)
@@ -8,7 +93,7 @@
* Emit onTap only for the feature above the others [#589](https://github.com/tobrun/flutter-mapbox-gl/pull/589)
* Add annotationOrder to web [#588](https://github.com/tobrun/flutter-mapbox-gl/pull/588)
-## 0.11.0, March 30, 2020
+## 0.11.0, March 30, 2021
* Fixed issues caused by new android API [#544](https://github.com/tobrun/flutter-mapbox-gl/pull/544)
* Add option to set maximum offline tile count [#549](https://github.com/tobrun/flutter-mapbox-gl/pull/549)
* Fixed web build failure due to http package upgrade [#550](https://github.com/tobrun/flutter-mapbox-gl/pull/550)
@@ -21,7 +106,7 @@
* Define which annotations consume the tap events [#575](https://github.com/tobrun/flutter-mapbox-gl/pull/575)
* Remove failed offline region downloads [#583](https://github.com/tobrun/flutter-mapbox-gl/pull/583)
-## 0.10.0, February 12, 2020
+## 0.10.0, February 12, 2021
* Merge offline regions [#532](https://github.com/tobrun/flutter-mapbox-gl/pull/532)
* Update offline region metadata [#530](https://github.com/tobrun/flutter-mapbox-gl/pull/530)
* Added web support for fills [#501](https://github.com/tobrun/flutter-mapbox-gl/pull/501)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index a160f0ad8..235f7c060 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -2,14 +2,11 @@
We welcome contributions to this repository. Please follow these steps if you're interested in making contributions:
-1. Please familiarize yourself with the [process of running the example app](https://github.com/tobrun/flutter-mapbox-gl#running-the-example-app) and [add a Mapbox access token](https://github.com/tobrun/flutter-mapbox-gl#adding-a-mapbox-access-token) as described in the Readme.
-2. Ensure that existing [pull requests](https://github.com/tobrun/flutter-mapbox-gl/pulls) and [issues](https://github.com/tobrun/flutter-mapbox-gl/issues) don’t already cover your contribution or question.
+- Please familiarize yourself with the process of running the example app and adding Mapbox access tokens as described in the Readme.
-3. Create a new branch that will contain your contributed code. Along with your contribution you should also adapt the example app to showcase any new features or APIs you have developed. This also makes testing your contribution much easier. Eventually create a pull request once you're done making changes.
+- Ensure that existing [pull requests](https://github.com/tobrun/flutter-mapbox-gl/pulls) and [issues](https://github.com/tobrun/flutter-mapbox-gl/issues) don’t already cover your contributions or questions.
-4. If there are any changes that developers should be aware of, please update the [changelog](https://github.com/tobrun/flutter-mapbox-gl/blob/master/CHANGELOG.md) once your pull request has been merged to the `master` branch.
+- Create a new branch that will contain your contributed code. Along with your contribution you should also adapt the example app to showcase any new features or APIs you have developed. This also makes testing your contribution much easier. In an ideal case, you also make your contribution cross platform but this isn't a true requirement. Eventually create a pull request once you're done making changes.
# Code of conduct
-Everyone is invited to participate in Mapbox’s open source projects and public discussions: we want to create a welcoming and friendly environment. Harassment of participants or other unethical and unprofessional behavior will not be tolerated in our spaces. The [Contributor Covenant](http://contributor-covenant.org) applies to all projects under the Mapbox organization and we ask that you please read [the full text](http://contributor-covenant.org/version/1/2/0/).
-
-You can learn more about our open source philosophy on [mapbox.com](https://www.mapbox.com/about/open/).
+Everyone is invited to participate in open source projects and public discussions: we want to create a welcoming and friendly environment. Harassment of participants or other unethical and unprofessional behavior will not be tolerated in this repository spaces. The [Contributor Covenant](http://contributor-covenant.org) applies to this project and we ask that you please read [the full text](http://contributor-covenant.org/version/1/2/0/).
diff --git a/LICENSE b/LICENSE
index a4c4948f4..5b31bdb92 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-flutter-mapbox-gl copyright (c) 2018, Mapbox.
+flutter-mapbox-gl copyright (c) 2021,
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000..71ae0f508
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,16 @@
+format:
+ java \
+ --add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
+ --add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
+ --add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
+ --add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
+ --add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED \
+ -jar google-java-format-1.13.0-all-deps.jar -r $(shell find . -type f -name "*.java")
+ flutter format .
+ ./swiftformat --swiftversion 4.2 --maxwidth 100 ios
+
+install_formatting:
+ ./install_formatting_tools.sh
+
+codegen:
+ dart scripts/lib/generate.dart
\ No newline at end of file
diff --git a/README.md b/README.md
index 1c4075d17..112b4c2fd 100644
--- a/README.md
+++ b/README.md
@@ -1,60 +1,120 @@
# Flutter Mapbox GL
-> **Please note that this project is community driven and is not an official Mapbox product.** We welcome [feedback](https://github.com/tobrun/flutter-mapbox-gl/issues) and contributions.
+> **Please note that this project is community driven and is not an official Mapbox product.**
+>
+> We welcome [feedback](https://github.com/tobrun/flutter-mapbox-gl/issues) and contributions.
+
+
+## Table of contents
+
+- [Flutter Mapbox GL](#flutter-mapbox-gl)
+ - [Table of contents](#table-of-contents)
+ - [Introduction](#introduction)
+ - [Setting up](#setting-up)
+ - [Mobile](#mobile)
+ - [Secret Mapbox access token](#secret-mapbox-access-token)
+ - [Web](#web)
+ - [All platforms](#all-platforms)
+ - [Public Mapbox access token](#public-mapbox-access-token)
+ - [Supported API](#supported-api)
+ - [Map Styles](#map-styles)
+ - [Offline Sideloading](#offline-sideloading)
+ - [Downloading Offline Regions](#downloading-offline-regions)
+ - [Create a static map snapshot](#create-a-static-map-snapshot)
+ - [Location features](#location-features)
+ - [Android](#android)
+ - [iOS](#ios)
+ - [Running the example code](#running-the-example-code)
+ - [Contributing](#contributing)
+
+## Introduction
This Flutter plugin allows to show embedded interactive and customizable vector maps inside a Flutter widget. For the Android and iOS integration, we use [mapbox-gl-native](https://github.com/mapbox/mapbox-gl-native). For web, we rely on [mapbox-gl-js](https://github.com/mapbox/mapbox-gl-js). This project only supports a subset of the API exposed by these libraries.

-## Running the example app
+## Setting up
-- Install [Flutter](https://flutter.io/get-started/) and validate its installation with `flutter doctor`
-- Clone the repository with `git clone git@github.com:tobrun/flutter-mapbox-gl.git`
-- Add a public Mapbox access token to the example app (see next section)
-- Add a secret Mapbox access token for downloading the SDK
-- Connect a mobile device or start an emulator, simulator or chrome
-- Locate the id of a the device with `flutter devices`
-- Run the app with `cd flutter_mapbox/example && flutter packages get && flutter run -d {device_id}`
+This package is available on [pub.dev](https://pub.dev/packages/mapbox_gl).
-## Adding a Mapbox Access Token
+Get it by running the following command:
-This project uses Mapbox vector tiles, which requires a Mapbox account and a Mapbox access token. Obtain a free access token on [your Mapbox account page](https://www.mapbox.com/account/access-tokens/).
-> **Even if you do not use Mapbox vector tiles but vector tiles from a different source (like self-hosted tiles) with this plugin, you will need to specify any non-empty string as Access Token as explained below!**
+```
+flutter pub add mapbox_gl
+```
+### Mobile
-The **recommended** way to provide your access token is through the `MapboxMap` constructor's `accessToken` parameter, which is available starting from the v0.8 release. Note that you should always use the same token throughout your entire app.
+#### Secret Mapbox access token
-An alternative method to provide access tokens that was required until the v0.7 release is described in [this wiki article](https://github.com/tobrun/flutter-mapbox-gl/wiki/Mapbox-access-tokens).
+A secret access token with the `Downloads: Read` scope is required for the underlying Mapbox SDKs to be downloaded.
+Information on setting it up is available in the Mapbox documentation:
+[Android](https://docs.mapbox.com/android/maps/guides/install/),
+[iOS](https://docs.mapbox.com/ios/maps/guides/install/).
-### SDK Download token
+If the properly configured token is not present,
+the build process fails with one the following errors *(for Android/iOS respectively)*:
-You must also [configure a secret access token having the Download: read
-scope][https://docs.mapbox.com/ios/maps/guides/install/]. If this configuration
-is not present, an error like the following appears during the iOS build.
+```
+* What went wrong:
+A problem occurred evaluating project ':mapbox_gl'.
+> SDK Registry token is null. See README.md for more information.
+```
```
[!] Error installing Mapbox-iOS-SDK
curl: (22) The requested URL returned error: 401 Unauthorized
```
-## Avoid Android UnsatisfiedLinkError
+### Web
-Update buildTypes in `android\app\build.gradle`
+Include the JavaScript and CSS files in the `` of your `index.html` file:
-```gradle
-buildTypes {
- release {
- // other configs
- ndk {
- abiFilters 'armeabi-v7a','arm64-v8a','x86_64', 'x86'
- }
+```
+
+
+
+
```
-## Using the SDK in your project
+*Note: Look for latest version in [Mapbox GL JS documentation](https://docs.mapbox.com/mapbox-gl-js/guides/).*
+
+### All platforms
+
+#### Public Mapbox access token
-This project is available on [pub.dev](https://pub.dev/packages/mapbox_gl), follow the [instructions](https://flutter.dev/docs/development/packages-and-plugins/using-packages#adding-a-package-dependency-to-an-app) to integrate a package into your flutter application. For platform specific integration, use the flutter application under the example folder as reference.
+A public access token must be provided to a MapboxMap widget for retrieving styles and resources.
+While you can hardcode it directly into source files,
+it's good practise to retrieve access tokens from some external source
+(e.g. a config file or an environment variable).
+The example app uses the following technique:
+
+The access token is passed via the command line arguments when either building
+
+```
+flutter build --dart-define ACCESS_TOKEN=YOUR_TOKEN_HERE
+```
+
+or running the application
+
+```
+flutter run --dart-define ACCESS_TOKEN=YOUR_TOKEN_HERE
+```
+
+Then it's retrieved in Dart:
+```
+MapboxMap(
+ ...
+ accessToken: const String.fromEnvironment("ACCESS_TOKEN"),
+ ...
+)
+```
## Supported API
@@ -64,10 +124,24 @@ This project is available on [pub.dev](https://pub.dev/packages/mapbox_gl), foll
| Camera | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| Gesture | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| User Location | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| Symbol | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| Circle | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| Line | :white_check_mark: | :white_check_mark: | :white_check_mark: |
-| Fill | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Style DSL | :x: | :x: | :x: |
+| Raster Layer | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Symbol Layer | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Circle Layer | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Line Layer | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Fill Layer | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Fill Extrusion Layer | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Hillshade Layer | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Heatmap Layer | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Vector Source | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Raster Source | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| GeoJson Source | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Image Source | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Expressions | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Symbol Annotation | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Circle Annotation | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Line Annotation | :white_check_mark: | :white_check_mark: | :white_check_mark: |
+| Fill Annotation | :white_check_mark: | :white_check_mark: | :white_check_mark: |
## Map Styles
@@ -80,7 +154,7 @@ Map styles can be supplied by setting the `styleString` in the `MapOptions`. The
## Offline Sideloading
-Support for offline maps is available by *"side loading"* the required map tiles and including them in your `assets` folder.
+Support for offline maps is available by side loading the required map tiles and including them in your `assets` folder.
* Create your tiles package by following the guide available [here](https://docs.mapbox.com/ios/maps/overview/offline/).
@@ -134,7 +208,25 @@ An offline region is a defined region of a map that is available for use in cond
downloadOfflineRegionStream(offlineRegion, onEvent);
```
+## Create a static map snapshot
+
+The snapshotManager generates static raster images of the map.
+Each snapshot image depicts a portion of a map defined by an SnapshotOptions object you provide.
+* Call `takeSnapshot` with predefined `SnapshotOptions`
+
+```
+ final renderBox = mapKey.currentContext?.findRenderObject() as RenderBox;
+
+ final snapshotOptions = SnapshotOptions(
+ width: renderBox.size.width,
+ height: renderBox.size.height,
+ writeToDisk: true,
+ withLogo: false,
+ );
+
+ final uri = await mapController?.takeSnapshot(snapshotOptions);
+```
## Location features
### Android
@@ -158,19 +250,14 @@ xml ...
[Your explanation here]
```
-Mapbox [recommends](https://docs.mapbox.com/help/tutorials/first-steps-ios-sdk/#display-the-users-location) the explanation "Shows your location on the map and helps improve the map".
-
-## Documentation
-
-This README file currently houses all of the documentation for this Flutter project. Please visit [mapbox.com/android-docs](https://www.mapbox.com/android-docs/) if you'd like more information about the Mapbox Maps SDK for Android and [mapbox.com/ios-sdk](https://www.mapbox.com/ios-sdk/) for more information about the Mapbox Maps SDK for iOS.
-
-## Getting Help
+[Recommended](https://docs.mapbox.com/help/tutorials/first-steps-ios-sdk/#display-the-users-location) explanation about "Shows your location on the map and helps improve the map".
-- **Need help with your code?**: Look for previous questions on the [#mapbox tag](https://stackoverflow.com/questions/tagged/mapbox+flutter) — or [ask a new question](https://stackoverflow.com/questions/tagged/mapbox+android).
-- **Have a bug to report?** [Open an issue](https://github.com/tobrun/flutter-mapbox-gl/issues/new). If possible, include a full log and information which shows the issue.
-- **Have a feature request?** [Open an issue](https://github.com/tobrun/flutter-mapbox-gl/issues/new). Tell us what the feature should do and why you want the feature.
+## Flutter 3.x.x issues and experimental workarounds
+Since Flutter 3.x.x was introduced, it exposed some race conditions resulting in occasional crashes upon map disposal. The parameter `useDelayedDisposal` was introduced as a workaround for this issue until Flutter and/or Mapbox fix this issue properly. Use with caution - this is not yet production ready since several users still report crashes after using this workaround.
+## Running the example code
+See the [documentation about this topic](doc/RUNNING_EXAMPLE_CODE.md)
## Contributing
-We welcome contributions to this repository! If you're interested in helping build this Mapbox/Flutter integration, please read [the contribution guide](https://github.com/tobrun/flutter-mapbox-gl/blob/master/CONTRIBUTING.md) to learn how to get started.
+We welcome contributions to this repository! If you're interested in helping build this Mapbox-Flutter integration, please read [the contribution guide](https://github.com/tobrun/flutter-mapbox-gl/blob/master/CONTRIBUTING.md) to learn how to get started.
diff --git a/RELEASE.md b/RELEASE.md
index 2fb3ffff1..488c2d8f7 100644
--- a/RELEASE.md
+++ b/RELEASE.md
@@ -2,20 +2,28 @@
This document describes the steps needed to make a release:
+### Update Changelog
+
For each supported library:
- `mapbox_gl_platform_interface`
- `mapbox_gl_web`
- `flutter-mapbox-gl`
-Perform the following actions:
- - Update `CHANGELOG.md` with the commits associated since previous release.
- - Update library version in `pubspec.yaml`
+Update the changelog by listing the commits that occurred for that given library.
+Starting with `flutter-mapbox-gl` allows you to capture them all and be more granular
+when updating the other libraries. Once the CHANGELOG.md's are updated, make a PR
+and merge to master.
+
+### Release libraries
+
+#### Release `mapbox_gl_platform_interface`
+
+Update library version in `mapbox_gl_platform_interface/pubspec.yaml` and run `flutter pub publish`.
+
+#### Release `mapbox_gl_web`
-Publish `mapbox_gl_platform_interface`, `mapbox_gl_web` and `flutter-mapbox-gl` after eachother with:
- - `flutter pub publish`
+Update library version in `mapbox_gl_web/pubspec.yaml` in `mapbox_gl_platform_interface`,
-Before publishgin in `mapbox_gl_web` update the version of the `mapbox_gl_platform_interface`
-Repeat this action for `flutter-mapbox-gl` for both dependencies:
```
Replace:
@@ -33,4 +41,13 @@ dependency_overrides:
path: ../mapbox_gl_platform_interface
```
-Before being able to publish `flutter-mapbox-gl`, you will have to PR and merge changelog changes.
\ No newline at end of file
+and run `flutter pub publish` in `mapbox_gl_web`.
+
+#### Release `flutter-mapbox-gl`
+
+Update library version in `pubspec.yaml`, replace both web as platform interface conform to above and run `flutter pub publish` from root of project.
+
+### Tag Release
+
+Once the PR that updates version numbers is merged, create a release for that version number
+with the contents of the root CHANGELOG.md.
\ No newline at end of file
diff --git a/android/build.gradle b/android/build.gradle
index e6b13d711..39bacb48e 100644
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -4,22 +4,21 @@ version '1.0-SNAPSHOT'
buildscript {
repositories {
google()
- jcenter()
+ mavenCentral()
}
dependencies {
- classpath 'com.android.tools.build:gradle:4.1.1'
+ classpath 'com.android.tools.build:gradle:4.2.0'
}
}
rootProject.allprojects {
- def token = System.getenv('SDK_REGISTRY_TOKEN')
+ def token = System.getenv('SDK_REGISTRY_TOKEN') ?: project.properties['MAPBOX_DOWNLOADS_TOKEN']
if (token == null || token.empty) {
throw new Exception("SDK Registry token is null. See README.md for more information.")
}
repositories {
google()
- jcenter()
mavenCentral()
maven {
url 'https://api.mapbox.com/downloads/v2/releases/maven'
@@ -37,7 +36,9 @@ rootProject.allprojects {
apply plugin: 'com.android.library'
android {
- compileSdkVersion 29
+ namespace "com.mapbox.mapboxgl"
+ compileSdkVersion 31
+ ndkVersion "20.1.5948944"
defaultConfig {
minSdkVersion 20
@@ -52,10 +53,12 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
dependencies {
- implementation "com.mapbox.mapboxsdk:mapbox-android-sdk:9.6.0"
+ implementation "com.mapbox.mapboxsdk:mapbox-android-sdk:9.6.2"
implementation "com.mapbox.mapboxsdk:mapbox-android-plugin-annotation-v9:0.9.0"
implementation "com.mapbox.mapboxsdk:mapbox-android-plugin-localization-v9:0.12.0"
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-offline-v9:0.7.0'
+ implementation 'com.squareup.okhttp3:okhttp:4.9.0'
+ implementation 'com.mapbox.mapboxsdk:mapbox-sdk-turf:5.1.0'
}
compileOptions {
sourceCompatibility 1.8
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 000000000..8428c0be2
--- /dev/null
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.1-all.zip
\ No newline at end of file
diff --git a/android/src/main/java/com/mapbox/mapboxgl/BitmapUtils.java b/android/src/main/java/com/mapbox/mapboxgl/BitmapUtils.java
new file mode 100644
index 000000000..c91044e51
--- /dev/null
+++ b/android/src/main/java/com/mapbox/mapboxgl/BitmapUtils.java
@@ -0,0 +1,57 @@
+package com.mapbox.mapboxgl;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.net.Uri;
+import android.util.Base64;
+import android.util.Log;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/** Created by nickitaliano on 10/9/17. */
+public class BitmapUtils {
+ private static final String LOG_TAG = "BitmapUtils";
+
+ public static String createTempFile(Context context, Bitmap bitmap) {
+ File tempFile = null;
+ FileOutputStream outputStream = null;
+
+ try {
+ tempFile = File.createTempFile(LOG_TAG, ".jpeg", context.getCacheDir());
+ outputStream = new FileOutputStream(tempFile);
+ } catch (IOException e) {
+ Log.w(LOG_TAG, e.getLocalizedMessage());
+ }
+
+ if (tempFile == null) {
+ return null;
+ }
+
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
+ closeSnapshotOutputStream(outputStream);
+ return Uri.fromFile(tempFile).toString();
+ }
+
+ public static String createBase64(Bitmap bitmap) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
+ byte[] bitmapBytes = outputStream.toByteArray();
+ closeSnapshotOutputStream(outputStream);
+ String base64Prefix = "data:image/jpeg;base64,";
+ return base64Prefix + Base64.encodeToString(bitmapBytes, Base64.NO_WRAP);
+ }
+
+ private static void closeSnapshotOutputStream(OutputStream outputStream) {
+ if (outputStream == null) {
+ return;
+ }
+ try {
+ outputStream.close();
+ } catch (IOException e) {
+ Log.w(LOG_TAG, e.getLocalizedMessage());
+ }
+ }
+}
diff --git a/android/src/main/java/com/mapbox/mapboxgl/CircleBuilder.java b/android/src/main/java/com/mapbox/mapboxgl/CircleBuilder.java
deleted file mode 100644
index db7accf56..000000000
--- a/android/src/main/java/com/mapbox/mapboxgl/CircleBuilder.java
+++ /dev/null
@@ -1,76 +0,0 @@
-// This file is generated.
-
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.mapbox.mapboxgl;
-
-import com.mapbox.geojson.Point;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.plugins.annotation.Circle;
-import com.mapbox.mapboxsdk.plugins.annotation.CircleManager;
-import com.mapbox.mapboxsdk.plugins.annotation.CircleOptions;
-
-class CircleBuilder implements CircleOptionsSink {
- private final CircleManager circleManager;
- private final CircleOptions circleOptions;
-
- CircleBuilder(CircleManager circleManager) {
- this.circleManager = circleManager;
- this.circleOptions = new CircleOptions();
- }
-
- public CircleOptions getCircleOptions(){
- return this.circleOptions;
- }
-
- Circle build() {
- return circleManager.create(circleOptions);
- }
-
- @Override
- public void setCircleRadius(float circleRadius) {
- circleOptions.withCircleRadius(circleRadius);
- }
-
- @Override
- public void setCircleColor(String circleColor) {
- circleOptions.withCircleColor(circleColor);
- }
-
- @Override
- public void setCircleBlur(float circleBlur) {
- circleOptions.withCircleBlur(circleBlur);
- }
-
- @Override
- public void setCircleOpacity(float circleOpacity) {
- circleOptions.withCircleOpacity(circleOpacity);
- }
-
- @Override
- public void setCircleStrokeWidth(float circleStrokeWidth) {
- circleOptions.withCircleStrokeWidth(circleStrokeWidth);
- }
-
- @Override
- public void setCircleStrokeColor(String circleStrokeColor) {
- circleOptions.withCircleStrokeColor(circleStrokeColor);
- }
-
- @Override
- public void setCircleStrokeOpacity(float circleStrokeOpacity) {
- circleOptions.withCircleStrokeOpacity(circleStrokeOpacity);
- }
-
- @Override
- public void setGeometry(LatLng geometry) {
- circleOptions.withGeometry(Point.fromLngLat(geometry.getLongitude(), geometry.getLatitude()));
- }
-
- @Override
- public void setDraggable(boolean draggable) {
- circleOptions.withDraggable(draggable);
- }
-}
\ No newline at end of file
diff --git a/android/src/main/java/com/mapbox/mapboxgl/CircleController.java b/android/src/main/java/com/mapbox/mapboxgl/CircleController.java
deleted file mode 100644
index 76860ea6f..000000000
--- a/android/src/main/java/com/mapbox/mapboxgl/CircleController.java
+++ /dev/null
@@ -1,96 +0,0 @@
-// This file is generated.
-
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.mapbox.mapboxgl;
-
-import android.graphics.Color;
-import com.mapbox.geojson.Point;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.plugins.annotation.Circle;
-import com.mapbox.mapboxsdk.plugins.annotation.CircleManager;
-
-/** Controller of a single Circle on the map. */
-class CircleController implements CircleOptionsSink {
- private final Circle circle;
- private final OnCircleTappedListener onTappedListener;
- private boolean consumeTapEvents;
-
- CircleController(Circle circle, boolean consumeTapEvents, OnCircleTappedListener onTappedListener) {
- this.circle = circle;
- this.consumeTapEvents = consumeTapEvents;
- this.onTappedListener = onTappedListener;
- }
-
- public Circle getCircle(){
- return this.circle;
- }
-
- boolean onTap() {
- if (onTappedListener != null) {
- onTappedListener.onCircleTapped(circle);
- }
- return consumeTapEvents;
- }
-
- void remove(CircleManager circleManager) {
- circleManager.delete(circle);
- }
-
- @Override
- public void setCircleRadius(float circleRadius) {
- circle.setCircleRadius(circleRadius);
- }
-
- @Override
- public void setCircleColor(String circleColor) {
- circle.setCircleColor(Color.parseColor(circleColor));
- }
-
- @Override
- public void setCircleBlur(float circleBlur) {
- circle.setCircleBlur(circleBlur);
- }
-
- @Override
- public void setCircleOpacity(float circleOpacity) {
- circle.setCircleOpacity(circleOpacity);
- }
-
- @Override
- public void setCircleStrokeWidth(float circleStrokeWidth) {
- circle.setCircleStrokeWidth(circleStrokeWidth);
- }
-
- @Override
- public void setCircleStrokeColor(String circleStrokeColor) {
- circle.setCircleStrokeColor(Color.parseColor(circleStrokeColor));
- }
-
- @Override
- public void setCircleStrokeOpacity(float circleStrokeOpacity) {
- circle.setCircleStrokeOpacity(circleStrokeOpacity);
- }
-
- @Override
- public void setGeometry(LatLng geometry) {
- circle.setGeometry(Point.fromLngLat(geometry.getLongitude(), geometry.getLatitude()));
- }
-
- public LatLng getGeometry() {
- Point point = circle.getGeometry();
- return new LatLng(point.latitude(), point.longitude());
- }
-
- @Override
- public void setDraggable(boolean draggable) {
- circle.setDraggable(draggable);
- }
-
- public void update(CircleManager circleManager) {
- circleManager.update(circle);
- }
-
-}
diff --git a/android/src/main/java/com/mapbox/mapboxgl/CircleOptionsSink.java b/android/src/main/java/com/mapbox/mapboxgl/CircleOptionsSink.java
deleted file mode 100644
index 80bd8ea04..000000000
--- a/android/src/main/java/com/mapbox/mapboxgl/CircleOptionsSink.java
+++ /dev/null
@@ -1,31 +0,0 @@
-// This file is generated.
-
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.mapbox.mapboxgl;
-
-import com.mapbox.mapboxsdk.geometry.LatLng;
-
-/** Receiver of Circle configuration options. */
-interface CircleOptionsSink {
-
- void setCircleRadius(float circleRadius);
-
- void setCircleColor(String circleColor);
-
- void setCircleBlur(float circleBlur);
-
- void setCircleOpacity(float circleOpacity);
-
- void setCircleStrokeWidth(float circleStrokeWidth);
-
- void setCircleStrokeColor(String circleStrokeColor);
-
- void setCircleStrokeOpacity(float circleStrokeOpacity);
-
- void setGeometry(LatLng geometry);
-
- void setDraggable(boolean draggable);
-}
diff --git a/android/src/main/java/com/mapbox/mapboxgl/Convert.java b/android/src/main/java/com/mapbox/mapboxgl/Convert.java
index ca22c4b54..f22b9d068 100644
--- a/android/src/main/java/com/mapbox/mapboxgl/Convert.java
+++ b/android/src/main/java/com/mapbox/mapboxgl/Convert.java
@@ -4,52 +4,28 @@
package com.mapbox.mapboxgl;
+import android.content.Context;
import android.graphics.Point;
+import android.util.DisplayMetrics;
import com.mapbox.geojson.Polygon;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdate;
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
-import com.mapbox.mapboxsdk.log.Logger;
import com.mapbox.mapboxsdk.maps.MapboxMap;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-/**
- * Conversions between JSON-like values and MapboxMaps data types.
- */
+/** Conversions between JSON-like values and MapboxMaps data types. */
class Convert {
- private final static String TAG = "Convert";
-
-// private static BitmapDescriptor toBitmapDescriptor(Object o) {
-// final List> data = toList(o);
-// switch (toString(data.get(0))) {
-// case "defaultMarker":
-// if (data.size() == 1) {
-// return BitmapDescriptorFactory.defaultMarker();
-// } else {
-// return BitmapDescriptorFactory.defaultMarker(toFloat(data.get(1)));
-// }
-// case "fromAsset":
-// if (data.size() == 2) {
-// return BitmapDescriptorFactory.fromAsset(
-// FlutterMain.getLookupKeyForAsset(toString(data.get(1))));
-// } else {
-// return BitmapDescriptorFactory.fromAsset(
-// FlutterMain.getLookupKeyForAsset(toString(data.get(1)), toString(data.get(2))));
-// }
-// default:
-// throw new IllegalArgumentException("Cannot interpret " + o + " as BitmapDescriptor");
-// }
-// }
+ private static final String TAG = "Convert";
- private static boolean toBoolean(Object o) {
+ static boolean toBoolean(Object o) {
return (Boolean) o;
}
@@ -63,19 +39,6 @@ static CameraPosition toCameraPosition(Object o) {
return builder.build();
}
- static List toAnnotationOrder(Object o) {
- final List> data = toList(o);
- List annotations = new ArrayList();
- for (int index = 0; index < data.size(); index++) {
- annotations.add(toString(data.get(index)));
- }
- return annotations;
- }
-
- static List toAnnotationConsumeTapEvents(Object o) {
- return toAnnotationOrder(o);
- }
-
static boolean isScrollByCameraUpdate(Object o) {
return toString(toList(o).get(0)).equals("scrollBy");
}
@@ -88,15 +51,17 @@ static CameraUpdate toCameraUpdate(Object o, MapboxMap mapboxMap, float density)
case "newLatLng":
return CameraUpdateFactory.newLatLng(toLatLng(data.get(1)));
case "newLatLngBounds":
- return CameraUpdateFactory.newLatLngBounds(toLatLngBounds(data.get(1)), toPixels(data.get(2), density),
- toPixels(data.get(3), density), toPixels(data.get(4), density), toPixels(data.get(5), density));
+ return CameraUpdateFactory.newLatLngBounds(
+ toLatLngBounds(data.get(1)),
+ toPixels(data.get(2), density),
+ toPixels(data.get(3), density),
+ toPixels(data.get(4), density),
+ toPixels(data.get(5), density));
case "newLatLngZoom":
return CameraUpdateFactory.newLatLngZoom(toLatLng(data.get(1)), toFloat(data.get(2)));
case "scrollBy":
mapboxMap.scrollBy(
- toFractionalPixels(data.get(1), density),
- toFractionalPixels(data.get(2), density)
- );
+ toFractionalPixels(data.get(1), density), toFractionalPixels(data.get(2), density));
return null;
case "zoomBy":
if (data.size() == 2) {
@@ -119,15 +84,15 @@ static CameraUpdate toCameraUpdate(Object o, MapboxMap mapboxMap, float density)
}
}
- private static double toDouble(Object o) {
+ static double toDouble(Object o) {
return ((Number) o).doubleValue();
}
- private static float toFloat(Object o) {
+ static float toFloat(Object o) {
return ((Number) o).floatValue();
}
- private static Float toFloatWrapper(Object o) {
+ static Float toFloatWrapper(Object o) {
return (o == null) ? null : toFloat(o);
}
@@ -151,12 +116,12 @@ private static Object toJson(LatLng latLng) {
return Arrays.asList(latLng.getLatitude(), latLng.getLongitude());
}
- private static LatLng toLatLng(Object o) {
+ static LatLng toLatLng(Object o) {
final List> data = toList(o);
return new LatLng(toDouble(data.get(0)), toDouble(data.get(1)));
}
- private static LatLngBounds toLatLngBounds(Object o) {
+ static LatLngBounds toLatLngBounds(Object o) {
if (o == null) {
return null;
}
@@ -168,15 +133,19 @@ private static LatLngBounds toLatLngBounds(Object o) {
return builder.build();
}
- static List toLatLngList(Object o) {
+ static List toLatLngList(Object o, boolean flippedOrder) {
if (o == null) {
return null;
}
final List> data = toList(o);
List latLngList = new ArrayList<>();
- for (int i=0; i< data.size(); i++) {
final List> coords = toList(data.get(i));
- latLngList.add(new LatLng(toDouble(coords.get(0)), toDouble(coords.get(1))));
+ if (flippedOrder) {
+ latLngList.add(new LatLng(toDouble(coords.get(1)), toDouble(coords.get(0))));
+ } else {
+ latLngList.add(new LatLng(toDouble(coords.get(0)), toDouble(coords.get(1))));
+ }
}
return latLngList;
}
@@ -188,7 +157,7 @@ private static List> toLatLngListList(Object o) {
final List> data = toList(o);
List> latLngListList = new ArrayList<>();
for (int i = 0; i < data.size(); i++) {
- List latLngList = toLatLngList(data.get(i));
+ List latLngList = toLatLngList(data.get(i), false);
latLngListList.add(latLngList);
}
return latLngListList;
@@ -199,14 +168,15 @@ static Polygon interpretListLatLng(List> geometry) {
for (List innerGeometry : geometry) {
List innerPoints = new ArrayList<>(innerGeometry.size());
for (LatLng latLng : innerGeometry) {
- innerPoints.add(com.mapbox.geojson.Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude()));
+ innerPoints.add(
+ com.mapbox.geojson.Point.fromLngLat(latLng.getLongitude(), latLng.getLatitude()));
}
points.add(innerPoints);
}
return Polygon.fromLngLats(points);
}
- private static List> toList(Object o) {
+ static List> toList(Object o) {
return (List>) o;
}
@@ -231,11 +201,12 @@ private static Point toPoint(Object o, float density) {
return new Point(toPixels(data.get(0), density), toPixels(data.get(1), density));
}
- private static String toString(Object o) {
+ static String toString(Object o) {
return (String) o;
}
- static void interpretMapboxMapOptions(Object o, MapboxMapOptionsSink sink) {
+ static void interpretMapboxMapOptions(Object o, MapboxMapOptionsSink sink, Context context) {
+ final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
final Map, ?> data = toMap(o);
final Object cameraTargetBounds = data.get("cameraTargetBounds");
if (cameraTargetBounds != null) {
@@ -254,8 +225,8 @@ static void interpretMapboxMapOptions(Object o, MapboxMapOptionsSink sink) {
if (minMaxZoomPreference != null) {
final List> zoomPreferenceData = toList(minMaxZoomPreference);
sink.setMinMaxZoomPreference( //
- toFloatWrapper(zoomPreferenceData.get(0)), //
- toFloatWrapper(zoomPreferenceData.get(1)));
+ toFloatWrapper(zoomPreferenceData.get(0)), //
+ toFloatWrapper(zoomPreferenceData.get(1)));
}
final Object rotateGesturesEnabled = data.get("rotateGesturesEnabled");
if (rotateGesturesEnabled != null) {
@@ -290,260 +261,30 @@ static void interpretMapboxMapOptions(Object o, MapboxMapOptionsSink sink) {
sink.setMyLocationRenderMode(toInt(myLocationRenderMode));
}
final Object logoViewMargins = data.get("logoViewMargins");
- if(logoViewMargins != null){
+ if (logoViewMargins != null) {
final List logoViewMarginsData = toList(logoViewMargins);
- sink.setLogoViewMargins(toInt(logoViewMarginsData.get(0)), toInt(logoViewMarginsData.get(1)));
+ final Point point = toPoint(logoViewMarginsData, metrics.density);
+ sink.setLogoViewMargins(point.x, point.y);
}
final Object compassGravity = data.get("compassViewPosition");
- if(compassGravity != null){
+ if (compassGravity != null) {
sink.setCompassGravity(toInt(compassGravity));
}
final Object compassViewMargins = data.get("compassViewMargins");
- if(compassViewMargins != null){
+ if (compassViewMargins != null) {
final List compassViewMarginsData = toList(compassViewMargins);
- sink.setCompassViewMargins(toInt(compassViewMarginsData.get(0)), toInt(compassViewMarginsData.get(1)));
+ final Point point = toPoint(compassViewMarginsData, metrics.density);
+ sink.setCompassViewMargins(point.x, point.y);
+ }
+ final Object attributionButtonGravity = data.get("attributionButtonPosition");
+ if (attributionButtonGravity != null) {
+ sink.setAttributionButtonGravity(toInt(attributionButtonGravity));
}
final Object attributionButtonMargins = data.get("attributionButtonMargins");
- if(attributionButtonMargins != null){
+ if (attributionButtonMargins != null) {
final List attributionButtonMarginsData = toList(attributionButtonMargins);
- sink.setAttributionButtonMargins(toInt(attributionButtonMarginsData.get(0)), toInt(attributionButtonMarginsData.get(1)));
- }
- }
-
- static void interpretSymbolOptions(Object o, SymbolOptionsSink sink) {
- final Map, ?> data = toMap(o);
- final Object iconSize = data.get("iconSize");
- if (iconSize != null) {
- sink.setIconSize(toFloat(iconSize));
- }
- final Object iconImage = data.get("iconImage");
- if (iconImage != null) {
- sink.setIconImage(toString(iconImage));
- }
- final Object iconRotate = data.get("iconRotate");
- if (iconRotate != null) {
- sink.setIconRotate(toFloat(iconRotate));
- }
- final Object iconOffset = data.get("iconOffset");
- if (iconOffset != null) {
- sink.setIconOffset(new float[] {toFloat(toList(iconOffset).get(0)), toFloat(toList(iconOffset).get(1))});
- }
- final Object iconAnchor = data.get("iconAnchor");
- if (iconAnchor != null) {
- sink.setIconAnchor(toString(iconAnchor));
- }
- final ArrayList fontNames = (ArrayList) data.get("fontNames");
- if (fontNames != null) {
- sink.setFontNames((String[]) fontNames.toArray(new String[0]));
- }
- final Object textField = data.get("textField");
- if (textField != null) {
- sink.setTextField(toString(textField));
- }
- final Object textSize = data.get("textSize");
- if (textSize != null) {
- sink.setTextSize(toFloat(textSize));
- }
- final Object textMaxWidth = data.get("textMaxWidth");
- if (textMaxWidth != null) {
- sink.setTextMaxWidth(toFloat(textMaxWidth));
- }
- final Object textLetterSpacing = data.get("textLetterSpacing");
- if (textLetterSpacing != null) {
- sink.setTextLetterSpacing(toFloat(textLetterSpacing));
- }
- final Object textJustify = data.get("textJustify");
- if (textJustify != null) {
- sink.setTextJustify(toString(textJustify));
- }
- final Object textAnchor = data.get("textAnchor");
- if (textAnchor != null) {
- sink.setTextAnchor(toString(textAnchor));
- }
- final Object textRotate = data.get("textRotate");
- if (textRotate != null) {
- sink.setTextRotate(toFloat(textRotate));
- }
- final Object textTransform = data.get("textTransform");
- if (textTransform != null) {
- sink.setTextTransform(toString(textTransform));
- }
- final Object textOffset = data.get("textOffset");
- if (textOffset != null) {
- sink.setTextOffset(new float[] {toFloat(toList(textOffset).get(0)), toFloat(toList(textOffset).get(1))});
- }
- final Object iconOpacity = data.get("iconOpacity");
- if (iconOpacity != null) {
- sink.setIconOpacity(toFloat(iconOpacity));
- }
- final Object iconColor = data.get("iconColor");
- if (iconColor != null) {
- sink.setIconColor(toString(iconColor));
- }
- final Object iconHaloColor = data.get("iconHaloColor");
- if (iconHaloColor != null) {
- sink.setIconHaloColor(toString(iconHaloColor));
- }
- final Object iconHaloWidth = data.get("iconHaloWidth");
- if (iconHaloWidth != null) {
- sink.setIconHaloWidth(toFloat(iconHaloWidth));
- }
- final Object iconHaloBlur = data.get("iconHaloBlur");
- if (iconHaloBlur != null) {
- sink.setIconHaloBlur(toFloat(iconHaloBlur));
- }
- final Object textOpacity = data.get("textOpacity");
- if (textOpacity != null) {
- sink.setTextOpacity(toFloat(textOpacity));
- }
- final Object textColor = data.get("textColor");
- if (textColor != null) {
- sink.setTextColor(toString(textColor));
- }
- final Object textHaloColor = data.get("textHaloColor");
- if (textHaloColor != null) {
- sink.setTextHaloColor(toString(textHaloColor));
- }
- final Object textHaloWidth = data.get("textHaloWidth");
- if (textHaloWidth != null) {
- sink.setTextHaloWidth(toFloat(textHaloWidth));
- }
- final Object textHaloBlur = data.get("textHaloBlur");
- if (textHaloBlur != null) {
- sink.setTextHaloBlur(toFloat(textHaloBlur));
- }
- final Object geometry = data.get("geometry");
- if (geometry != null) {
- sink.setGeometry(toLatLng(geometry));
- }
- final Object symbolSortKey = data.get("zIndex");
- if (symbolSortKey != null) {
- sink.setSymbolSortKey(toFloat(symbolSortKey));
- }
- final Object draggable = data.get("draggable");
- if (draggable != null) {
- sink.setDraggable(toBoolean(draggable));
- }
- }
-
- static void interpretCircleOptions(Object o, CircleOptionsSink sink) {
- final Map, ?> data = toMap(o);
- final Object circleRadius = data.get("circleRadius");
- if (circleRadius != null) {
- sink.setCircleRadius(toFloat(circleRadius));
- }
- final Object circleColor = data.get("circleColor");
- if (circleColor != null) {
- sink.setCircleColor(toString(circleColor));
- }
- final Object circleBlur = data.get("circleBlur");
- if (circleBlur != null) {
- sink.setCircleBlur(toFloat(circleBlur));
- }
- final Object circleOpacity = data.get("circleOpacity");
- if (circleOpacity != null) {
- sink.setCircleOpacity(toFloat(circleOpacity));
- }
- final Object circleStrokeWidth = data.get("circleStrokeWidth");
- if (circleStrokeWidth != null) {
- sink.setCircleStrokeWidth(toFloat(circleStrokeWidth));
- }
- final Object circleStrokeColor = data.get("circleStrokeColor");
- if (circleStrokeColor != null) {
- sink.setCircleStrokeColor(toString(circleStrokeColor));
- }
- final Object circleStrokeOpacity = data.get("circleStrokeOpacity");
- if (circleStrokeOpacity != null) {
- sink.setCircleStrokeOpacity(toFloat(circleStrokeOpacity));
- }
- final Object geometry = data.get("geometry");
- if (geometry != null) {
- sink.setGeometry(toLatLng(geometry));
- }
- final Object draggable = data.get("draggable");
- if (draggable != null) {
- sink.setDraggable(toBoolean(draggable));
- }
- }
- static void interpretLineOptions(Object o, LineOptionsSink sink) {
- final Map, ?> data = toMap(o);
- final Object lineJoin = data.get("lineJoin");
- if (lineJoin != null) {
- Logger.e(TAG, "setLineJoin" + lineJoin);
- sink.setLineJoin(toString(lineJoin));
- }
- final Object lineOpacity = data.get("lineOpacity");
- if (lineOpacity != null) {
- Logger.e(TAG, "setLineOpacity" + lineOpacity);
- sink.setLineOpacity(toFloat(lineOpacity));
- }
- final Object lineColor = data.get("lineColor");
- if (lineColor != null) {
- Logger.e(TAG, "setLineColor" + lineColor);
- sink.setLineColor(toString(lineColor));
- }
- final Object lineWidth = data.get("lineWidth");
- if (lineWidth != null) {
- Logger.e(TAG, "setLineWidth" + lineWidth);
- sink.setLineWidth(toFloat(lineWidth));
- }
- final Object lineGapWidth = data.get("lineGapWidth");
- if (lineGapWidth != null) {
- Logger.e(TAG, "setLineGapWidth" + lineGapWidth);
- sink.setLineGapWidth(toFloat(lineGapWidth));
- }
- final Object lineOffset = data.get("lineOffset");
- if (lineOffset != null) {
- Logger.e(TAG, "setLineOffset" + lineOffset);
- sink.setLineOffset(toFloat(lineOffset));
- }
- final Object lineBlur = data.get("lineBlur");
- if (lineBlur != null) {
- Logger.e(TAG, "setLineBlur" + lineBlur);
- sink.setLineBlur(toFloat(lineBlur));
- }
- final Object linePattern = data.get("linePattern");
- if (linePattern != null) {
- Logger.e(TAG, "setLinePattern" + linePattern);
- sink.setLinePattern(toString(linePattern));
- }
- final Object geometry = data.get("geometry");
- if (geometry != null) {
- Logger.e(TAG, "SetGeometry");
- sink.setGeometry(toLatLngList(geometry));
- }
- final Object draggable = data.get("draggable");
- if (draggable != null) {
- Logger.e(TAG, "SetDraggable");
- sink.setDraggable(toBoolean(draggable));
- }
- }
-
- static void interpretFillOptions(Object o, FillOptionsSink sink) {
- final Map, ?> data = toMap(o);
- final Object fillOpacity = data.get("fillOpacity");
- if (fillOpacity != null) {
- sink.setFillOpacity(toFloat(fillOpacity));
- }
- final Object fillColor = data.get("fillColor");
- if (fillColor != null) {
- sink.setFillColor(toString(fillColor));
- }
- final Object fillOutlineColor = data.get("fillOutlineColor");
- if (fillOutlineColor != null) {
- sink.setFillOutlineColor(toString(fillOutlineColor));
- }
- final Object fillPattern = data.get("fillPattern");
- if (fillPattern != null) {
- sink.setFillPattern(toString(fillPattern));
- }
- final Object geometry = data.get("geometry");
- if (geometry != null) {
- sink.setGeometry(toLatLngListList(geometry));
- }
- final Object draggable = data.get("draggable");
- if (draggable != null) {
- sink.setDraggable(toBoolean(draggable));
+ final Point point = toPoint(attributionButtonMarginsData, metrics.density);
+ sink.setAttributionButtonMargins(point.x, point.y);
}
}
-}
\ No newline at end of file
+}
diff --git a/android/src/main/java/com/mapbox/mapboxgl/FillBuilder.java b/android/src/main/java/com/mapbox/mapboxgl/FillBuilder.java
deleted file mode 100644
index b70589cba..000000000
--- a/android/src/main/java/com/mapbox/mapboxgl/FillBuilder.java
+++ /dev/null
@@ -1,62 +0,0 @@
-// This file is generated.
-
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.mapbox.mapboxgl;
-
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.plugins.annotation.Fill;
-import com.mapbox.mapboxsdk.plugins.annotation.FillManager;
-import com.mapbox.mapboxsdk.plugins.annotation.FillOptions;
-
-import java.util.List;
-
-class FillBuilder implements FillOptionsSink {
- private final FillManager fillManager;
- private final FillOptions fillOptions;
-
- FillBuilder(FillManager fillManager) {
- this.fillManager = fillManager;
- this.fillOptions = new FillOptions();
- }
-
- public FillOptions getFillOptions(){
- return this.fillOptions;
- }
-
- Fill build() {
- return fillManager.create(fillOptions);
- }
-
- @Override
- public void setFillOpacity(float fillOpacity) {
- fillOptions.withFillOpacity(fillOpacity);
- }
-
- @Override
- public void setFillColor(String fillColor) {
- fillOptions.withFillColor(fillColor);
- }
-
- @Override
- public void setFillOutlineColor(String fillOutlineColor) {
- fillOptions.withFillOutlineColor(fillOutlineColor);
- }
-
- @Override
- public void setFillPattern(String fillPattern) {
- fillOptions.withFillPattern(fillPattern);
- }
-
- @Override
- public void setGeometry(List> geometry) {
- fillOptions.withGeometry(Convert.interpretListLatLng(geometry));
- }
-
- @Override
- public void setDraggable(boolean draggable) {
- fillOptions.withDraggable(draggable);
- }
-}
\ No newline at end of file
diff --git a/android/src/main/java/com/mapbox/mapboxgl/FillController.java b/android/src/main/java/com/mapbox/mapboxgl/FillController.java
deleted file mode 100644
index 86bc01137..000000000
--- a/android/src/main/java/com/mapbox/mapboxgl/FillController.java
+++ /dev/null
@@ -1,78 +0,0 @@
-// This file is generated.
-
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.mapbox.mapboxgl;
-
-import android.graphics.Color;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.plugins.annotation.Fill;
-import com.mapbox.mapboxsdk.plugins.annotation.FillManager;
-
-import java.util.List;
-
-/**
- * Controller of a single Fill on the map.
- */
-class FillController implements FillOptionsSink {
- private final Fill fill;
- private final OnFillTappedListener onTappedListener;
- private boolean consumeTapEvents;
-
- FillController(Fill fill, boolean consumeTapEvents, OnFillTappedListener onTappedListener) {
- this.fill = fill;
- this.consumeTapEvents = consumeTapEvents;
- this.onTappedListener = onTappedListener;
- }
-
- public Fill getFill(){
- return this.fill;
- }
-
- boolean onTap() {
- if (onTappedListener != null) {
- onTappedListener.onFillTapped(fill);
- }
- return consumeTapEvents;
- }
-
- void remove(FillManager fillManager) {
- fillManager.delete(fill);
- }
-
- @Override
- public void setFillOpacity(float fillOpacity) {
- fill.setFillOpacity(fillOpacity);
- }
-
- @Override
- public void setFillColor(String fillColor) {
- fill.setFillColor(Color.parseColor(fillColor));
- }
-
- @Override
- public void setFillOutlineColor(String fillOutlineColor) {
- fill.setFillOutlineColor(Color.parseColor(fillOutlineColor));
- }
-
- @Override
- public void setFillPattern(String fillPattern) {
- fill.setFillPattern(fillPattern);
- }
-
- @Override
- public void setGeometry(List> geometry) {
- fill.setGeometry(Convert.interpretListLatLng(geometry));
- }
-
- @Override
- public void setDraggable(boolean draggable) {
- fill.setDraggable(draggable);
- }
-
- public void update(FillManager fillManager) {
- fillManager.update(fill);
- }
-}
diff --git a/android/src/main/java/com/mapbox/mapboxgl/FillOptionsSink.java b/android/src/main/java/com/mapbox/mapboxgl/FillOptionsSink.java
deleted file mode 100644
index 849788103..000000000
--- a/android/src/main/java/com/mapbox/mapboxgl/FillOptionsSink.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// This file is generated.
-
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.mapbox.mapboxgl;
-
-import com.mapbox.mapboxsdk.geometry.LatLng;
-
-import java.util.List;
-
-/** Receiver of Fill configuration options. */
-interface FillOptionsSink {
-
- void setFillOpacity(float fillOpacity);
-
- void setFillColor(String fillColor);
-
- void setFillOutlineColor(String fillOutlineColor);
-
- void setFillPattern(String fillPattern);
-
- void setGeometry(List> geometry);
-
- void setDraggable(boolean draggable);
-}
diff --git a/android/src/main/java/com/mapbox/mapboxgl/GeoJSONUtils.java b/android/src/main/java/com/mapbox/mapboxgl/GeoJSONUtils.java
new file mode 100644
index 000000000..db3b3ed51
--- /dev/null
+++ b/android/src/main/java/com/mapbox/mapboxgl/GeoJSONUtils.java
@@ -0,0 +1,38 @@
+package com.mapbox.mapboxgl;
+
+import com.mapbox.geojson.Feature;
+import com.mapbox.geojson.FeatureCollection;
+import com.mapbox.geojson.Geometry;
+import com.mapbox.geojson.GeometryCollection;
+import com.mapbox.geojson.Point;
+import com.mapbox.mapboxsdk.geometry.LatLng;
+import com.mapbox.mapboxsdk.geometry.LatLngBounds;
+import com.mapbox.turf.TurfMeasurement;
+import java.util.ArrayList;
+import java.util.List;
+
+public class GeoJSONUtils {
+ public static LatLng toLatLng(Point point) {
+ if (point == null) {
+ return null;
+ }
+ return new LatLng(point.latitude(), point.longitude());
+ }
+
+ private static GeometryCollection toGeometryCollection(List features) {
+ ArrayList geometries = new ArrayList<>();
+ geometries.ensureCapacity(features.size());
+ for (Feature feature : features) {
+ geometries.add(feature.geometry());
+ }
+ return GeometryCollection.fromGeometries(geometries);
+ }
+
+ public static LatLngBounds toLatLngBounds(FeatureCollection featureCollection) {
+ List features = featureCollection.features();
+
+ double[] bbox = TurfMeasurement.bbox(toGeometryCollection(features));
+
+ return LatLngBounds.from(bbox[3], bbox[2], bbox[1], bbox[0]);
+ }
+}
diff --git a/android/src/main/java/com/mapbox/mapboxgl/GlobalMethodHandler.java b/android/src/main/java/com/mapbox/mapboxgl/GlobalMethodHandler.java
index 1b95f47f5..771fd8a28 100644
--- a/android/src/main/java/com/mapbox/mapboxgl/GlobalMethodHandler.java
+++ b/android/src/main/java/com/mapbox/mapboxgl/GlobalMethodHandler.java
@@ -2,14 +2,14 @@
import android.content.Context;
import android.util.Log;
-
-import com.google.gson.Gson;
-import com.google.gson.JsonObject;
-import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-
+import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
+import io.flutter.embedding.engine.plugins.FlutterPlugin;
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+import io.flutter.plugin.common.PluginRegistry;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
@@ -20,139 +20,127 @@
import java.io.OutputStream;
import java.util.Map;
-import io.flutter.embedding.engine.plugins.FlutterPlugin;
-import io.flutter.plugin.common.BinaryMessenger;
-import io.flutter.plugin.common.MethodCall;
-import io.flutter.plugin.common.MethodChannel;
-import io.flutter.plugin.common.PluginRegistry;
-
class GlobalMethodHandler implements MethodChannel.MethodCallHandler {
- private static final String TAG = GlobalMethodHandler.class.getSimpleName();
- private static final String DATABASE_NAME = "mbgl-offline.db";
- private static final int BUFFER_SIZE = 1024 * 2;
-
- @Nullable
- private PluginRegistry.Registrar registrar;
- @Nullable
- private FlutterPlugin.FlutterAssets flutterAssets;
- @NonNull
- private final Context context;
- @NonNull
- private final BinaryMessenger messenger;
-
- GlobalMethodHandler(@NonNull PluginRegistry.Registrar registrar) {
- this.registrar = registrar;
- this.context = registrar.activeContext();
- this.messenger = registrar.messenger();
-
- }
-
- GlobalMethodHandler(@NonNull FlutterPlugin.FlutterPluginBinding binding) {
- this.context = binding.getApplicationContext();
- this.flutterAssets = binding.getFlutterAssets();
- this.messenger = binding.getBinaryMessenger();
- }
-
- @Override
- public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
- String accessToken = methodCall.argument("accessToken");
- MapBoxUtils.getMapbox(context, accessToken);
-
- switch (methodCall.method) {
- case "installOfflineMapTiles":
- String tilesDb = methodCall.argument("tilesdb");
- installOfflineMapTiles(tilesDb);
- result.success(null);
- break;
- case "setOffline":
- boolean offline = methodCall.argument("offline");
- ConnectivityReceiver.instance(context).setConnected(offline ? false : null);
- result.success(null);
- break;
- case "mergeOfflineRegions":
- OfflineManagerUtils.mergeRegions(result, context, methodCall.argument("path"));
- break;
- case "setOfflineTileCountLimit":
- OfflineManagerUtils.setOfflineTileCountLimit(result, context, methodCall.argument("limit").longValue());
- break;
- case "downloadOfflineRegion":
- // Get args from caller
- Map definitionMap = (Map) methodCall.argument("definition");
- Map metadataMap = (Map) methodCall.argument("metadata");
- String channelName = methodCall.argument("channelName");
-
- // Prepare args
- OfflineChannelHandlerImpl channelHandler = new OfflineChannelHandlerImpl(messenger, channelName);
-
- // Start downloading
- OfflineManagerUtils.downloadRegion(result, context, definitionMap, metadataMap, channelHandler);
- break;
- case "getListOfRegions":
- OfflineManagerUtils.regionsList(result, context);
- break;
- case "updateOfflineRegionMetadata":
- // Get download region arguments from caller
- Map metadata = (Map) methodCall.argument("metadata");
- OfflineManagerUtils.updateRegionMetadata(result, context, methodCall.argument("id").longValue(), metadata);
- break;
- case "deleteOfflineRegion":
- OfflineManagerUtils.deleteRegion(result, context, methodCall.argument("id").longValue());
- break;
- default:
- result.notImplemented();
- break;
- }
+ private static final String TAG = GlobalMethodHandler.class.getSimpleName();
+ private static final String DATABASE_NAME = "mbgl-offline.db";
+ private static final int BUFFER_SIZE = 1024 * 2;
+ @NonNull private final Context context;
+ @NonNull private final BinaryMessenger messenger;
+ @Nullable private FlutterPlugin.FlutterAssets flutterAssets;
+
+ GlobalMethodHandler(@NonNull FlutterPlugin.FlutterPluginBinding binding) {
+ this.context = binding.getApplicationContext();
+ this.flutterAssets = binding.getFlutterAssets();
+ this.messenger = binding.getBinaryMessenger();
+ }
+
+ private static void copy(InputStream input, OutputStream output) throws IOException {
+ final byte[] buffer = new byte[BUFFER_SIZE];
+ final BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);
+ final BufferedOutputStream out = new BufferedOutputStream(output, BUFFER_SIZE);
+ int count = 0;
+ int n = 0;
+ try {
+ while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
+ out.write(buffer, 0, n);
+ count += n;
+ }
+ out.flush();
+ } finally {
+ try {
+ out.close();
+ } catch (IOException e) {
+ Log.e(TAG, e.getMessage(), e);
+ }
+ try {
+ in.close();
+ } catch (IOException e) {
+ Log.e(TAG, e.getMessage(), e);
+ }
}
-
- private void installOfflineMapTiles(String tilesDb) {
- final File dest = new File(context.getFilesDir(), DATABASE_NAME);
- try (InputStream input = openTilesDbFile(tilesDb);
- OutputStream output = new FileOutputStream(dest)) {
- copy(input, output);
- } catch (IOException e) {
- e.printStackTrace();
- }
+ }
+
+ @Override
+ public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
+ String accessToken = methodCall.argument("accessToken");
+ MapBoxUtils.getMapbox(context, accessToken);
+
+ switch (methodCall.method) {
+ case "installOfflineMapTiles":
+ String tilesDb = methodCall.argument("tilesdb");
+ installOfflineMapTiles(tilesDb);
+ result.success(null);
+ break;
+ case "setOffline":
+ boolean offline = methodCall.argument("offline");
+ ConnectivityReceiver.instance(context).setConnected(offline ? false : null);
+ result.success(null);
+ break;
+ case "mergeOfflineRegions":
+ OfflineManagerUtils.mergeRegions(result, context, methodCall.argument("path"));
+ break;
+ case "setOfflineTileCountLimit":
+ OfflineManagerUtils.setOfflineTileCountLimit(
+ result, context, methodCall.argument("limit").longValue());
+ break;
+ case "setHttpHeaders":
+ Map headers = (Map) methodCall.argument("headers");
+ MapboxHttpRequestUtil.setHttpHeaders(headers, result);
+ break;
+ case "downloadOfflineRegion":
+ // Get args from caller
+ Map definitionMap = (Map) methodCall.argument("definition");
+ Map metadataMap = (Map) methodCall.argument("metadata");
+ String channelName = methodCall.argument("channelName");
+
+ // Prepare args
+ OfflineChannelHandlerImpl channelHandler =
+ new OfflineChannelHandlerImpl(messenger, channelName);
+
+ // Start downloading
+ OfflineManagerUtils.downloadRegion(
+ result, context, definitionMap, metadataMap, channelHandler);
+ break;
+ case "getListOfRegions":
+ OfflineManagerUtils.regionsList(result, context);
+ break;
+ case "updateOfflineRegionMetadata":
+ // Get download region arguments from caller
+ Map metadata = (Map) methodCall.argument("metadata");
+ OfflineManagerUtils.updateRegionMetadata(
+ result, context, methodCall.argument("id").longValue(), metadata);
+ break;
+ case "deleteOfflineRegion":
+ OfflineManagerUtils.deleteRegion(
+ result, context, methodCall.argument("id").longValue());
+ break;
+ default:
+ result.notImplemented();
+ break;
}
-
- private InputStream openTilesDbFile(String tilesDb) throws IOException {
- if (tilesDb.startsWith("/")) { // Absolute path.
- return new FileInputStream(new File(tilesDb));
- } else {
- String assetKey;
- if (registrar != null) {
- assetKey = registrar.lookupKeyForAsset(tilesDb);
- } else if(flutterAssets != null) {
- assetKey = flutterAssets.getAssetFilePathByName(tilesDb);
- } else {
- throw new IllegalStateException();
- }
- return context.getAssets().open(assetKey);
- }
+ }
+
+ private void installOfflineMapTiles(String tilesDb) {
+ final File dest = new File(context.getFilesDir(), DATABASE_NAME);
+ try (InputStream input = openTilesDbFile(tilesDb);
+ OutputStream output = new FileOutputStream(dest)) {
+ copy(input, output);
+ } catch (IOException e) {
+ e.printStackTrace();
}
-
- private static void copy(InputStream input, OutputStream output) throws IOException {
- final byte[] buffer = new byte[BUFFER_SIZE];
- final BufferedInputStream in = new BufferedInputStream(input, BUFFER_SIZE);
- final BufferedOutputStream out = new BufferedOutputStream(output, BUFFER_SIZE);
- int count = 0;
- int n = 0;
- try {
- while ((n = in.read(buffer, 0, BUFFER_SIZE)) != -1) {
- out.write(buffer, 0, n);
- count += n;
- }
- out.flush();
- } finally {
- try {
- out.close();
- } catch (IOException e) {
- Log.e(TAG, e.getMessage(), e);
- }
- try {
- in.close();
- } catch (IOException e) {
- Log.e(TAG, e.getMessage(), e);
- }
- }
+ }
+
+ private InputStream openTilesDbFile(String tilesDb) throws IOException {
+ if (tilesDb.startsWith("/")) { // Absolute path.
+ return new FileInputStream(new File(tilesDb));
+ } else {
+ String assetKey;
+ if (flutterAssets != null) {
+ assetKey = flutterAssets.getAssetFilePathByName(tilesDb);
+ } else {
+ throw new IllegalStateException();
+ }
+ return context.getAssets().open(assetKey);
}
+ }
}
diff --git a/android/src/main/java/com/mapbox/mapboxgl/LayerPropertyConverter.java b/android/src/main/java/com/mapbox/mapboxgl/LayerPropertyConverter.java
new file mode 100644
index 000000000..b10599dbb
--- /dev/null
+++ b/android/src/main/java/com/mapbox/mapboxgl/LayerPropertyConverter.java
@@ -0,0 +1,535 @@
+// This file is generated by
+// ./scripts/lib/generate.dart
+
+package com.mapbox.mapboxgl;
+
+import static com.mapbox.mapboxgl.Convert.toMap;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.mapbox.mapboxsdk.style.expressions.Expression;
+import com.mapbox.mapboxsdk.style.layers.PropertyFactory;
+import com.mapbox.mapboxsdk.style.layers.PropertyValue;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+class LayerPropertyConverter {
+ static PropertyValue[] interpretSymbolLayerProperties(Object o) {
+ final Map data = (Map) toMap(o);
+ final List properties = new LinkedList();
+ final JsonParser parser = new JsonParser();
+
+ for (Map.Entry entry : data.entrySet()) {
+ final JsonElement jsonElement = parser.parse(entry.getValue());
+ Expression expression = Expression.Converter.convert(jsonElement);
+ switch (entry.getKey()) {
+ case "icon-opacity":
+ properties.add(PropertyFactory.iconOpacity(expression));
+ break;
+ case "icon-color":
+ properties.add(PropertyFactory.iconColor(expression));
+ break;
+ case "icon-halo-color":
+ properties.add(PropertyFactory.iconHaloColor(expression));
+ break;
+ case "icon-halo-width":
+ properties.add(PropertyFactory.iconHaloWidth(expression));
+ break;
+ case "icon-halo-blur":
+ properties.add(PropertyFactory.iconHaloBlur(expression));
+ break;
+ case "icon-translate":
+ properties.add(PropertyFactory.iconTranslate(expression));
+ break;
+ case "icon-translate-anchor":
+ properties.add(PropertyFactory.iconTranslateAnchor(expression));
+ break;
+ case "text-opacity":
+ properties.add(PropertyFactory.textOpacity(expression));
+ break;
+ case "text-color":
+ properties.add(PropertyFactory.textColor(expression));
+ break;
+ case "text-halo-color":
+ properties.add(PropertyFactory.textHaloColor(expression));
+ break;
+ case "text-halo-width":
+ properties.add(PropertyFactory.textHaloWidth(expression));
+ break;
+ case "text-halo-blur":
+ properties.add(PropertyFactory.textHaloBlur(expression));
+ break;
+ case "text-translate":
+ properties.add(PropertyFactory.textTranslate(expression));
+ break;
+ case "text-translate-anchor":
+ properties.add(PropertyFactory.textTranslateAnchor(expression));
+ break;
+ case "symbol-placement":
+ properties.add(PropertyFactory.symbolPlacement(expression));
+ break;
+ case "symbol-spacing":
+ properties.add(PropertyFactory.symbolSpacing(expression));
+ break;
+ case "symbol-avoid-edges":
+ properties.add(PropertyFactory.symbolAvoidEdges(expression));
+ break;
+ case "symbol-sort-key":
+ properties.add(PropertyFactory.symbolSortKey(expression));
+ break;
+ case "symbol-z-order":
+ properties.add(PropertyFactory.symbolZOrder(expression));
+ break;
+ case "icon-allow-overlap":
+ properties.add(PropertyFactory.iconAllowOverlap(expression));
+ break;
+ case "icon-ignore-placement":
+ properties.add(PropertyFactory.iconIgnorePlacement(expression));
+ break;
+ case "icon-optional":
+ properties.add(PropertyFactory.iconOptional(expression));
+ break;
+ case "icon-rotation-alignment":
+ properties.add(PropertyFactory.iconRotationAlignment(expression));
+ break;
+ case "icon-size":
+ properties.add(PropertyFactory.iconSize(expression));
+ break;
+ case "icon-text-fit":
+ properties.add(PropertyFactory.iconTextFit(expression));
+ break;
+ case "icon-text-fit-padding":
+ properties.add(PropertyFactory.iconTextFitPadding(expression));
+ break;
+ case "icon-image":
+ if (jsonElement.isJsonPrimitive() && jsonElement.getAsJsonPrimitive().isString()) {
+ properties.add(PropertyFactory.iconImage(jsonElement.getAsString()));
+ } else {
+ properties.add(PropertyFactory.iconImage(expression));
+ }
+ break;
+ case "icon-rotate":
+ properties.add(PropertyFactory.iconRotate(expression));
+ break;
+ case "icon-padding":
+ properties.add(PropertyFactory.iconPadding(expression));
+ break;
+ case "icon-keep-upright":
+ properties.add(PropertyFactory.iconKeepUpright(expression));
+ break;
+ case "icon-offset":
+ properties.add(PropertyFactory.iconOffset(expression));
+ break;
+ case "icon-anchor":
+ properties.add(PropertyFactory.iconAnchor(expression));
+ break;
+ case "icon-pitch-alignment":
+ properties.add(PropertyFactory.iconPitchAlignment(expression));
+ break;
+ case "text-pitch-alignment":
+ properties.add(PropertyFactory.textPitchAlignment(expression));
+ break;
+ case "text-rotation-alignment":
+ properties.add(PropertyFactory.textRotationAlignment(expression));
+ break;
+ case "text-field":
+ properties.add(PropertyFactory.textField(expression));
+ break;
+ case "text-font":
+ properties.add(PropertyFactory.textFont(expression));
+ break;
+ case "text-size":
+ properties.add(PropertyFactory.textSize(expression));
+ break;
+ case "text-max-width":
+ properties.add(PropertyFactory.textMaxWidth(expression));
+ break;
+ case "text-line-height":
+ properties.add(PropertyFactory.textLineHeight(expression));
+ break;
+ case "text-letter-spacing":
+ properties.add(PropertyFactory.textLetterSpacing(expression));
+ break;
+ case "text-justify":
+ properties.add(PropertyFactory.textJustify(expression));
+ break;
+ case "text-radial-offset":
+ properties.add(PropertyFactory.textRadialOffset(expression));
+ break;
+ case "text-variable-anchor":
+ properties.add(PropertyFactory.textVariableAnchor(expression));
+ break;
+ case "text-anchor":
+ properties.add(PropertyFactory.textAnchor(expression));
+ break;
+ case "text-max-angle":
+ properties.add(PropertyFactory.textMaxAngle(expression));
+ break;
+ case "text-writing-mode":
+ properties.add(PropertyFactory.textWritingMode(expression));
+ break;
+ case "text-rotate":
+ properties.add(PropertyFactory.textRotate(expression));
+ break;
+ case "text-padding":
+ properties.add(PropertyFactory.textPadding(expression));
+ break;
+ case "text-keep-upright":
+ properties.add(PropertyFactory.textKeepUpright(expression));
+ break;
+ case "text-transform":
+ properties.add(PropertyFactory.textTransform(expression));
+ break;
+ case "text-offset":
+ properties.add(PropertyFactory.textOffset(expression));
+ break;
+ case "text-allow-overlap":
+ properties.add(PropertyFactory.textAllowOverlap(expression));
+ break;
+ case "text-ignore-placement":
+ properties.add(PropertyFactory.textIgnorePlacement(expression));
+ break;
+ case "text-optional":
+ properties.add(PropertyFactory.textOptional(expression));
+ break;
+ case "visibility":
+ properties.add(PropertyFactory.visibility(entry.getValue()));
+ break;
+ default:
+ break;
+ }
+ }
+
+ return properties.toArray(new PropertyValue[properties.size()]);
+ }
+
+ static PropertyValue[] interpretCircleLayerProperties(Object o) {
+ final Map data = (Map) toMap(o);
+ final List properties = new LinkedList();
+ final JsonParser parser = new JsonParser();
+
+ for (Map.Entry entry : data.entrySet()) {
+ final JsonElement jsonElement = parser.parse(entry.getValue());
+ Expression expression = Expression.Converter.convert(jsonElement);
+ switch (entry.getKey()) {
+ case "circle-radius":
+ properties.add(PropertyFactory.circleRadius(expression));
+ break;
+ case "circle-color":
+ properties.add(PropertyFactory.circleColor(expression));
+ break;
+ case "circle-blur":
+ properties.add(PropertyFactory.circleBlur(expression));
+ break;
+ case "circle-opacity":
+ properties.add(PropertyFactory.circleOpacity(expression));
+ break;
+ case "circle-translate":
+ properties.add(PropertyFactory.circleTranslate(expression));
+ break;
+ case "circle-translate-anchor":
+ properties.add(PropertyFactory.circleTranslateAnchor(expression));
+ break;
+ case "circle-pitch-scale":
+ properties.add(PropertyFactory.circlePitchScale(expression));
+ break;
+ case "circle-pitch-alignment":
+ properties.add(PropertyFactory.circlePitchAlignment(expression));
+ break;
+ case "circle-stroke-width":
+ properties.add(PropertyFactory.circleStrokeWidth(expression));
+ break;
+ case "circle-stroke-color":
+ properties.add(PropertyFactory.circleStrokeColor(expression));
+ break;
+ case "circle-stroke-opacity":
+ properties.add(PropertyFactory.circleStrokeOpacity(expression));
+ break;
+ case "circle-sort-key":
+ properties.add(PropertyFactory.circleSortKey(expression));
+ break;
+ case "visibility":
+ properties.add(PropertyFactory.visibility(entry.getValue()));
+ break;
+ default:
+ break;
+ }
+ }
+
+ return properties.toArray(new PropertyValue[properties.size()]);
+ }
+
+ static PropertyValue[] interpretLineLayerProperties(Object o) {
+ final Map data = (Map) toMap(o);
+ final List properties = new LinkedList();
+ final JsonParser parser = new JsonParser();
+
+ for (Map.Entry entry : data.entrySet()) {
+ final JsonElement jsonElement = parser.parse(entry.getValue());
+ Expression expression = Expression.Converter.convert(jsonElement);
+ switch (entry.getKey()) {
+ case "line-opacity":
+ properties.add(PropertyFactory.lineOpacity(expression));
+ break;
+ case "line-color":
+ properties.add(PropertyFactory.lineColor(expression));
+ break;
+ case "line-translate":
+ properties.add(PropertyFactory.lineTranslate(expression));
+ break;
+ case "line-translate-anchor":
+ properties.add(PropertyFactory.lineTranslateAnchor(expression));
+ break;
+ case "line-width":
+ properties.add(PropertyFactory.lineWidth(expression));
+ break;
+ case "line-gap-width":
+ properties.add(PropertyFactory.lineGapWidth(expression));
+ break;
+ case "line-offset":
+ properties.add(PropertyFactory.lineOffset(expression));
+ break;
+ case "line-blur":
+ properties.add(PropertyFactory.lineBlur(expression));
+ break;
+ case "line-dasharray":
+ properties.add(PropertyFactory.lineDasharray(expression));
+ break;
+ case "line-pattern":
+ properties.add(PropertyFactory.linePattern(expression));
+ break;
+ case "line-gradient":
+ properties.add(PropertyFactory.lineGradient(expression));
+ break;
+ case "line-cap":
+ properties.add(PropertyFactory.lineCap(expression));
+ break;
+ case "line-join":
+ properties.add(PropertyFactory.lineJoin(expression));
+ break;
+ case "line-miter-limit":
+ properties.add(PropertyFactory.lineMiterLimit(expression));
+ break;
+ case "line-round-limit":
+ properties.add(PropertyFactory.lineRoundLimit(expression));
+ break;
+ case "line-sort-key":
+ properties.add(PropertyFactory.lineSortKey(expression));
+ break;
+ case "visibility":
+ properties.add(PropertyFactory.visibility(entry.getValue()));
+ break;
+ default:
+ break;
+ }
+ }
+
+ return properties.toArray(new PropertyValue[properties.size()]);
+ }
+
+ static PropertyValue[] interpretFillLayerProperties(Object o) {
+ final Map data = (Map) toMap(o);
+ final List properties = new LinkedList();
+ final JsonParser parser = new JsonParser();
+
+ for (Map.Entry entry : data.entrySet()) {
+ final JsonElement jsonElement = parser.parse(entry.getValue());
+ Expression expression = Expression.Converter.convert(jsonElement);
+ switch (entry.getKey()) {
+ case "fill-antialias":
+ properties.add(PropertyFactory.fillAntialias(expression));
+ break;
+ case "fill-opacity":
+ properties.add(PropertyFactory.fillOpacity(expression));
+ break;
+ case "fill-color":
+ properties.add(PropertyFactory.fillColor(expression));
+ break;
+ case "fill-outline-color":
+ properties.add(PropertyFactory.fillOutlineColor(expression));
+ break;
+ case "fill-translate":
+ properties.add(PropertyFactory.fillTranslate(expression));
+ break;
+ case "fill-translate-anchor":
+ properties.add(PropertyFactory.fillTranslateAnchor(expression));
+ break;
+ case "fill-pattern":
+ properties.add(PropertyFactory.fillPattern(expression));
+ break;
+ case "fill-sort-key":
+ properties.add(PropertyFactory.fillSortKey(expression));
+ break;
+ case "visibility":
+ properties.add(PropertyFactory.visibility(entry.getValue()));
+ break;
+ default:
+ break;
+ }
+ }
+
+ return properties.toArray(new PropertyValue[properties.size()]);
+ }
+
+ static PropertyValue[] interpretFillExtrusionLayerProperties(Object o) {
+ final Map data = (Map) toMap(o);
+ final List properties = new LinkedList();
+ final JsonParser parser = new JsonParser();
+
+ for (Map.Entry entry : data.entrySet()) {
+ final JsonElement jsonElement = parser.parse(entry.getValue());
+ Expression expression = Expression.Converter.convert(jsonElement);
+ switch (entry.getKey()) {
+ case "fill-extrusion-opacity":
+ properties.add(PropertyFactory.fillExtrusionOpacity(expression));
+ break;
+ case "fill-extrusion-color":
+ properties.add(PropertyFactory.fillExtrusionColor(expression));
+ break;
+ case "fill-extrusion-translate":
+ properties.add(PropertyFactory.fillExtrusionTranslate(expression));
+ break;
+ case "fill-extrusion-translate-anchor":
+ properties.add(PropertyFactory.fillExtrusionTranslateAnchor(expression));
+ break;
+ case "fill-extrusion-pattern":
+ properties.add(PropertyFactory.fillExtrusionPattern(expression));
+ break;
+ case "fill-extrusion-height":
+ properties.add(PropertyFactory.fillExtrusionHeight(expression));
+ break;
+ case "fill-extrusion-base":
+ properties.add(PropertyFactory.fillExtrusionBase(expression));
+ break;
+ case "fill-extrusion-vertical-gradient":
+ properties.add(PropertyFactory.fillExtrusionVerticalGradient(expression));
+ break;
+ case "visibility":
+ properties.add(PropertyFactory.visibility(entry.getValue()));
+ break;
+ default:
+ break;
+ }
+ }
+
+ return properties.toArray(new PropertyValue[properties.size()]);
+ }
+
+ static PropertyValue[] interpretRasterLayerProperties(Object o) {
+ final Map data = (Map) toMap(o);
+ final List properties = new LinkedList();
+ final JsonParser parser = new JsonParser();
+
+ for (Map.Entry entry : data.entrySet()) {
+ final JsonElement jsonElement = parser.parse(entry.getValue());
+ Expression expression = Expression.Converter.convert(jsonElement);
+ switch (entry.getKey()) {
+ case "raster-opacity":
+ properties.add(PropertyFactory.rasterOpacity(expression));
+ break;
+ case "raster-hue-rotate":
+ properties.add(PropertyFactory.rasterHueRotate(expression));
+ break;
+ case "raster-brightness-min":
+ properties.add(PropertyFactory.rasterBrightnessMin(expression));
+ break;
+ case "raster-brightness-max":
+ properties.add(PropertyFactory.rasterBrightnessMax(expression));
+ break;
+ case "raster-saturation":
+ properties.add(PropertyFactory.rasterSaturation(expression));
+ break;
+ case "raster-contrast":
+ properties.add(PropertyFactory.rasterContrast(expression));
+ break;
+ case "raster-resampling":
+ properties.add(PropertyFactory.rasterResampling(expression));
+ break;
+ case "raster-fade-duration":
+ properties.add(PropertyFactory.rasterFadeDuration(expression));
+ break;
+ case "visibility":
+ properties.add(PropertyFactory.visibility(entry.getValue()));
+ break;
+ default:
+ break;
+ }
+ }
+
+ return properties.toArray(new PropertyValue[properties.size()]);
+ }
+
+ static PropertyValue[] interpretHillshadeLayerProperties(Object o) {
+ final Map data = (Map) toMap(o);
+ final List properties = new LinkedList();
+ final JsonParser parser = new JsonParser();
+
+ for (Map.Entry entry : data.entrySet()) {
+ final JsonElement jsonElement = parser.parse(entry.getValue());
+ Expression expression = Expression.Converter.convert(jsonElement);
+ switch (entry.getKey()) {
+ case "hillshade-illumination-direction":
+ properties.add(PropertyFactory.hillshadeIlluminationDirection(expression));
+ break;
+ case "hillshade-illumination-anchor":
+ properties.add(PropertyFactory.hillshadeIlluminationAnchor(expression));
+ break;
+ case "hillshade-exaggeration":
+ properties.add(PropertyFactory.hillshadeExaggeration(expression));
+ break;
+ case "hillshade-shadow-color":
+ properties.add(PropertyFactory.hillshadeShadowColor(expression));
+ break;
+ case "hillshade-highlight-color":
+ properties.add(PropertyFactory.hillshadeHighlightColor(expression));
+ break;
+ case "hillshade-accent-color":
+ properties.add(PropertyFactory.hillshadeAccentColor(expression));
+ break;
+ case "visibility":
+ properties.add(PropertyFactory.visibility(entry.getValue()));
+ break;
+ default:
+ break;
+ }
+ }
+
+ return properties.toArray(new PropertyValue[properties.size()]);
+ }
+
+ static PropertyValue[] interpretHeatmapLayerProperties(Object o) {
+ final Map data = (Map) toMap(o);
+ final List properties = new LinkedList();
+ final JsonParser parser = new JsonParser();
+
+ for (Map.Entry entry : data.entrySet()) {
+ final JsonElement jsonElement = parser.parse(entry.getValue());
+ Expression expression = Expression.Converter.convert(jsonElement);
+ switch (entry.getKey()) {
+ case "heatmap-radius":
+ properties.add(PropertyFactory.heatmapRadius(expression));
+ break;
+ case "heatmap-weight":
+ properties.add(PropertyFactory.heatmapWeight(expression));
+ break;
+ case "heatmap-intensity":
+ properties.add(PropertyFactory.heatmapIntensity(expression));
+ break;
+ case "heatmap-color":
+ properties.add(PropertyFactory.heatmapColor(expression));
+ break;
+ case "heatmap-opacity":
+ properties.add(PropertyFactory.heatmapOpacity(expression));
+ break;
+ case "visibility":
+ properties.add(PropertyFactory.visibility(entry.getValue()));
+ break;
+ default:
+ break;
+ }
+ }
+
+ return properties.toArray(new PropertyValue[properties.size()]);
+ }
+}
diff --git a/android/src/main/java/com/mapbox/mapboxgl/LineBuilder.java b/android/src/main/java/com/mapbox/mapboxgl/LineBuilder.java
deleted file mode 100644
index 5d7276143..000000000
--- a/android/src/main/java/com/mapbox/mapboxgl/LineBuilder.java
+++ /dev/null
@@ -1,82 +0,0 @@
-// This file is generated.
-
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.mapbox.mapboxgl;
-
-import java.util.List;
-import com.mapbox.geojson.Point;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.plugins.annotation.Line;
-import com.mapbox.mapboxsdk.plugins.annotation.LineManager;
-import com.mapbox.mapboxsdk.plugins.annotation.LineOptions;
-
-class LineBuilder implements LineOptionsSink {
- private final LineManager lineManager;
- private final LineOptions lineOptions;
-
- LineBuilder(LineManager lineManager) {
- this.lineManager = lineManager;
- this.lineOptions = new LineOptions();
- }
-
- public LineOptions getLineOptions(){
- return this.lineOptions;
- }
-
- Line build() {
- return lineManager.create(lineOptions);
- }
-
- @Override
- public void setLineJoin(String lineJoin) {
- lineOptions.withLineJoin(lineJoin);
- }
-
- @Override
- public void setLineOpacity(float lineOpacity) {
- lineOptions.withLineOpacity(lineOpacity);
- }
-
- @Override
- public void setLineColor(String lineColor) {
- lineOptions.withLineColor(lineColor);
- }
-
- @Override
- public void setLineWidth(float lineWidth) {
- lineOptions.withLineWidth(lineWidth);
- }
-
- @Override
- public void setLineGapWidth(float lineGapWidth) {
- lineOptions.withLineGapWidth(lineGapWidth);
- }
-
- @Override
- public void setLineOffset(float lineOffset) {
- lineOptions.withLineOffset(lineOffset);
- }
-
- @Override
- public void setLineBlur(float lineBlur) {
- lineOptions.withLineBlur(lineBlur);
- }
-
- @Override
- public void setLinePattern(String linePattern) {
- lineOptions.withLinePattern(linePattern);
- }
-
- @Override
- public void setGeometry(List geometry) {
- lineOptions.withLatLngs(geometry);
- }
-
- @Override
- public void setDraggable(boolean draggable) {
- lineOptions.withDraggable(draggable);
- }
-}
\ No newline at end of file
diff --git a/android/src/main/java/com/mapbox/mapboxgl/LineController.java b/android/src/main/java/com/mapbox/mapboxgl/LineController.java
deleted file mode 100644
index d7715909c..000000000
--- a/android/src/main/java/com/mapbox/mapboxgl/LineController.java
+++ /dev/null
@@ -1,112 +0,0 @@
-// This file is generated.
-
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.mapbox.mapboxgl;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import android.graphics.PointF;
-import android.util.Log;
-
-import com.mapbox.geojson.Point;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-import com.mapbox.mapboxsdk.plugins.annotation.Line;
-import com.mapbox.mapboxsdk.plugins.annotation.LineManager;
-import com.mapbox.mapboxsdk.utils.ColorUtils;
-
-/**
- * Controller of a single Line on the map.
- */
-class LineController implements LineOptionsSink {
- private final Line line;
- private final OnLineTappedListener onTappedListener;
- private boolean consumeTapEvents;
-
- LineController(Line line, boolean consumeTapEvents, OnLineTappedListener onTappedListener) {
- this.line = line;
- this.consumeTapEvents = consumeTapEvents;
- this.onTappedListener = onTappedListener;
- }
-
- public Line getLine(){
- return this.line;
- }
-
- boolean onTap() {
- if (onTappedListener != null) {
- onTappedListener.onLineTapped(line);
- }
- return consumeTapEvents;
- }
-
- void remove(LineManager lineManager) {
- lineManager.delete(line);
- }
-
- @Override
- public void setLineJoin(String lineJoin) {
- line.setLineJoin(lineJoin);
- }
-
- @Override
- public void setLineOpacity(float lineOpacity) {
- line.setLineOpacity(lineOpacity);
- }
-
- @Override
- public void setLineColor(String lineColor) {
- line.setLineColor(ColorUtils.rgbaToColor(lineColor));
- }
-
- @Override
- public void setLineWidth(float lineWidth) {
- line.setLineWidth(lineWidth);
- }
-
- @Override
- public void setLineGapWidth(float lineGapWidth) {
- line.setLineGapWidth(lineGapWidth);
- }
-
- @Override
- public void setLineOffset(float lineOffset) {
- line.setLineOffset(lineOffset);
- }
-
- @Override
- public void setLineBlur(float lineBlur) {
- line.setLineBlur(lineBlur);
- }
-
- @Override
- public void setLinePattern(String linePattern) {
- line.setLinePattern(linePattern);
- }
-
- @Override
- public void setGeometry(List geometry) {
- line.setLatLngs(geometry);
- }
-
- public List getGeometry() {
- List points = line.getGeometry().coordinates();
- List latLngs = new ArrayList<>();
- for (Point point : points) {
- latLngs.add(new LatLng(point.latitude(), point.longitude()));
- }
- return latLngs;
- }
-
- @Override
- public void setDraggable(boolean draggable) {
- line.setDraggable(draggable);
- }
-
- public void update(LineManager lineManager) {
- lineManager.update(line);
- }
-}
diff --git a/android/src/main/java/com/mapbox/mapboxgl/LineOptionsSink.java b/android/src/main/java/com/mapbox/mapboxgl/LineOptionsSink.java
deleted file mode 100644
index ddd2646b7..000000000
--- a/android/src/main/java/com/mapbox/mapboxgl/LineOptionsSink.java
+++ /dev/null
@@ -1,36 +0,0 @@
-// This file is generated.
-
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package com.mapbox.mapboxgl;
-
-import java.util.List;
-import com.mapbox.mapboxsdk.geometry.LatLng;
-
-/**
- * Receiver of Line configuration options.
- */
-interface LineOptionsSink {
-
- void setLineJoin(String lineJoin);
-
- void setLineOpacity(float lineOpacity);
-
- void setLineColor(String lineColor);
-
- void setLineWidth(float lineWidth);
-
- void setLineGapWidth(float lineGapWidth);
-
- void setLineOffset(float lineOffset);
-
- void setLineBlur(float lineBlur);
-
- void setLinePattern(String linePattern);
-
- void setGeometry(List geometry);
-
- void setDraggable(boolean draggable);
-}
diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapBoxUtils.java b/android/src/main/java/com/mapbox/mapboxgl/MapBoxUtils.java
index 2319da949..1bd491801 100644
--- a/android/src/main/java/com/mapbox/mapboxgl/MapBoxUtils.java
+++ b/android/src/main/java/com/mapbox/mapboxgl/MapBoxUtils.java
@@ -5,33 +5,37 @@
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.util.Log;
-
import androidx.annotation.NonNull;
-
import com.mapbox.mapboxsdk.Mapbox;
abstract class MapBoxUtils {
- private static final String TAG = "MapboxMapController";
+ private static final String TAG = "MapboxMapController";
- static Mapbox getMapbox(Context context, String accessToken) {
- return Mapbox.getInstance(context, accessToken == null ? getAccessToken(context) : accessToken);
- }
+ static Mapbox getMapbox(Context context, String accessToken) {
+ return Mapbox.getInstance(context, accessToken == null ? getAccessToken(context) : accessToken);
+ }
- private static String getAccessToken(@NonNull Context context) {
- try {
- ApplicationInfo ai = context.getPackageManager()
- .getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
- Bundle bundle = ai.metaData;
- String token = bundle.getString("com.mapbox.token");
- if (token == null || token.isEmpty()) {
- throw new NullPointerException();
- }
- return token;
- } catch (Exception e) {
- Log.e(TAG, "Failed to find an Access Token in the Application meta-data. Maps may not load correctly. " +
- "Please refer to the installation guide at https://github.com/tobrun/flutter-mapbox-gl#mapbox-access-token " +
- "for troubleshooting advice." + e.getMessage());
- }
- return null;
+ private static String getAccessToken(@NonNull Context context) {
+ try {
+ ApplicationInfo ai =
+ context
+ .getPackageManager()
+ .getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
+ Bundle bundle = ai.metaData;
+ String token = bundle.getString("com.mapbox.token");
+ if (token == null || token.isEmpty()) {
+ throw new NullPointerException();
+ }
+ return token;
+ } catch (Exception e) {
+ Log.e(
+ TAG,
+ "Failed to find an Access Token in the Application meta-data. Maps may not load"
+ + " correctly. Please refer to the installation guide at"
+ + " https://github.com/tobrun/flutter-mapbox-gl#mapbox-access-token for"
+ + " troubleshooting advice."
+ + e.getMessage());
}
+ return null;
+ }
}
diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxHttpRequestUtil.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxHttpRequestUtil.java
new file mode 100644
index 000000000..185bccd91
--- /dev/null
+++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxHttpRequestUtil.java
@@ -0,0 +1,43 @@
+package com.mapbox.mapboxgl;
+
+import com.mapbox.mapboxsdk.module.http.HttpRequestUtil;
+import io.flutter.plugin.common.MethodChannel;
+import java.util.Map;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+
+abstract class MapboxHttpRequestUtil {
+
+ public static void setHttpHeaders(Map headers, MethodChannel.Result result) {
+ HttpRequestUtil.setOkHttpClient(getOkHttpClient(headers, result).build());
+ result.success(null);
+ }
+
+ private static OkHttpClient.Builder getOkHttpClient(
+ Map headers, MethodChannel.Result result) {
+ try {
+ return new OkHttpClient.Builder()
+ .addNetworkInterceptor(
+ chain -> {
+ Request.Builder builder = chain.request().newBuilder();
+ for (Map.Entry header : headers.entrySet()) {
+ if (header.getKey() == null || header.getKey().trim().isEmpty()) {
+ continue;
+ }
+ if (header.getValue() == null || header.getValue().trim().isEmpty()) {
+ builder.removeHeader(header.getKey());
+ } else {
+ builder.header(header.getKey(), header.getValue());
+ }
+ }
+ return chain.proceed(builder.build());
+ });
+ } catch (Exception e) {
+ result.error(
+ "OK_HTTP_CLIENT_ERROR",
+ "An unexcepted error happened during creating http " + "client" + e.getMessage(),
+ null);
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java
index 045bb76f5..44121b20c 100644
--- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java
+++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapBuilder.java
@@ -5,45 +5,51 @@
package com.mapbox.mapboxgl;
import android.content.Context;
-import android.util.Log;
import android.view.Gravity;
-
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
import com.mapbox.mapboxsdk.maps.MapboxMapOptions;
import com.mapbox.mapboxsdk.maps.Style;
-
import io.flutter.plugin.common.BinaryMessenger;
-import io.flutter.plugin.common.PluginRegistry;
-
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.List;
-import java.util.ArrayList;
-
class MapboxMapBuilder implements MapboxMapOptionsSink {
public final String TAG = getClass().getSimpleName();
- private final MapboxMapOptions options = new MapboxMapOptions()
- .textureMode(true)
- .attributionEnabled(true);
+ private final MapboxMapOptions options =
+ new MapboxMapOptions().textureMode(true).attributionEnabled(true);
private boolean trackCameraPosition = false;
private boolean myLocationEnabled = false;
+ private boolean dragEnabled = true;
private int myLocationTrackingMode = 0;
private int myLocationRenderMode = 0;
private String styleString = Style.MAPBOX_STREETS;
- private List annotationOrder = new ArrayList();
- private List annotationConsumeTapEvents = new ArrayList();
-
+ private LatLngBounds bounds = null;
MapboxMapController build(
- int id, Context context, BinaryMessenger messenger, MapboxMapsPlugin.LifecycleProvider lifecycleProvider, String accessToken) {
+ int id,
+ Context context,
+ BinaryMessenger messenger,
+ MapboxMapsPlugin.LifecycleProvider lifecycleProvider,
+ String accessToken) {
final MapboxMapController controller =
- new MapboxMapController(id, context, messenger, lifecycleProvider, options, accessToken, styleString, annotationOrder, annotationConsumeTapEvents);
+ new MapboxMapController(
+ id,
+ context,
+ messenger,
+ lifecycleProvider,
+ options,
+ accessToken,
+ styleString,
+ dragEnabled);
controller.init();
controller.setMyLocationEnabled(myLocationEnabled);
controller.setMyLocationTrackingMode(myLocationTrackingMode);
controller.setMyLocationRenderMode(myLocationRenderMode);
controller.setTrackCameraPosition(trackCameraPosition);
+
+ if (null != bounds) {
+ controller.setCameraTargetBounds(bounds);
+ }
+
return controller;
}
@@ -58,15 +64,13 @@ public void setCompassEnabled(boolean compassEnabled) {
@Override
public void setCameraTargetBounds(LatLngBounds bounds) {
- Log.e(TAG, "setCameraTargetBounds is supported only after map initiated.");
- //throw new UnsupportedOperationException("setCameraTargetBounds is supported only after map initiated.");
- //options.latLngBoundsForCameraTarget(bounds);
+ this.bounds = bounds;
}
@Override
public void setStyleString(String styleString) {
this.styleString = styleString;
- //options. styleString(styleString);
+ // options. styleString(styleString);
}
@Override
@@ -118,23 +122,23 @@ public void setMyLocationTrackingMode(int myLocationTrackingMode) {
public void setMyLocationRenderMode(int myLocationRenderMode) {
this.myLocationRenderMode = myLocationRenderMode;
}
-
+
public void setLogoViewMargins(int x, int y) {
- options.logoMargins(new int[] {
- (int) x, //left
- (int) 0, //top
- (int) 0, //right
- (int) y, //bottom
- });
+ options.logoMargins(
+ new int[] {
+ (int) x, // left
+ (int) 0, // top
+ (int) 0, // right
+ (int) y, // bottom
+ });
}
@Override
public void setCompassGravity(int gravity) {
- switch(gravity){
+ switch (gravity) {
case 0:
options.compassGravity(Gravity.TOP | Gravity.START);
break;
- default:
case 1:
options.compassGravity(Gravity.TOP | Gravity.END);
break;
@@ -149,11 +153,12 @@ public void setCompassGravity(int gravity) {
@Override
public void setCompassViewMargins(int x, int y) {
- switch(options.getCompassGravity())
- {
+ switch (options.getCompassGravity()) {
case Gravity.TOP | Gravity.START:
options.compassMargins(new int[] {(int) x, (int) y, 0, 0});
break;
+ // If the application code has not specified gravity, assume the platform
+ // default for the compass which is top-right
default:
case Gravity.TOP | Gravity.END:
options.compassMargins(new int[] {0, (int) y, (int) x, 0});
@@ -168,21 +173,45 @@ public void setCompassViewMargins(int x, int y) {
}
@Override
- public void setAttributionButtonMargins(int x, int y) {
- options.attributionMargins(new int[] {
- (int) x, //left
- (int) 0, //top
- (int) 0, //right
- (int) y, //bottom
- });
+ public void setAttributionButtonGravity(int gravity) {
+ switch (gravity) {
+ case 0:
+ options.attributionGravity(Gravity.TOP | Gravity.START);
+ break;
+ case 1:
+ options.attributionGravity(Gravity.TOP | Gravity.END);
+ break;
+ case 2:
+ options.attributionGravity(Gravity.BOTTOM | Gravity.START);
+ break;
+ case 3:
+ options.attributionGravity(Gravity.BOTTOM | Gravity.END);
+ break;
+ }
}
- public void setAnnotationOrder(List annotations) {
- this.annotationOrder = annotations;
+ @Override
+ public void setAttributionButtonMargins(int x, int y) {
+ switch (options.getAttributionGravity()) {
+ case Gravity.TOP | Gravity.START:
+ options.attributionMargins(new int[] {(int) x, (int) y, 0, 0});
+ break;
+ case Gravity.TOP | Gravity.END:
+ options.attributionMargins(new int[] {0, (int) y, (int) x, 0});
+ break;
+ // If the application code has not specified gravity, assume the platform
+ // default for the attribution button which is bottom left
+ default:
+ case Gravity.BOTTOM | Gravity.START:
+ options.attributionMargins(new int[] {(int) x, 0, 0, (int) y});
+ break;
+ case Gravity.BOTTOM | Gravity.END:
+ options.attributionMargins(new int[] {0, 0, (int) x, (int) y});
+ break;
+ }
}
- public void setAnnotationConsumeTapEvents(List annotations) {
- this.annotationConsumeTapEvents = annotations;
+ public void setDragEnabled(boolean enabled) {
+ this.dragEnabled = enabled;
}
-
}
diff --git a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java
index 62b3cbd75..3499d4ef5 100644
--- a/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java
+++ b/android/src/main/java/com/mapbox/mapboxgl/MapboxMapController.java
@@ -4,6 +4,9 @@
package com.mapbox.mapboxgl;
+import static com.mapbox.mapboxsdk.style.layers.Property.*;
+import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
+
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -18,25 +21,30 @@
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Gravity;
+import android.view.MotionEvent;
import android.view.View;
-
import androidx.annotation.NonNull;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
-
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
import com.mapbox.android.core.location.LocationEngine;
import com.mapbox.android.core.location.LocationEngineCallback;
import com.mapbox.android.core.location.LocationEngineProvider;
import com.mapbox.android.core.location.LocationEngineResult;
+import com.mapbox.android.gestures.AndroidGesturesManager;
+import com.mapbox.android.gestures.MoveGestureDetector;
import com.mapbox.android.telemetry.TelemetryEnabler;
import com.mapbox.geojson.Feature;
+import com.mapbox.geojson.FeatureCollection;
+import com.mapbox.geojson.Point;
import com.mapbox.mapboxsdk.Mapbox;
import com.mapbox.mapboxsdk.camera.CameraPosition;
import com.mapbox.mapboxsdk.camera.CameraUpdate;
+import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
import com.mapbox.mapboxsdk.constants.MapboxConstants;
import com.mapbox.mapboxsdk.geometry.LatLng;
import com.mapbox.mapboxsdk.geometry.LatLngBounds;
@@ -53,115 +61,128 @@
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
import com.mapbox.mapboxsdk.maps.Style;
import com.mapbox.mapboxsdk.offline.OfflineManager;
-import com.mapbox.mapboxsdk.plugins.annotation.Annotation;
-import com.mapbox.mapboxsdk.plugins.annotation.Circle;
-import com.mapbox.mapboxsdk.plugins.annotation.CircleManager;
-import com.mapbox.mapboxsdk.plugins.annotation.CircleOptions;
-import com.mapbox.mapboxsdk.plugins.annotation.Fill;
-import com.mapbox.mapboxsdk.plugins.annotation.FillManager;
-import com.mapbox.mapboxsdk.plugins.annotation.FillOptions;
-import com.mapbox.mapboxsdk.plugins.annotation.Line;
-import com.mapbox.mapboxsdk.plugins.annotation.LineManager;
-import com.mapbox.mapboxsdk.plugins.annotation.LineOptions;
-import com.mapbox.mapboxsdk.plugins.annotation.OnAnnotationClickListener;
-import com.mapbox.mapboxsdk.plugins.annotation.Symbol;
-import com.mapbox.mapboxsdk.plugins.annotation.SymbolManager;
-import com.mapbox.mapboxsdk.plugins.annotation.SymbolOptions;
import com.mapbox.mapboxsdk.plugins.localization.LocalizationPlugin;
+import com.mapbox.mapboxsdk.snapshotter.MapSnapshotter;
+import com.mapbox.mapboxsdk.storage.FileSource;
import com.mapbox.mapboxsdk.style.expressions.Expression;
+import com.mapbox.mapboxsdk.style.layers.CircleLayer;
+import com.mapbox.mapboxsdk.style.layers.FillExtrusionLayer;
+import com.mapbox.mapboxsdk.style.layers.FillLayer;
+import com.mapbox.mapboxsdk.style.layers.HeatmapLayer;
+import com.mapbox.mapboxsdk.style.layers.HillshadeLayer;
+import com.mapbox.mapboxsdk.style.layers.Layer;
+import com.mapbox.mapboxsdk.style.layers.LineLayer;
+import com.mapbox.mapboxsdk.style.layers.PropertyValue;
import com.mapbox.mapboxsdk.style.layers.RasterLayer;
+import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
+import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
import com.mapbox.mapboxsdk.style.sources.ImageSource;
-
+import io.flutter.plugin.common.BinaryMessenger;
+import io.flutter.plugin.common.MethodCall;
+import io.flutter.plugin.common.MethodChannel;
+import io.flutter.plugin.platform.PlatformView;
import java.io.IOException;
import java.io.InputStream;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.List;
-import java.util.ArrayList;
import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
-import io.flutter.plugin.common.BinaryMessenger;
-import io.flutter.plugin.common.MethodCall;
-import io.flutter.plugin.common.MethodChannel;
-import io.flutter.plugin.platform.PlatformView;
-
-/**
- * Controller of a single MapboxMaps MapView instance.
- */
+/** Controller of a single MapboxMaps MapView instance. */
@SuppressLint("MissingPermission")
final class MapboxMapController
- implements DefaultLifecycleObserver,
- MapboxMap.OnCameraIdleListener,
- MapboxMap.OnCameraMoveListener,
- MapboxMap.OnCameraMoveStartedListener,
- OnAnnotationClickListener,
- MapboxMap.OnMapClickListener,
- MapboxMap.OnMapLongClickListener,
- MapboxMapOptionsSink,
- MethodChannel.MethodCallHandler,
- OnMapReadyCallback,
- OnCameraTrackingChangedListener,
- OnSymbolTappedListener,
- OnLineTappedListener,
- OnCircleTappedListener,
- OnFillTappedListener,
- PlatformView {
+ implements DefaultLifecycleObserver,
+ MapboxMap.OnCameraIdleListener,
+ MapboxMap.OnCameraMoveListener,
+ MapboxMap.OnCameraMoveStartedListener,
+ MapView.OnDidBecomeIdleListener,
+ MapboxMap.OnMapClickListener,
+ MapboxMap.OnMapLongClickListener,
+ MapboxMapOptionsSink,
+ MethodChannel.MethodCallHandler,
+ OnMapReadyCallback,
+ OnCameraTrackingChangedListener,
+ PlatformView {
+
private static final String TAG = "MapboxMapController";
private final int id;
private final MethodChannel methodChannel;
private final MapboxMapsPlugin.LifecycleProvider lifecycleProvider;
+ private final float density;
+ private final Context context;
+ private final String styleStringInitial;
+ private final Set interactiveFeatureLayerIds;
+ private final Map addedFeaturesByLayer;
+ private final Map mSnapshotterMap;
private MapView mapView;
private MapboxMap mapboxMap;
- private final Map symbols;
- private final Map lines;
- private final Map circles;
- private final Map fills;
- private SymbolManager symbolManager;
- private LineManager lineManager;
- private CircleManager circleManager;
- private FillManager fillManager;
private boolean trackCameraPosition = false;
private boolean myLocationEnabled = false;
private int myLocationTrackingMode = 0;
private int myLocationRenderMode = 0;
private boolean disposed = false;
- private final float density;
+ private boolean dragEnabled = true;
private MethodChannel.Result mapReadyResult;
- private final Context context;
- private final String styleStringInitial;
private LocationComponent locationComponent = null;
private LocationEngine locationEngine = null;
private LocationEngineCallback locationEngineCallback = null;
private LocalizationPlugin localizationPlugin;
private Style style;
- private List annotationOrder;
- private List annotationConsumeTapEvents;
+ private Feature draggedFeature;
+ private AndroidGesturesManager androidGesturesManager;
+ private LatLng dragOrigin;
+ private LatLng dragPrevious;
+ private LatLngBounds bounds = null;
+ Style.OnStyleLoaded onStyleLoadedCallback =
+ new Style.OnStyleLoaded() {
+ @Override
+ public void onStyleLoaded(@NonNull Style style) {
+ MapboxMapController.this.style = style;
+
+ updateMyLocationEnabled();
+
+ if (null != bounds) {
+ mapboxMap.setLatLngBoundsForCameraTarget(bounds);
+ }
+
+ mapboxMap.addOnMapClickListener(MapboxMapController.this);
+ mapboxMap.addOnMapLongClickListener(MapboxMapController.this);
+ localizationPlugin = new LocalizationPlugin(mapView, mapboxMap, style);
+
+ methodChannel.invokeMethod("map#onStyleLoaded", null);
+ }
+ };
MapboxMapController(
- int id,
- Context context,
- BinaryMessenger messenger,
- MapboxMapsPlugin.LifecycleProvider lifecycleProvider,
- MapboxMapOptions options,
- String accessToken,
- String styleStringInitial,
- List annotationOrder,
- List annotationConsumeTapEvents) {
+ int id,
+ Context context,
+ BinaryMessenger messenger,
+ MapboxMapsPlugin.LifecycleProvider lifecycleProvider,
+ MapboxMapOptions options,
+ String accessToken,
+ String styleStringInitial,
+ boolean dragEnabled) {
MapBoxUtils.getMapbox(context, accessToken);
this.id = id;
this.context = context;
+ this.dragEnabled = dragEnabled;
this.styleStringInitial = styleStringInitial;
this.mapView = new MapView(context, options);
- this.symbols = new HashMap<>();
- this.lines = new HashMap<>();
- this.circles = new HashMap<>();
- this.fills = new HashMap<>();
+ this.interactiveFeatureLayerIds = new HashSet<>();
+ this.addedFeaturesByLayer = new HashMap();
this.density = context.getResources().getDisplayMetrics().density;
this.lifecycleProvider = lifecycleProvider;
+ if (dragEnabled) {
+ this.androidGesturesManager = new AndroidGesturesManager(this.mapView.getContext(), false);
+ }
+ this.mSnapshotterMap = new HashMap<>();
methodChannel = new MethodChannel(messenger, "plugins.flutter.io/mapbox_maps_" + id);
methodChannel.setMethodCallHandler(this);
- this.annotationOrder = annotationOrder;
- this.annotationConsumeTapEvents = annotationConsumeTapEvents;
}
@Override
@@ -186,71 +207,6 @@ private CameraPosition getCameraPosition() {
return trackCameraPosition ? mapboxMap.getCameraPosition() : null;
}
- private SymbolController symbol(String symbolId) {
- final SymbolController symbol = symbols.get(symbolId);
- if (symbol == null) {
- throw new IllegalArgumentException("Unknown symbol: " + symbolId);
- }
- return symbol;
- }
-
- private LineBuilder newLineBuilder() {
- return new LineBuilder(lineManager);
- }
-
- private void removeLine(String lineId) {
- final LineController lineController = lines.remove(lineId);
- if (lineController != null) {
- lineController.remove(lineManager);
- }
- }
-
- private LineController line(String lineId) {
- final LineController line = lines.get(lineId);
- if (line == null) {
- throw new IllegalArgumentException("Unknown line: " + lineId);
- }
- return line;
- }
-
- private CircleBuilder newCircleBuilder() {
- return new CircleBuilder(circleManager);
- }
-
- private void removeCircle(String circleId) {
- final CircleController circleController = circles.remove(circleId);
- if (circleController != null) {
- circleController.remove(circleManager);
- }
- }
-
- private CircleController circle(String circleId) {
- final CircleController circle = circles.get(circleId);
- if (circle == null) {
- throw new IllegalArgumentException("Unknown circle: " + circleId);
- }
- return circle;
- }
-
- private FillBuilder newFillBuilder() {
- return new FillBuilder(fillManager);
- }
-
- private void removeFill(String fillId) {
- final FillController fillController = fills.remove(fillId);
- if (fillController != null) {
- fillController.remove(fillManager);
- }
- }
-
- private FillController fill(String fillId) {
- final FillController fill = fills.get(fillId);
- if (fill == null) {
- throw new IllegalArgumentException("Unknown fill: " + fillId);
- }
- return fill;
- }
-
@Override
public void onMapReady(MapboxMap mapboxMap) {
this.mapboxMap = mapboxMap;
@@ -262,20 +218,38 @@ public void onMapReady(MapboxMap mapboxMap) {
mapboxMap.addOnCameraMoveListener(this);
mapboxMap.addOnCameraIdleListener(this);
- mapView.addOnStyleImageMissingListener((id) -> {
- DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
- final Bitmap bitmap = getScaledImage(id, displayMetrics.density);
- if (bitmap != null) {
- mapboxMap.getStyle().addImage(id, bitmap);
- }
- });
+ if (androidGesturesManager != null) {
+ androidGesturesManager.setMoveGestureListener(new MoveGestureListener());
+ mapView.setOnTouchListener(
+ new View.OnTouchListener() {
+ @Override
+ public boolean onTouch(View v, MotionEvent event) {
+ androidGesturesManager.onTouchEvent(event);
+
+ return draggedFeature != null;
+ }
+ });
+ }
+
+ mapView.addOnStyleImageMissingListener(
+ (id) -> {
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ final Bitmap bitmap = getScaledImage(id, displayMetrics.density);
+ if (bitmap != null) {
+ mapboxMap.getStyle().addImage(id, bitmap);
+ }
+ });
+
+ mapView.addOnDidBecomeIdleListener(this);
setStyleString(styleStringInitial);
- // updateMyLocationEnabled();
}
@Override
public void setStyleString(String styleString) {
+ // clear old layer id from the location Component
+ clearLocationComponentLayer();
+
// Check if json, url, absolute path or asset path:
if (styleString == null || styleString.isEmpty()) {
Log.e(TAG, "setStyleString - string empty or null");
@@ -283,11 +257,11 @@ public void setStyleString(String styleString) {
mapboxMap.setStyle(new Style.Builder().fromJson(styleString), onStyleLoadedCallback);
} else if (styleString.startsWith("/")) {
// Absolute path
- mapboxMap.setStyle(new Style.Builder().fromUri("file://" + styleString), onStyleLoadedCallback);
- } else if (
- !styleString.startsWith("http://") &&
- !styleString.startsWith("https://")&&
- !styleString.startsWith("mapbox://")) {
+ mapboxMap.setStyle(
+ new Style.Builder().fromUri("file://" + styleString), onStyleLoadedCallback);
+ } else if (!styleString.startsWith("http://")
+ && !styleString.startsWith("https://")
+ && !styleString.startsWith("mapbox://")) {
// We are assuming that the style will be loaded from an asset here.
String key = MapboxMapsPlugin.flutterAssets.getAssetFilePathByName(styleString);
mapboxMap.setStyle(new Style.Builder().fromUri("asset://" + key), onStyleLoadedCallback);
@@ -296,77 +270,83 @@ public void setStyleString(String styleString) {
}
}
- Style.OnStyleLoaded onStyleLoadedCallback = new Style.OnStyleLoaded() {
- @Override
- public void onStyleLoaded(@NonNull Style style) {
- MapboxMapController.this.style = style;
- for(String annotationType : annotationOrder) {
- switch (annotationType) {
- case "AnnotationType.fill":
- enableFillManager(style);
- break;
- case "AnnotationType.line":
- enableLineManager(style);
- break;
- case "AnnotationType.circle":
- enableCircleManager(style);
- break;
- case "AnnotationType.symbol":
- enableSymbolManager(style);
- break;
- default:
- throw new IllegalArgumentException("Unknown annotation type: " + annotationType + ", must be either 'fill', 'line', 'circle' or 'symbol'");
- }
- }
-
- if (myLocationEnabled) {
- enableLocationComponent(style);
- }
- // needs to be placed after SymbolManager#addClickListener,
- // is fixed with 0.6.0 of annotations plugin
- mapboxMap.addOnMapClickListener(MapboxMapController.this);
- mapboxMap.addOnMapLongClickListener(MapboxMapController.this);
- localizationPlugin = new LocalizationPlugin(mapView, mapboxMap, style);
-
- methodChannel.invokeMethod("map#onStyleLoaded", null);
- }
- };
-
- @SuppressWarnings( {"MissingPermission"})
+ @SuppressWarnings({"MissingPermission"})
private void enableLocationComponent(@NonNull Style style) {
if (hasLocationPermission()) {
locationEngine = LocationEngineProvider.getBestLocationEngine(context);
- LocationComponentOptions locationComponentOptions = LocationComponentOptions.builder(context)
- .trackingGesturesManagement(true)
- .build();
locationComponent = mapboxMap.getLocationComponent();
- locationComponent.activateLocationComponent(context, style, locationComponentOptions);
+ locationComponent.activateLocationComponent(
+ context, style, buildLocationComponentOptions(style));
locationComponent.setLocationComponentEnabled(true);
// locationComponent.setRenderMode(RenderMode.COMPASS); // remove or keep default?
locationComponent.setLocationEngine(locationEngine);
locationComponent.setMaxAnimationFps(30);
updateMyLocationTrackingMode();
- setMyLocationTrackingMode(this.myLocationTrackingMode);
updateMyLocationRenderMode();
- setMyLocationRenderMode(this.myLocationRenderMode);
locationComponent.addOnCameraTrackingChangedListener(this);
} else {
Log.e(TAG, "missing location permissions");
}
}
- private void onUserLocationUpdate(Location location){
- if(location==null){
+ private void updateLocationComponentLayer() {
+ if (locationComponent != null && locationComponentRequiresUpdate()) {
+ locationComponent.applyStyle(buildLocationComponentOptions(style));
+ }
+ }
+
+ private void clearLocationComponentLayer() {
+ if (locationComponent != null) {
+ locationComponent.applyStyle(buildLocationComponentOptions(null));
+ }
+ }
+
+ String getLastLayerOnStyle(Style style) {
+ if (style != null) {
+ final List layers = style.getLayers();
+
+ if (layers.size() > 0) {
+ return layers.get(layers.size() - 1).getId();
+ }
+ }
+ return null;
+ }
+
+ /// only update if the last layer is not the mapbox-location-bearing-layer
+ boolean locationComponentRequiresUpdate() {
+ final String lastLayerId = getLastLayerOnStyle(style);
+ return lastLayerId != null && !lastLayerId.equals("mapbox-location-bearing-layer");
+ }
+
+ private LocationComponentOptions buildLocationComponentOptions(Style style) {
+ final LocationComponentOptions.Builder optionsBuilder =
+ LocationComponentOptions.builder(context);
+ optionsBuilder.trackingGesturesManagement(true);
+
+ final String lastLayerId = getLastLayerOnStyle(style);
+ if (lastLayerId != null) {
+ optionsBuilder.layerAbove(lastLayerId);
+ }
+ return optionsBuilder.build();
+ }
+
+ private void onUserLocationUpdate(Location location) {
+ if (location == null) {
return;
}
final Map userLocation = new HashMap<>(6);
- userLocation.put("position", new double[]{location.getLatitude(), location.getLongitude()});
+ userLocation.put("position", new double[] {location.getLatitude(), location.getLongitude()});
+ userLocation.put("speed", location.getSpeed());
userLocation.put("altitude", location.getAltitude());
userLocation.put("bearing", location.getBearing());
userLocation.put("horizontalAccuracy", location.getAccuracy());
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- userLocation.put("verticalAccuracy", (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) ? location.getVerticalAccuracyMeters() : null);
+ userLocation.put(
+ "verticalAccuracy",
+ (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
+ ? location.getVerticalAccuracyMeters()
+ : null);
}
userLocation.put("timestamp", location.getTime());
@@ -375,40 +355,311 @@ private void onUserLocationUpdate(Location location){
methodChannel.invokeMethod("map#onUserLocationUpdated", arguments);
}
- private void enableSymbolManager(@NonNull Style style) {
- if (symbolManager == null) {
- symbolManager = new SymbolManager(mapView, mapboxMap, style);
- symbolManager.setIconAllowOverlap(true);
- symbolManager.setIconIgnorePlacement(true);
- symbolManager.setTextAllowOverlap(true);
- symbolManager.setTextIgnorePlacement(true);
- symbolManager.addClickListener(MapboxMapController.this::onAnnotationClick);
+ private void addGeoJsonSource(String sourceName, String source) {
+ FeatureCollection featureCollection = FeatureCollection.fromJson(source);
+ GeoJsonSource geoJsonSource = new GeoJsonSource(sourceName, featureCollection);
+ addedFeaturesByLayer.put(sourceName, featureCollection);
+
+ style.addSource(geoJsonSource);
+ }
+
+ private void setGeoJsonSource(String sourceName, String geojson) {
+ FeatureCollection featureCollection = FeatureCollection.fromJson(geojson);
+ GeoJsonSource geoJsonSource = style.getSourceAs(sourceName);
+ addedFeaturesByLayer.put(sourceName, featureCollection);
+
+ geoJsonSource.setGeoJson(featureCollection);
+ }
+
+ private void setGeoJsonFeature(String sourceName, String geojsonFeature) {
+ Feature feature = Feature.fromJson(geojsonFeature);
+ FeatureCollection featureCollection = addedFeaturesByLayer.get(sourceName);
+ GeoJsonSource geoJsonSource = style.getSourceAs(sourceName);
+ if (featureCollection != null && geoJsonSource != null) {
+ final List features = featureCollection.features();
+ for (int i = 0; i < features.size(); i++) {
+ final String id = features.get(i).id();
+ if (id.equals(feature.id())) {
+ features.set(i, feature);
+ break;
+ }
+ }
+
+ geoJsonSource.setGeoJson(featureCollection);
+ }
+ }
+
+ private void addSymbolLayer(
+ String layerName,
+ String sourceName,
+ String belowLayerId,
+ String sourceLayer,
+ Float minZoom,
+ Float maxZoom,
+ PropertyValue[] properties,
+ boolean enableInteraction,
+ Expression filter) {
+
+ SymbolLayer symbolLayer = new SymbolLayer(layerName, sourceName);
+ symbolLayer.setProperties(properties);
+ if (sourceLayer != null) {
+ symbolLayer.setSourceLayer(sourceLayer);
+ }
+ if (minZoom != null) {
+ symbolLayer.setMinZoom(minZoom);
+ }
+ if (maxZoom != null) {
+ symbolLayer.setMaxZoom(maxZoom);
+ }
+ if (filter != null) {
+ symbolLayer.setFilter(filter);
+ }
+ if (belowLayerId != null) {
+ style.addLayerBelow(symbolLayer, belowLayerId);
+ } else {
+ style.addLayer(symbolLayer);
+ }
+ if (enableInteraction) {
+ interactiveFeatureLayerIds.add(layerName);
+ }
+ }
+
+ private void addLineLayer(
+ String layerName,
+ String sourceName,
+ String belowLayerId,
+ String sourceLayer,
+ Float minZoom,
+ Float maxZoom,
+ PropertyValue[] properties,
+ boolean enableInteraction,
+ Expression filter) {
+ LineLayer lineLayer = new LineLayer(layerName, sourceName);
+ lineLayer.setProperties(properties);
+ if (sourceLayer != null) {
+ lineLayer.setSourceLayer(sourceLayer);
+ }
+ if (minZoom != null) {
+ lineLayer.setMinZoom(minZoom);
+ }
+ if (maxZoom != null) {
+ lineLayer.setMaxZoom(maxZoom);
+ }
+ if (filter != null) {
+ lineLayer.setFilter(filter);
+ }
+ if (belowLayerId != null) {
+ style.addLayerBelow(lineLayer, belowLayerId);
+ } else {
+ style.addLayer(lineLayer);
+ }
+ if (enableInteraction) {
+ interactiveFeatureLayerIds.add(layerName);
+ }
+ }
+
+ private void addFillLayer(
+ String layerName,
+ String sourceName,
+ String belowLayerId,
+ String sourceLayer,
+ Float minZoom,
+ Float maxZoom,
+ PropertyValue[] properties,
+ boolean enableInteraction,
+ Expression filter) {
+ FillLayer fillLayer = new FillLayer(layerName, sourceName);
+ fillLayer.setProperties(properties);
+ if (sourceLayer != null) {
+ fillLayer.setSourceLayer(sourceLayer);
+ }
+ if (minZoom != null) {
+ fillLayer.setMinZoom(minZoom);
+ }
+ if (maxZoom != null) {
+ fillLayer.setMaxZoom(maxZoom);
+ }
+ if (filter != null) {
+ fillLayer.setFilter(filter);
+ }
+ if (belowLayerId != null) {
+ style.addLayerBelow(fillLayer, belowLayerId);
+ } else {
+ style.addLayer(fillLayer);
+ }
+ if (enableInteraction) {
+ interactiveFeatureLayerIds.add(layerName);
+ }
+ }
+
+ private void addFillExtrusionLayer(
+ String layerName,
+ String sourceName,
+ String belowLayerId,
+ String sourceLayer,
+ Float minZoom,
+ Float maxZoom,
+ PropertyValue[] properties,
+ boolean enableInteraction,
+ Expression filter) {
+ FillExtrusionLayer fillLayer = new FillExtrusionLayer(layerName, sourceName);
+ fillLayer.setProperties(properties);
+ if (sourceLayer != null) {
+ fillLayer.setSourceLayer(sourceLayer);
+ }
+ if (minZoom != null) {
+ fillLayer.setMinZoom(minZoom);
+ }
+ if (maxZoom != null) {
+ fillLayer.setMaxZoom(maxZoom);
+ }
+ if (filter != null) {
+ fillLayer.setFilter(filter);
+ }
+ if (belowLayerId != null) {
+ style.addLayerBelow(fillLayer, belowLayerId);
+ } else {
+ style.addLayer(fillLayer);
+ }
+ if (enableInteraction) {
+ interactiveFeatureLayerIds.add(layerName);
}
}
- private void enableLineManager(@NonNull Style style) {
- if (lineManager == null) {
- lineManager = new LineManager(mapView, mapboxMap, style);
- lineManager.addClickListener(MapboxMapController.this::onAnnotationClick);
+ private void addCircleLayer(
+ String layerName,
+ String sourceName,
+ String belowLayerId,
+ String sourceLayer,
+ Float minZoom,
+ Float maxZoom,
+ PropertyValue[] properties,
+ boolean enableInteraction,
+ Expression filter) {
+ CircleLayer circleLayer = new CircleLayer(layerName, sourceName);
+ circleLayer.setProperties(properties);
+ if (sourceLayer != null) {
+ circleLayer.setSourceLayer(sourceLayer);
+ }
+ if (minZoom != null) {
+ circleLayer.setMinZoom(minZoom);
+ }
+ if (maxZoom != null) {
+ circleLayer.setMaxZoom(maxZoom);
+ }
+ if (filter != null) {
+ circleLayer.setFilter(filter);
+ }
+ if (belowLayerId != null) {
+ style.addLayerBelow(circleLayer, belowLayerId);
+ } else {
+ style.addLayer(circleLayer);
+ }
+ if (enableInteraction) {
+ interactiveFeatureLayerIds.add(layerName);
}
}
- private void enableCircleManager(@NonNull Style style) {
- if (circleManager == null) {
- circleManager = new CircleManager(mapView, mapboxMap, style);
- circleManager.addClickListener(MapboxMapController.this::onAnnotationClick);
+ private Expression parseFilter(String filter) {
+ JsonParser parser = new JsonParser();
+ JsonElement filterJsonElement = parser.parse(filter);
+ return filterJsonElement.isJsonNull() ? null : Expression.Converter.convert(filterJsonElement);
+ }
+
+ private void addRasterLayer(
+ String layerName,
+ String sourceName,
+ Float minZoom,
+ Float maxZoom,
+ String belowLayerId,
+ PropertyValue[] properties,
+ Expression filter) {
+ RasterLayer layer = new RasterLayer(layerName, sourceName);
+ layer.setProperties(properties);
+ if (minZoom != null) {
+ layer.setMinZoom(minZoom);
+ }
+ if (maxZoom != null) {
+ layer.setMaxZoom(maxZoom);
+ }
+ if (belowLayerId != null) {
+ style.addLayerBelow(layer, belowLayerId);
+ } else {
+ style.addLayer(layer);
}
}
- private void enableFillManager(@NonNull Style style) {
- if (fillManager == null) {
- fillManager = new FillManager(mapView, mapboxMap, style);
- fillManager.addClickListener(MapboxMapController.this::onAnnotationClick);
+ private void addHillshadeLayer(
+ String layerName,
+ String sourceName,
+ Float minZoom,
+ Float maxZoom,
+ String belowLayerId,
+ PropertyValue[] properties,
+ Expression filter) {
+ HillshadeLayer layer = new HillshadeLayer(layerName, sourceName);
+ layer.setProperties(properties);
+ if (minZoom != null) {
+ layer.setMinZoom(minZoom);
+ }
+ if (maxZoom != null) {
+ layer.setMaxZoom(maxZoom);
+ }
+ if (belowLayerId != null) {
+ style.addLayerBelow(layer, belowLayerId);
+ } else {
+ style.addLayer(layer);
}
}
+ private void addHeatmapLayer(
+ String layerName,
+ String sourceName,
+ Float minZoom,
+ Float maxZoom,
+ String belowLayerId,
+ PropertyValue[] properties,
+ Expression filter) {
+ HeatmapLayer layer = new HeatmapLayer(layerName, sourceName);
+ layer.setProperties(properties);
+ if (minZoom != null) {
+ layer.setMinZoom(minZoom);
+ }
+ if (maxZoom != null) {
+ layer.setMaxZoom(maxZoom);
+ }
+ if (belowLayerId != null) {
+ style.addLayerBelow(layer, belowLayerId);
+ } else {
+ style.addLayer(layer);
+ }
+ }
+
+ private Feature firstFeatureOnLayers(RectF in) {
+ if (style != null) {
+ final List layers = style.getLayers();
+ final List layersInOrder = new ArrayList();
+ for (Layer layer : layers) {
+ String id = layer.getId();
+ if (interactiveFeatureLayerIds.contains(id)) {
+ layersInOrder.add(id);
+ }
+ }
+ Collections.reverse(layersInOrder);
+
+ for (String id : layersInOrder) {
+ List features = mapboxMap.queryRenderedFeatures(in, id);
+ if (!features.isEmpty()) {
+ return features.get(0);
+ }
+ }
+ }
+ return null;
+ }
+
@Override
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
+
switch (call.method) {
case "map#waitForMap":
if (mapboxMap != null) {
@@ -417,571 +668,767 @@ public void onMethodCall(MethodCall call, MethodChannel.Result result) {
}
mapReadyResult = result;
break;
- case "map#update": {
- Convert.interpretMapboxMapOptions(call.argument("options"), this);
- result.success(Convert.toJson(getCameraPosition()));
- break;
- }
- case "map#updateMyLocationTrackingMode": {
- int myLocationTrackingMode = call.argument("mode");
- setMyLocationTrackingMode(myLocationTrackingMode);
- result.success(null);
- break;
- }
- case "map#matchMapLanguageWithDeviceDefault": {
- try {
- localizationPlugin.matchMapLanguageWithDeviceDefault();
- result.success(null);
- } catch (RuntimeException exception) {
- Log.d(TAG, exception.toString());
- result.error("MAPBOX LOCALIZATION PLUGIN ERROR", exception.toString(), null);
- }
- break;
- }
- case "map#setMapLanguage": {
- final String language = call.argument("language");
- try {
- localizationPlugin.setMapLanguage(language);
- result.success(null);
- } catch (RuntimeException exception) {
- Log.d(TAG, exception.toString());
- result.error("MAPBOX LOCALIZATION PLUGIN ERROR", exception.toString(), null);
- }
- break;
- }
- case "map#getVisibleRegion": {
- Map reply = new HashMap<>();
- VisibleRegion visibleRegion = mapboxMap.getProjection().getVisibleRegion();
- reply.put("sw", Arrays.asList(visibleRegion.nearLeft.getLatitude(), visibleRegion.nearLeft.getLongitude()));
- reply.put("ne", Arrays.asList(visibleRegion.farRight.getLatitude(), visibleRegion.farRight.getLongitude()));
- result.success(reply);
- break;
- }
- case "map#toScreenLocation": {
- Map reply = new HashMap<>();
- PointF pointf = mapboxMap.getProjection().toScreenLocation(new LatLng(call.argument("latitude"),call.argument("longitude")));
- reply.put("x", pointf.x);
- reply.put("y", pointf.y);
- result.success(reply);
- break;
- }
- case "map#toScreenLocationBatch": {
- double[] param = (double[])call.argument("coordinates");
- double[] reply = new double[param.length];
-
- for (int i = 0; i < param.length; i += 2) {
- PointF pointf = mapboxMap.getProjection().toScreenLocation(new LatLng(param[i], param[i + 1]));
- reply[i] = pointf.x;
- reply[i + 1] = pointf.y;
+ case "map#update":
+ {
+ Convert.interpretMapboxMapOptions(call.argument("options"), this, context);
+ result.success(Convert.toJson(getCameraPosition()));
+ break;
}
-
- result.success(reply);
- break;
- }
- case "map#toLatLng": {
- Map reply = new HashMap<>();
- LatLng latlng = mapboxMap.getProjection().fromScreenLocation(new PointF( ((Double) call.argument("x")).floatValue(), ((Double) call.argument("y")).floatValue()));
- reply.put("latitude", latlng.getLatitude());
- reply.put("longitude", latlng.getLongitude());
- result.success(reply);
- break;
- }
- case "map#getMetersPerPixelAtLatitude": {
- Map reply = new HashMap<>();
- Double retVal = mapboxMap.getProjection().getMetersPerPixelAtLatitude((Double)call.argument("latitude"));
- reply.put("metersperpixel", retVal);
- result.success(reply);
- break;
- }
- case "camera#move": {
- final CameraUpdate cameraUpdate = Convert.toCameraUpdate(call.argument("cameraUpdate"), mapboxMap, density);
- if (cameraUpdate != null) {
- // camera transformation not handled yet
- mapboxMap.moveCamera(cameraUpdate, new OnCameraMoveFinishedListener(){
- @Override
- public void onFinish() {
- super.onFinish();
- result.success(true);
- }
-
- @Override
- public void onCancel() {
- super.onCancel();
- result.success(false);
- }
- });
-
- // moveCamera(cameraUpdate);
- }else {
- result.success(false);
+ case "map#updateMyLocationTrackingMode":
+ {
+ int myLocationTrackingMode = call.argument("mode");
+ setMyLocationTrackingMode(myLocationTrackingMode);
+ result.success(null);
+ break;
}
- break;
- }
- case "camera#animate": {
- final CameraUpdate cameraUpdate = Convert.toCameraUpdate(call.argument("cameraUpdate"), mapboxMap, density);
- final Integer duration = call.argument("duration");
-
- final OnCameraMoveFinishedListener onCameraMoveFinishedListener = new OnCameraMoveFinishedListener(){
- @Override
- public void onFinish() {
- super.onFinish();
- result.success(true);
+ case "map#matchMapLanguageWithDeviceDefault":
+ {
+ try {
+ localizationPlugin.matchMapLanguageWithDeviceDefault();
+ result.success(null);
+ } catch (RuntimeException exception) {
+ Log.d(TAG, exception.toString());
+ result.error("MAPBOX LOCALIZATION PLUGIN ERROR", exception.toString(), null);
}
-
- @Override
- public void onCancel() {
- super.onCancel();
- result.success(false);
+ break;
+ }
+ case "map#updateContentInsets":
+ {
+ HashMap insets = call.argument("bounds");
+ final CameraUpdate cameraUpdate =
+ CameraUpdateFactory.paddingTo(
+ Convert.toPixels(insets.get("left"), density),
+ Convert.toPixels(insets.get("top"), density),
+ Convert.toPixels(insets.get("right"), density),
+ Convert.toPixels(insets.get("bottom"), density));
+
+ if (call.argument("animated")) {
+ animateCamera(cameraUpdate, null, result);
+ } else {
+ moveCamera(cameraUpdate, result);
}
- };
- if (cameraUpdate != null && duration != null) {
- // camera transformation not handled yet
- mapboxMap.animateCamera(cameraUpdate, duration, onCameraMoveFinishedListener);
- } else if (cameraUpdate != null) {
- // camera transformation not handled yet
- mapboxMap.animateCamera(cameraUpdate, onCameraMoveFinishedListener);
- } else {
- result.success(false);
+ break;
}
- break;
- }
- case "map#queryRenderedFeatures": {
- Map reply = new HashMap<>();
- List features;
-
- String[] layerIds = ((List) call.argument("layerIds")).toArray(new String[0]);
+ case "map#setMapLanguage":
+ {
+ final String language = call.argument("language");
+ try {
+ localizationPlugin.setMapLanguage(language);
+ result.success(null);
+ } catch (RuntimeException exception) {
+ Log.d(TAG, exception.toString());
+ result.error("MAPBOX LOCALIZATION PLUGIN ERROR", exception.toString(), null);
+ }
+ break;
+ }
+ case "map#getVisibleRegion":
+ {
+ Map reply = new HashMap<>();
+ VisibleRegion visibleRegion = mapboxMap.getProjection().getVisibleRegion();
+ reply.put(
+ "sw",
+ Arrays.asList(
+ visibleRegion.nearLeft.getLatitude(), visibleRegion.nearLeft.getLongitude()));
+ reply.put(
+ "ne",
+ Arrays.asList(
+ visibleRegion.farRight.getLatitude(), visibleRegion.farRight.getLongitude()));
+ result.success(reply);
+ break;
+ }
+ case "map#toScreenLocation":
+ {
+ Map reply = new HashMap<>();
+ PointF pointf =
+ mapboxMap
+ .getProjection()
+ .toScreenLocation(
+ new LatLng(call.argument("latitude"), call.argument("longitude")));
+ reply.put("x", pointf.x);
+ reply.put("y", pointf.y);
+ result.success(reply);
+ break;
+ }
+ case "map#toScreenLocationBatch":
+ {
+ double[] param = (double[]) call.argument("coordinates");
+ double[] reply = new double[param.length];
+
+ for (int i = 0; i < param.length; i += 2) {
+ PointF pointf =
+ mapboxMap.getProjection().toScreenLocation(new LatLng(param[i], param[i + 1]));
+ reply[i] = pointf.x;
+ reply[i + 1] = pointf.y;
+ }
- List