Merge branch 'release-agua' into tvn-merge-release
This commit is contained in:
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,6 +1,3 @@
|
||||
[submodule "platform/ios/vendor/SMCalloutView"]
|
||||
path = platform/ios/vendor/SMCalloutView
|
||||
url = https://github.com/nfarina/calloutview.git
|
||||
[submodule "platform/ios/uitest/KIF"]
|
||||
path = platform/ios/uitest/KIF
|
||||
url = https://github.com/kif-framework/KIF.git
|
||||
|
||||
21
Makefile
21
Makefile
@@ -222,6 +222,14 @@ iproj: $(IOS_PROJ_PATH)
|
||||
ios-test: $(IOS_PROJ_PATH)
|
||||
set -o pipefail && $(IOS_XCODEBUILD_SIM) -scheme 'CI' test $(XCPRETTY)
|
||||
|
||||
.PHONY: ios-sanitize-address
|
||||
ios-sanitize-address: $(IOS_PROJ_PATH)
|
||||
set -o pipefail && $(IOS_XCODEBUILD_SIM) -scheme 'CI' -enableAddressSanitizer YES test $(XCPRETTY)
|
||||
|
||||
.PHONY: ios-sanitize-thread
|
||||
ios-sanitize-thread: $(IOS_PROJ_PATH)
|
||||
set -o pipefail && $(IOS_XCODEBUILD_SIM) -scheme 'CI' -enableThreadSanitizer YES test $(XCPRETTY)
|
||||
|
||||
.PHONY: ipackage
|
||||
ipackage: $(IOS_PROJ_PATH)
|
||||
FORMAT=$(FORMAT) BUILD_DEVICE=$(BUILD_DEVICE) SYMBOLS=$(SYMBOLS) \
|
||||
@@ -553,6 +561,11 @@ run-android-ui-test-$1-%: platform/android/configuration.gradle
|
||||
-adb uninstall com.mapbox.mapboxsdk.testapp 2> /dev/null
|
||||
cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=$2 :MapboxGLAndroidSDKTestApp:connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class="$$*"
|
||||
|
||||
# Symbolicate native stack trace with the specified abi
|
||||
.PHONY: android-ndk-stack-$1
|
||||
android-ndk-stack-$1: platform/android/configuration.gradle
|
||||
adb logcat | ndk-stack -sym platform/android/MapboxGLAndroidSDK/build/intermediates/cmake/debug/obj/$2/
|
||||
|
||||
endef
|
||||
|
||||
# Explodes the arguments into individual variables
|
||||
@@ -582,9 +595,9 @@ run-android-ui-test-%: run-android-ui-test-arm-v7-%
|
||||
# Run Java Unit tests on the JVM of the development machine executing this
|
||||
.PHONY: run-android-unit-test
|
||||
run-android-unit-test: platform/android/configuration.gradle
|
||||
cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDKTestApp:testDebugUnitTest
|
||||
cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:testDebugUnitTest
|
||||
run-android-unit-test-%: platform/android/configuration.gradle
|
||||
cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDKTestApp:testDebugUnitTest --tests "$*"
|
||||
cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:testDebugUnitTest --tests "$*"
|
||||
|
||||
# Run Instrumentation tests on AWS device farm, requires additional authentication through gradle.properties
|
||||
.PHONY: run-android-ui-test-aws
|
||||
@@ -641,6 +654,10 @@ android-lint-test-app: platform/android/configuration.gradle
|
||||
android-javadoc: platform/android/configuration.gradle
|
||||
cd platform/android && $(MBGL_ANDROID_GRADLE) -Pmapbox.abis=none :MapboxGLAndroidSDK:javadocrelease
|
||||
|
||||
# Symbolicate ndk stack traces for the arm-v7 abi
|
||||
.PHONY: android-ndk-stack
|
||||
android-ndk-stack: android-ndk-stack-arm-v7
|
||||
|
||||
# Open Android Studio if machine is macos
|
||||
ifeq ($(HOST_PLATFORM), macos)
|
||||
.PHONY: aproj
|
||||
|
||||
109
circle.yml
109
circle.yml
@@ -30,6 +30,10 @@ workflows:
|
||||
- linux-gcc5-debug-coverage
|
||||
- linux-gcc5-release-qt4
|
||||
- linux-gcc5-release-qt5
|
||||
- ios-debug
|
||||
#- ios-sanitize-address
|
||||
- ios-sanitize-thread
|
||||
- macos-debug
|
||||
|
||||
step-library:
|
||||
- &generate-cache-key
|
||||
@@ -47,7 +51,7 @@ step-library:
|
||||
- &save-cache
|
||||
save_cache:
|
||||
key: 'v3/{{ .Environment.CIRCLE_JOB }}/{{ arch }}/{{ .Branch }}/{{ checksum ".circle-week" }}'
|
||||
paths: [ "node_modules", "/root/.ccache", "mason_packages/.binaries" ]
|
||||
paths: [ "node_modules", "/root/.ccache", "~/.ccache", "mason_packages/.binaries" ]
|
||||
|
||||
|
||||
- &reset-ccache-stats
|
||||
@@ -97,6 +101,28 @@ step-library:
|
||||
run:
|
||||
name: Build qt-test
|
||||
command: make qt-test
|
||||
- &build-ios-test
|
||||
run:
|
||||
name: Build ios-test
|
||||
command: make ios-test
|
||||
- &build-macos-test
|
||||
run:
|
||||
name: Build and run macOS tests
|
||||
command: make run-test
|
||||
|
||||
|
||||
- &check-public-symbols
|
||||
run:
|
||||
name: Check public symbols
|
||||
command: make check-public-symbols
|
||||
|
||||
|
||||
- &install-macos-dependencies
|
||||
run:
|
||||
name: Install dependencies
|
||||
command: |
|
||||
brew install cmake
|
||||
brew install ccache
|
||||
|
||||
|
||||
- &run-node-tests
|
||||
@@ -225,7 +251,7 @@ jobs:
|
||||
--app platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug.apk \
|
||||
--test platform/android/MapboxGLAndroidSDKTestApp/build/outputs/apk/MapboxGLAndroidSDKTestApp-debug-androidTest.apk \
|
||||
--device-ids shamu --os-version-ids 22 --locales en --orientations portrait --timeout 20m \
|
||||
--test-targets "package com.mapbox.mapboxsdk.testapp.style" 2>&1 | tee firebase.log) || EXIT_CODE=$?
|
||||
2>&1 | tee firebase.log) || EXIT_CODE=$?
|
||||
|
||||
FIREBASE_TEST_BUCKET=$(sed -n 's|^.*\[https://console.developers.google.com/storage/browser/\([^]]*\).*|gs://\1|p' firebase.log)
|
||||
echo "Downloading from: ${FIREBASE_TEST_BUCKET}"
|
||||
@@ -294,7 +320,7 @@ jobs:
|
||||
- deploy:
|
||||
name: Publish to Maven
|
||||
command: |
|
||||
if [ "${CIRCLE_BRANCH}" == "master" ]; then make run-android-upload-archives ; fi
|
||||
if [ "${CIRCLE_BRANCH}" == "release-agua" ]; then make run-android-upload-archives ; fi
|
||||
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
@@ -589,3 +615,80 @@ jobs:
|
||||
command: |
|
||||
xvfb-run --server-args="-screen 0 1024x768x24" \
|
||||
scripts/valgrind.sh build/qt-linux-x86_64/Release/mbgl-test --gtest_filter=-*.Load --gtest_filter=-Memory.Vector
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
ios-debug:
|
||||
macos:
|
||||
xcode: "9.0"
|
||||
environment:
|
||||
BUILDTYPE: Debug
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
steps:
|
||||
- checkout
|
||||
- *install-macos-dependencies
|
||||
- *generate-cache-key
|
||||
- *restore-cache
|
||||
- *reset-ccache-stats
|
||||
- *build-ios-test
|
||||
- *check-public-symbols
|
||||
- *show-ccache-stats
|
||||
- *save-cache
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
ios-sanitize-address:
|
||||
macos:
|
||||
xcode: "9.0"
|
||||
environment:
|
||||
BUILDTYPE: Debug
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
steps:
|
||||
- checkout
|
||||
- *install-macos-dependencies
|
||||
- *generate-cache-key
|
||||
- *restore-cache
|
||||
- *reset-ccache-stats
|
||||
- run:
|
||||
name: Build and run SDK unit tests with address sanitizer
|
||||
command: make ios-sanitize-address
|
||||
- *show-ccache-stats
|
||||
- *save-cache
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
ios-sanitize-thread:
|
||||
macos:
|
||||
xcode: "9.0"
|
||||
environment:
|
||||
BUILDTYPE: Debug
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
steps:
|
||||
- checkout
|
||||
- *install-macos-dependencies
|
||||
- *generate-cache-key
|
||||
- *restore-cache
|
||||
- *reset-ccache-stats
|
||||
- run:
|
||||
name: Build and run SDK unit tests with thread sanitizer
|
||||
command: make ios-sanitize-thread
|
||||
- *show-ccache-stats
|
||||
- *save-cache
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
macos-debug:
|
||||
macos:
|
||||
xcode: "9.0"
|
||||
environment:
|
||||
BUILDTYPE: Debug
|
||||
HOMEBREW_NO_AUTO_UPDATE: 1
|
||||
steps:
|
||||
- checkout
|
||||
- *install-macos-dependencies
|
||||
- *generate-cache-key
|
||||
- *restore-cache
|
||||
- *reset-ccache-stats
|
||||
- *build-macos-test
|
||||
- *check-public-symbols
|
||||
- *show-ccache-stats
|
||||
- *save-cache
|
||||
- store_artifacts:
|
||||
path: test/fixtures
|
||||
destination: test/fixtures
|
||||
|
||||
@@ -40,6 +40,8 @@ public:
|
||||
std::vector<Feature> queryRenderedFeatures(const ScreenBox& box, const RenderedQueryOptions& options = {}) const;
|
||||
std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions& options = {}) const;
|
||||
AnnotationIDs queryPointAnnotations(const ScreenBox& box) const;
|
||||
AnnotationIDs queryShapeAnnotations(const ScreenBox& box) const;
|
||||
AnnotationIDs getAnnotationIDs(const std::vector<Feature>&) const;
|
||||
|
||||
// Debug
|
||||
void dumpDebugLogs();
|
||||
|
||||
@@ -4,11 +4,110 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to
|
||||
|
||||
## 5.2.0 - TBA
|
||||
|
||||
* Add support for ImageSource [#9110](https://github.com/mapbox/mapbox-gl-native/pull/9110)
|
||||
* Increased the default maximum zoom level from 20 to 22. ([#9835](https://github.com/mapbox/mapbox-gl-native/pull/9835))
|
||||
* Added `MapboxMap.getCameraForGeometry()` to get a camera with zoom level and center coordinate computed to fit a shape. ([#10107](https://github.com/mapbox/mapbox-gl-native/pull/10107))
|
||||
## 5.2.0-beta.4 - November 3, 2017
|
||||
|
||||
### 5.1.4 - September 25, 2017
|
||||
- Revert adding mapbox-android-core dependency (#10354) [#10380](https://github.com/mapbox/mapbox-gl-native/pull/10380)
|
||||
- Asynchronous TextureView [#10370](https://github.com/mapbox/mapbox-gl-native/pull/10370)
|
||||
- Workaround OkHttp bug on Android O [10366](https://github.com/mapbox/mapbox-gl-native/pull/10366)
|
||||
- Revisit logo resize [10553](https://github.com/mapbox/mapbox-gl-native/pull/10353)
|
||||
- Logo resize for MapSnapshotter [#10312](https://github.com/mapbox/mapbox-gl-native/pull/10312)
|
||||
- Make location provider optional [#10354](https://github.com/mapbox/mapbox-gl-native/pull/10354)
|
||||
- Check for positive animation value [#10348](https://github.com/mapbox/mapbox-gl-native/pull/10348)
|
||||
- Fix IAE of ease/animate [#10338](https://github.com/mapbox/mapbox-gl-native/pull/10338)
|
||||
- Run full test suite on CI [#10333](https://github.com/mapbox/mapbox-gl-native/pull/10333)
|
||||
- Make sure camera position gets updated in onFinish() callback after camera.move [#10324](https://github.com/mapbox/mapbox-gl-native/pull/10324)
|
||||
- throw IAE in animate() and easeCamera() when duration <= 0 [#10321](https://github.com/mapbox/mapbox-gl-native/pull/10321)
|
||||
- Don't save state if map hasn't been initialised [#10320](https://github.com/mapbox/mapbox-gl-native/pull/10320)
|
||||
- Make map snapshot optional [#10310](https://github.com/mapbox/mapbox-gl-native/pull/10310)
|
||||
- Synchronise locationlastions with Transifex [#10309](https://github.com/mapbox/mapbox-gl-native/pull/10309)
|
||||
- MapboxMap#addImages [#10281](https://github.com/mapbox/mapbox-gl-native/pull/10281)
|
||||
- Move shape annotation click handling to core [#10267](https://github.com/mapbox/mapbox-gl-native/pull/10267)
|
||||
- Map snapshotter additions [#10163](https://github.com/mapbox/mapbox-gl-native/pull/10163)
|
||||
- Add velocity to gestures / port animations to SDK animators [#10202](https://github.com/mapbox/mapbox-gl-native/pull/10202)
|
||||
- Don't save state if map hasn't been initialised [#10320](https://github.com/mapbox/mapbox-gl-native/pull/10320)
|
||||
- android.hardware.location.gps feature should not be required [#10347](https://github.com/mapbox/mapbox-gl-native/pull/10347)
|
||||
|
||||
## 5.2.0-beta.3 - October 26, 2017
|
||||
|
||||
- Reorganize dependencies [#10268](https://github.com/mapbox/mapbox-gl-native/pull/10268)
|
||||
- Blacklist VAO usage on adreno 3xx [#10291](https://github.com/mapbox/mapbox-gl-native/pull/10291)
|
||||
- On stop null check [#10259](https://github.com/mapbox/mapbox-gl-native/pull/10259)
|
||||
|
||||
## 5.2.0-beta.2 - October 19, 2017
|
||||
|
||||
- Wire up MapZoomButtonController with camera change events [#10221](https://github.com/mapbox/mapbox-gl-native/pull/10221)
|
||||
- Execute callbacks only when not idle [#10220](https://github.com/mapbox/mapbox-gl-native/pull/10220)
|
||||
- Cleanup unused gradle plugins [#10211](https://github.com/mapbox/mapbox-gl-native/pull/10211)
|
||||
- add FileSource pause/resume [#9977](https://github.com/mapbox/mapbox-gl-native/pull/9977)
|
||||
- add make target for ndk-stack [#10185](https://github.com/mapbox/mapbox-gl-native/pull/10185)
|
||||
- Add interpolator examples [#10067](https://github.com/mapbox/mapbox-gl-native/pull/10067)
|
||||
- Add an UnsatisfiedLinkError safeguard [#10180](https://github.com/mapbox/mapbox-gl-native/pull/10180)
|
||||
- Hold off handling hover events untill map has been created [#10142](https://github.com/mapbox/mapbox-gl-native/pull/10142)
|
||||
- Added `MapboxMap.getCameraForGeometry()` to get a camera with zoom level and center coordinate computed to fit a shape [#10107](https://github.com/mapbox/mapbox-gl-native/pull/10107)
|
||||
- Fine tune gesture zoom & rotation [#10134](https://github.com/mapbox/mapbox-gl-native/pull/10134)
|
||||
|
||||
## 5.2.0-beta.1 - October 6, 2017
|
||||
|
||||
- Allow multiple listeners for camera events, deprecate old API [#10141](https://github.com/mapbox/mapbox-gl-native/pull/10141)
|
||||
- Update symbol layer example with location [#10092](https://github.com/mapbox/mapbox-gl-native/pull/10092)
|
||||
- Make OfflineTilePyramidRegionDefinition parceable [#10080](https://github.com/mapbox/mapbox-gl-native/pull/10080)
|
||||
- Fix 5.2.0-SNAPSHOT CI build failing [#10079](https://github.com/mapbox/mapbox-gl-native/pull/10079)
|
||||
- Deprecate MarkerView [#9782](https://github.com/mapbox/mapbox-gl-native/pull/9782)
|
||||
- Hide overlain views on initalisation [#10068](https://github.com/mapbox/mapbox-gl-native/pull/10068)
|
||||
- API for platform side animations [#10001](https://github.com/mapbox/mapbox-gl-native/pull/10001)
|
||||
- Android asynchronous rendering [#9576](https://github.com/mapbox/mapbox-gl-native/pull/9576)
|
||||
- Set error handler when starting snapshotter [#10035](https://github.com/mapbox/mapbox-gl-native/pull/10035)
|
||||
- Hook camera events into compass [#10019](https://github.com/mapbox/mapbox-gl-native/pull/10019)
|
||||
- Testapp cleanup [#10006](https://github.com/mapbox/mapbox-gl-native/pull/10006)
|
||||
- Update zoom function example with selected state [#9987](https://github.com/mapbox/mapbox-gl-native/pull/9987)
|
||||
- Add style inspection to debug activity [#9773](https://github.com/mapbox/mapbox-gl-native/pull/9773)
|
||||
- Bump external dependencies [#9972](https://github.com/mapbox/mapbox-gl-native/pull/9972)
|
||||
- Don't recycle bitmap for icon reuse. [#9966](https://github.com/mapbox/mapbox-gl-native/pull/9966)
|
||||
- Android snapshotter [#9748](https://github.com/mapbox/mapbox-gl-native/pull/9748)
|
||||
- Revert #9764 [#9851](https://github.com/mapbox/mapbox-gl-native/pull/9851)
|
||||
- Update docs replacing Bitrise mentions with CircleCI [#9515](https://github.com/mapbox/mapbox-gl-native/pull/9515)
|
||||
- Style image accessor [#9763](https://github.com/mapbox/mapbox-gl-native/pull/9763)
|
||||
- Update readme with checkstyle and ndk-stack [#9788](https://github.com/mapbox/mapbox-gl-native/pull/9788)
|
||||
- make android-check [#9787](https://github.com/mapbox/mapbox-gl-native/pull/9787)
|
||||
- Deprecate MyLocationView in favor of LocationLayer plugin [#9771](https://github.com/mapbox/mapbox-gl-native/pull/9771)
|
||||
- Increase firebase timeout for CI testing [#9774](https://github.com/mapbox/mapbox-gl-native/pull/9774)
|
||||
- Restore max zoom to 25.5 [#9765](https://github.com/mapbox/mapbox-gl-native/pull/9765)
|
||||
- Update example of camera zoom function on a symbol layer. [#9743](https://github.com/mapbox/mapbox-gl-native/pull/9743)
|
||||
- Optimise icon management [#9643](https://github.com/mapbox/mapbox-gl-native/pull/9643)
|
||||
- Expose setStyleJson and getStyleJson [#9714](https://github.com/mapbox/mapbox-gl-native/pull/9714)
|
||||
- update LatLngBounds activity with BottomSheet interaction [#9736](https://github.com/mapbox/mapbox-gl-native/pull/9736)
|
||||
- post updating InfoWindow update for InfoWindowAdapter [#9716](https://github.com/mapbox/mapbox-gl-native/pull/9716)
|
||||
- Annotate MapboxMap class with UiThread [#9712](https://github.com/mapbox/mapbox-gl-native/pull/9712)
|
||||
- Move ZoomButtonController creation to view initalisation [#9587](https://github.com/mapbox/mapbox-gl-native/pull/9587)
|
||||
- Solve lint issues, reduce baseline [#9627](https://github.com/mapbox/mapbox-gl-native/pull/9627)
|
||||
- Remove wear module from project [#9618](https://github.com/mapbox/mapbox-gl-native/pull/9618)
|
||||
- Add zMediaOverlay configuration + bottom sheet integration [#9592](https://github.com/mapbox/mapbox-gl-native/pull/9592)
|
||||
- Forward getMapAsync to map for fragment [#9621](https://github.com/mapbox/mapbox-gl-native/pull/9621)
|
||||
- Make target for dumping system gfx information [#9616](https://github.com/mapbox/mapbox-gl-native/pull/9616)
|
||||
- Make target documentation [#9617](https://github.com/mapbox/mapbox-gl-native/pull/9617)
|
||||
- onGlobalLayout hook for map creation [#9607](https://github.com/mapbox/mapbox-gl-native/pull/9607)
|
||||
- Custom viewpager for horizontal swiping [#9601](https://github.com/mapbox/mapbox-gl-native/pull/9601)
|
||||
- Disable program caching on Adreno 3xx, 4xx, and 5xx GPUs due to known bugs [#9574](https://github.com/mapbox/mapbox-gl-native/pull/9574)
|
||||
- Avoid creating InfoWindow iterator if no InfoWindows are shown [#9477](https://github.com/mapbox/mapbox-gl-native/pull/9477)
|
||||
- Rewire map initialisation [#9462](https://github.com/mapbox/mapbox-gl-native/pull/9462)
|
||||
- Trying to update non-existent polyline fix [#9544](https://github.com/mapbox/mapbox-gl-native/pull/9544)
|
||||
- Location accuracy threshold [#9472](https://github.com/mapbox/mapbox-gl-native/pull/9472)
|
||||
- Rewire gesture handling and telemetry event push [#9494](https://github.com/mapbox/mapbox-gl-native/pull/9494)
|
||||
- run style instrumentation tests on CI [#9353](https://github.com/mapbox/mapbox-gl-native/pull/9353)
|
||||
- Fix javadoc comment for public setOfflineMapboxTileCountLimit method [#9454](https://github.com/mapbox/mapbox-gl-native/pull/9454)
|
||||
- add Map change & visibility test activities [#9425](https://github.com/mapbox/mapbox-gl-native/pull/9425)
|
||||
- build release package once during ci build [#9351](https://github.com/mapbox/mapbox-gl-native/pull/9351)
|
||||
- Add support for ImageSource [#9110](https://github.com/mapbox/mapbox-gl-native/pull/9110)
|
||||
- Increased the default maximum zoom level from 20 to 22. [#9835](https://github.com/mapbox/mapbox-gl-native/pull/9835)
|
||||
|
||||
## 5.1.5 - October 31, 2017
|
||||
|
||||
* Remove obsolete terminate context/display calls [#10162](https://github.com/mapbox/mapbox-gl-native/pull/10162)
|
||||
* Determine need for clip ID based on actual layers/tiles [#10216](https://github.com/mapbox/mapbox-gl-native/pull/10216)
|
||||
* Correctly alter sprite URLs [#10217](https://github.com/mapbox/mapbox-gl-native/pull/10217)
|
||||
* Russian and Ukrainian localizations [#9945](https://github.com/mapbox/mapbox-gl-native/pull/9945)
|
||||
|
||||
## 5.1.4 - September 25, 2017
|
||||
|
||||
* Update translations [#10033](https://github.com/mapbox/mapbox-gl-native/pull/10033) & [#9945](https://github.com/mapbox/mapbox-gl-native/pull/9945)
|
||||
* Continue rendering tiles despite erros [#10012](https://github.com/mapbox/mapbox-gl-native/pull/10012)
|
||||
@@ -101,7 +200,7 @@ Mapbox welcomes participation and contributions from everyone. If you'd like to
|
||||
* Infinite location animation updates [#9194](https://github.com/mapbox/mapbox-gl-native/pull/9194)
|
||||
* Invoke callback with valid fling gestures [#9192](https://github.com/mapbox/mapbox-gl-native/pull/9192)
|
||||
* Keep location tracking after screen rotation [#9187](https://github.com/mapbox/mapbox-gl-native/pull/9187)
|
||||
* Update components with camera values when animating [#9174](https://github.com/mapbox/mapbox-gl-native/pull/9174)
|
||||
* Update components with camera values when animating [#9174](https://github.com/mapbox/mapbox-gl-native/pull/9174)
|
||||
* Validate if gestures should execute [#9173](https://github.com/mapbox/mapbox-gl-native/pull/9173)
|
||||
* Custom location source and LOST integration [#9142](https://github.com/mapbox/mapbox-gl-native/pull/9142)
|
||||
|
||||
@@ -503,12 +602,6 @@ Mapbox Android 4.0.0 is the most ambitious Android release to date with 3 major
|
||||
- Satellite Streets Style ([#2739](https://github.com/mapbox/mapbox-gl-native/issues/2739))
|
||||
- **RESOLVED** Black Screen On Ice Cream Sandwich and Jelly Bean devices ([#2802](https://github.com/mapbox/mapbox-gl-native/issues/2802))
|
||||
|
||||
|
||||
## 2.1.0 - October 21, 2015
|
||||
|
||||
- Initial Android release.
|
||||
|
||||
Known issues:
|
||||
|
||||
- Black Screen On Ice Cream Sandwich and Jelly Bean devices ([#2802](https://github.com/mapbox/mapbox-gl-native/issues/2802))
|
||||
- Resolved in 2.2.0
|
||||
|
||||
@@ -2,8 +2,7 @@ apply plugin: 'com.android.library'
|
||||
|
||||
dependencies {
|
||||
compile rootProject.ext.dep.supportAnnotations
|
||||
compile rootProject.ext.dep.supportV4
|
||||
compile rootProject.ext.dep.supportDesign
|
||||
compile rootProject.ext.dep.supportFragmentV4
|
||||
compile rootProject.ext.dep.timber
|
||||
compile rootProject.ext.dep.okhttp3
|
||||
provided(rootProject.ext.dep.lost) {
|
||||
@@ -21,6 +20,7 @@ dependencies {
|
||||
// Mapbox Android Services (Telemetry support)
|
||||
compile(rootProject.ext.dep.mapboxAndroidTelemetry) {
|
||||
transitive = true
|
||||
exclude group: 'com.android.support'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
|
||||
<uses-feature android:name="android.hardware.wifi" android:required="false" /> <!-- Implied by ACCESS_WIFI_STATE. -->
|
||||
<uses-feature android:name="android.hardware.location.gps" android:required="false"/>
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package com.mapbox.mapboxsdk;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
/**
|
||||
* Centralises the knowledge about "mapbox-gl" library loading.
|
||||
*/
|
||||
@@ -9,7 +11,10 @@ public class LibraryLoader {
|
||||
* Loads "libmapbox-gl.so" native shared library.
|
||||
*/
|
||||
public static void load() {
|
||||
System.loadLibrary("mapbox-gl");
|
||||
try {
|
||||
System.loadLibrary("mapbox-gl");
|
||||
} catch (UnsatisfiedLinkError error) {
|
||||
Timber.e(error, "Failed to load native shared library.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -80,12 +80,12 @@ public class MapboxConstants {
|
||||
/**
|
||||
* The currently used minimun scale factor to clamp to when a quick zoom gesture occurs
|
||||
*/
|
||||
public static final float MINIMUM_SCALE_FACTOR_CLAMP = 0.65f;
|
||||
public static final float MINIMUM_SCALE_FACTOR_CLAMP = 0.00f;
|
||||
|
||||
/**
|
||||
* The currently used maximum scale factor to clamp to when a quick zoom gesture occurs
|
||||
*/
|
||||
public static final float MAXIMUM_SCALE_FACTOR_CLAMP = 1.35f;
|
||||
public static final float MAXIMUM_SCALE_FACTOR_CLAMP = 0.45f;
|
||||
|
||||
/**
|
||||
* Fragment Argument Key for MapboxMapOptions
|
||||
|
||||
@@ -85,7 +85,14 @@ class HTTPRequest implements Callback {
|
||||
}
|
||||
mRequest = builder.build();
|
||||
mCall = mClient.newCall(mRequest);
|
||||
mCall.enqueue(this);
|
||||
|
||||
// TODO remove code block for workaround in #10303
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.N_MR1) {
|
||||
mCall.enqueue(this);
|
||||
} else {
|
||||
// Calling execute instead of enqueue is a workaround for #10303
|
||||
onResponse(mCall, mCall.execute());
|
||||
}
|
||||
} catch (Exception exception) {
|
||||
onFailure(exception);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ import com.mapbox.mapboxsdk.annotations.Polygon;
|
||||
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.Polyline;
|
||||
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
|
||||
import com.mapbox.services.commons.geojson.Feature;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -41,7 +40,6 @@ import timber.log.Timber;
|
||||
*/
|
||||
class AnnotationManager {
|
||||
|
||||
private static final String LAYER_ID_SHAPE_ANNOTATIONS = "com.mapbox.annotations.shape.";
|
||||
private static final long NO_ANNOTATION_ID = -1;
|
||||
|
||||
private final MapView mapView;
|
||||
@@ -50,7 +48,6 @@ class AnnotationManager {
|
||||
private final MarkerViewManager markerViewManager;
|
||||
private final LongSparseArray<Annotation> annotationsArray;
|
||||
private final List<Marker> selectedMarkers = new ArrayList<>();
|
||||
private final List<String> shapeAnnotationIds = new ArrayList<>();
|
||||
|
||||
private MapboxMap mapboxMap;
|
||||
private MapboxMap.OnMarkerClickListener onMarkerClickListener;
|
||||
@@ -58,13 +55,14 @@ class AnnotationManager {
|
||||
private MapboxMap.OnPolylineClickListener onPolylineClickListener;
|
||||
|
||||
private Annotations annotations;
|
||||
private ShapeAnnotations shapeAnnotations;
|
||||
private Markers markers;
|
||||
private Polygons polygons;
|
||||
private Polylines polylines;
|
||||
|
||||
AnnotationManager(NativeMapView view, MapView mapView, LongSparseArray<Annotation> annotationsArray,
|
||||
MarkerViewManager markerViewManager, IconManager iconManager, Annotations annotations,
|
||||
Markers markers, Polygons polygons, Polylines polylines) {
|
||||
Markers markers, Polygons polygons, Polylines polylines, ShapeAnnotations shapeAnnotations) {
|
||||
this.mapView = mapView;
|
||||
this.annotationsArray = annotationsArray;
|
||||
this.markerViewManager = markerViewManager;
|
||||
@@ -73,6 +71,7 @@ class AnnotationManager {
|
||||
this.markers = markers;
|
||||
this.polygons = polygons;
|
||||
this.polylines = polylines;
|
||||
this.shapeAnnotations = shapeAnnotations;
|
||||
if (view != null) {
|
||||
// null checking needed for unit tests
|
||||
view.addOnMapChangedListener(markerViewManager);
|
||||
@@ -122,9 +121,6 @@ class AnnotationManager {
|
||||
// do icon cleanup
|
||||
iconManager.iconCleanup(marker.getIcon());
|
||||
}
|
||||
} else {
|
||||
// instanceOf Polygon/Polyline
|
||||
shapeAnnotationIds.remove(annotation.getId());
|
||||
}
|
||||
annotations.removeBy(annotation);
|
||||
}
|
||||
@@ -143,9 +139,6 @@ class AnnotationManager {
|
||||
} else {
|
||||
iconManager.iconCleanup(marker.getIcon());
|
||||
}
|
||||
} else {
|
||||
// instanceOf Polygon/Polyline
|
||||
shapeAnnotationIds.remove(annotation.getId());
|
||||
}
|
||||
}
|
||||
annotations.removeBy(annotationList);
|
||||
@@ -167,9 +160,6 @@ class AnnotationManager {
|
||||
} else {
|
||||
iconManager.iconCleanup(marker.getIcon());
|
||||
}
|
||||
} else {
|
||||
// instanceOf Polygon/Polyline
|
||||
shapeAnnotationIds.remove(annotation.getId());
|
||||
}
|
||||
}
|
||||
annotations.removeAll();
|
||||
@@ -227,17 +217,11 @@ class AnnotationManager {
|
||||
//
|
||||
|
||||
Polygon addPolygon(@NonNull PolygonOptions polygonOptions, @NonNull MapboxMap mapboxMap) {
|
||||
Polygon polygon = polygons.addBy(polygonOptions, mapboxMap);
|
||||
shapeAnnotationIds.add(LAYER_ID_SHAPE_ANNOTATIONS + polygon.getId());
|
||||
return polygon;
|
||||
return polygons.addBy(polygonOptions, mapboxMap);
|
||||
}
|
||||
|
||||
List<Polygon> addPolygons(@NonNull List<PolygonOptions> polygonOptionsList, @NonNull MapboxMap mapboxMap) {
|
||||
List<Polygon> polygonList = polygons.addBy(polygonOptionsList, mapboxMap);
|
||||
for (Polygon polygon : polygonList) {
|
||||
shapeAnnotationIds.add(LAYER_ID_SHAPE_ANNOTATIONS + polygon.getId());
|
||||
}
|
||||
return polygonList;
|
||||
return polygons.addBy(polygonOptionsList, mapboxMap);
|
||||
}
|
||||
|
||||
void updatePolygon(Polygon polygon) {
|
||||
@@ -257,17 +241,11 @@ class AnnotationManager {
|
||||
//
|
||||
|
||||
Polyline addPolyline(@NonNull PolylineOptions polylineOptions, @NonNull MapboxMap mapboxMap) {
|
||||
Polyline polyline = polylines.addBy(polylineOptions, mapboxMap);
|
||||
shapeAnnotationIds.add(LAYER_ID_SHAPE_ANNOTATIONS + polyline.getId());
|
||||
return polyline;
|
||||
return polylines.addBy(polylineOptions, mapboxMap);
|
||||
}
|
||||
|
||||
List<Polyline> addPolylines(@NonNull List<PolylineOptions> polylineOptionsList, @NonNull MapboxMap mapboxMap) {
|
||||
List<Polyline> polylineList = polylines.addBy(polylineOptionsList, mapboxMap);
|
||||
for (Polyline polyline : polylineList) {
|
||||
shapeAnnotationIds.add(LAYER_ID_SHAPE_ANNOTATIONS + polyline.getId());
|
||||
}
|
||||
return polylineList;
|
||||
return polylines.addBy(polylineOptionsList, mapboxMap);
|
||||
}
|
||||
|
||||
void updatePolyline(Polyline polyline) {
|
||||
@@ -397,11 +375,11 @@ class AnnotationManager {
|
||||
//
|
||||
|
||||
boolean onTap(PointF tapPoint) {
|
||||
if (!shapeAnnotationIds.isEmpty()) {
|
||||
ShapeAnnotationHit shapeAnnotationHit = getShapeAnnotationHitFromTap(tapPoint);
|
||||
long shapeAnnotationId = new ShapeAnnotationHitResolver(mapboxMap).execute(shapeAnnotationHit);
|
||||
if (shapeAnnotationId != NO_ANNOTATION_ID) {
|
||||
handleClickForShapeAnnotation(shapeAnnotationId);
|
||||
ShapeAnnotationHit shapeAnnotationHit = getShapeAnnotationHitFromTap(tapPoint);
|
||||
Annotation annotation = new ShapeAnnotationHitResolver(shapeAnnotations).execute(shapeAnnotationHit);
|
||||
if (annotation != null) {
|
||||
if (handleClickForShapeAnnotation(annotation)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -418,16 +396,18 @@ class AnnotationManager {
|
||||
tapPoint.x + touchTargetSide,
|
||||
tapPoint.y + touchTargetSide
|
||||
);
|
||||
return new ShapeAnnotationHit(tapRect, shapeAnnotationIds.toArray(new String[shapeAnnotationIds.size()]));
|
||||
return new ShapeAnnotationHit(tapRect);
|
||||
}
|
||||
|
||||
private void handleClickForShapeAnnotation(long shapeAnnotationId) {
|
||||
Annotation annotation = getAnnotation(shapeAnnotationId);
|
||||
private boolean handleClickForShapeAnnotation(Annotation annotation) {
|
||||
if (annotation instanceof Polygon && onPolygonClickListener != null) {
|
||||
onPolygonClickListener.onPolygonClick((Polygon) annotation);
|
||||
return true;
|
||||
} else if (annotation instanceof Polyline && onPolylineClickListener != null) {
|
||||
onPolylineClickListener.onPolylineClick((Polyline) annotation);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private MarkerHit getMarkerHitFromTouchArea(PointF tapPoint) {
|
||||
@@ -470,28 +450,19 @@ class AnnotationManager {
|
||||
|
||||
private static class ShapeAnnotationHitResolver {
|
||||
|
||||
private MapboxMap mapboxMap;
|
||||
private ShapeAnnotations shapeAnnotations;
|
||||
|
||||
ShapeAnnotationHitResolver(MapboxMap mapboxMap) {
|
||||
this.mapboxMap = mapboxMap;
|
||||
ShapeAnnotationHitResolver(ShapeAnnotations shapeAnnotations) {
|
||||
this.shapeAnnotations = shapeAnnotations;
|
||||
}
|
||||
|
||||
public long execute(ShapeAnnotationHit shapeHit) {
|
||||
long foundAnnotationId = NO_ANNOTATION_ID;
|
||||
List<Feature> features = mapboxMap.queryRenderedFeatures(shapeHit.tapPoint, shapeHit.layerIds);
|
||||
if (!features.isEmpty()) {
|
||||
foundAnnotationId = getIdFromFeature(features.get(0));
|
||||
}
|
||||
return foundAnnotationId;
|
||||
}
|
||||
|
||||
private long getIdFromFeature(Feature feature) {
|
||||
try {
|
||||
return Long.valueOf(feature.getId());
|
||||
} catch (NumberFormatException exception) {
|
||||
Timber.e(exception, "Couldn't parse feature id to a long, with id: %s", feature.getId());
|
||||
return NO_ANNOTATION_ID;
|
||||
public Annotation execute(ShapeAnnotationHit shapeHit) {
|
||||
Annotation foundAnnotation = null;
|
||||
List<Annotation> annotations = shapeAnnotations.obtainAllIn(shapeHit.tapPoint);
|
||||
if (annotations.size() > 0) {
|
||||
foundAnnotation = annotations.get(0);
|
||||
}
|
||||
return foundAnnotation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -567,11 +538,9 @@ class AnnotationManager {
|
||||
|
||||
private static class ShapeAnnotationHit {
|
||||
private final RectF tapPoint;
|
||||
private final String[] layerIds;
|
||||
|
||||
ShapeAnnotationHit(RectF tapRect, String[] layerIds) {
|
||||
this.tapPoint = tapRect;
|
||||
this.layerIds = layerIds;
|
||||
ShapeAnnotationHit(RectF tapPoint) {
|
||||
this.tapPoint = tapPoint;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
package com.mapbox.mapboxsdk.maps;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.Html;
|
||||
import android.text.SpannableStringBuilder;
|
||||
import android.text.TextUtils;
|
||||
@@ -56,7 +56,7 @@ class AttributionDialogManager implements View.OnClickListener, DialogInterface.
|
||||
|
||||
private void showAttributionDialog() {
|
||||
attributionKeys = attributionMap.keySet().toArray(new String[attributionMap.size()]);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.mapbox_AlertDialogStyle);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.mapbox_attributionsDialogTitle);
|
||||
builder.setAdapter(new ArrayAdapter<>(context, R.layout.mapbox_attribution_list_item, attributionKeys), this);
|
||||
builder.show();
|
||||
@@ -77,7 +77,7 @@ class AttributionDialogManager implements View.OnClickListener, DialogInterface.
|
||||
}
|
||||
|
||||
private void showTelemetryDialog() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context, R.style.mapbox_AlertDialogStyle);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.mapbox_attributionTelemetryTitle);
|
||||
builder.setMessage(R.string.mapbox_attributionTelemetryMessage);
|
||||
builder.setPositiveButton(R.string.mapbox_attributionTelemetryPositive, new DialogInterface.OnClickListener() {
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
package com.mapbox.mapboxsdk.maps;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraIdleListener;
|
||||
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveCanceledListener;
|
||||
import static com.mapbox.mapboxsdk.maps.MapboxMap.OnCameraMoveListener;
|
||||
@@ -10,23 +15,32 @@ class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, M
|
||||
|
||||
private boolean idle = true;
|
||||
|
||||
private final List<OnCameraMoveStartedListener> onCameraMoveStartedListenerList = new ArrayList<>();
|
||||
private final List<OnCameraMoveCanceledListener> onCameraMoveCanceledListenerList = new ArrayList<>();
|
||||
private final List<OnCameraMoveListener> onCameraMoveListenerList = new ArrayList<>();
|
||||
private final List<OnCameraIdleListener> onCameraIdleListenerList = new ArrayList<>();
|
||||
|
||||
private OnCameraMoveStartedListener onCameraMoveStartedListener;
|
||||
private OnCameraMoveCanceledListener onCameraMoveCanceledListener;
|
||||
private OnCameraMoveListener onCameraMoveListener;
|
||||
private OnCameraIdleListener onCameraIdleListener;
|
||||
|
||||
@Deprecated
|
||||
void setOnCameraMoveStartedListener(OnCameraMoveStartedListener onCameraMoveStartedListener) {
|
||||
this.onCameraMoveStartedListener = onCameraMoveStartedListener;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
void setOnCameraMoveCanceledListener(OnCameraMoveCanceledListener onCameraMoveCanceledListener) {
|
||||
this.onCameraMoveCanceledListener = onCameraMoveCanceledListener;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
void setOnCameraMoveListener(OnCameraMoveListener onCameraMoveListener) {
|
||||
this.onCameraMoveListener = onCameraMoveListener;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
void setOnCameraIdleListener(OnCameraIdleListener onCameraIdleListener) {
|
||||
this.onCameraIdleListener = onCameraIdleListener;
|
||||
}
|
||||
@@ -36,34 +50,106 @@ class CameraChangeDispatcher implements MapboxMap.OnCameraMoveStartedListener, M
|
||||
if (!idle) {
|
||||
return;
|
||||
}
|
||||
|
||||
idle = false;
|
||||
|
||||
// deprecated API
|
||||
if (onCameraMoveStartedListener != null) {
|
||||
onCameraMoveStartedListener.onCameraMoveStarted(reason);
|
||||
}
|
||||
|
||||
// new API
|
||||
if (!onCameraMoveStartedListenerList.isEmpty()) {
|
||||
for (OnCameraMoveStartedListener cameraMoveStartedListener : onCameraMoveStartedListenerList) {
|
||||
cameraMoveStartedListener.onCameraMoveStarted(reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraMove() {
|
||||
// deprecated API
|
||||
if (onCameraMoveListener != null && !idle) {
|
||||
onCameraMoveListener.onCameraMove();
|
||||
}
|
||||
|
||||
// new API
|
||||
if (!onCameraMoveListenerList.isEmpty() && !idle) {
|
||||
for (OnCameraMoveListener cameraMoveListener : onCameraMoveListenerList) {
|
||||
cameraMoveListener.onCameraMove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraMoveCanceled() {
|
||||
// deprecated API
|
||||
if (onCameraMoveCanceledListener != null && !idle) {
|
||||
onCameraMoveCanceledListener.onCameraMoveCanceled();
|
||||
}
|
||||
|
||||
// new API
|
||||
if (!onCameraMoveCanceledListenerList.isEmpty() && !idle) {
|
||||
for (OnCameraMoveCanceledListener cameraMoveCanceledListener : onCameraMoveCanceledListenerList) {
|
||||
cameraMoveCanceledListener.onCameraMoveCanceled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCameraIdle() {
|
||||
if (!idle) {
|
||||
idle = true;
|
||||
// deprecated API
|
||||
if (onCameraIdleListener != null) {
|
||||
onCameraIdleListener.onCameraIdle();
|
||||
}
|
||||
|
||||
// new API
|
||||
if (!onCameraIdleListenerList.isEmpty()) {
|
||||
for (OnCameraIdleListener cameraIdleListener : onCameraIdleListenerList) {
|
||||
cameraIdleListener.onCameraIdle();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void addOnCameraIdleListener(@NonNull OnCameraIdleListener listener) {
|
||||
onCameraIdleListenerList.add(listener);
|
||||
}
|
||||
|
||||
void removeOnCameraIdleListener(@NonNull OnCameraIdleListener listener) {
|
||||
if (onCameraIdleListenerList.contains(listener)) {
|
||||
onCameraIdleListenerList.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
void addOnCameraMoveCancelListener(OnCameraMoveCanceledListener listener) {
|
||||
onCameraMoveCanceledListenerList.add(listener);
|
||||
}
|
||||
|
||||
void removeOnCameraMoveCancelListener(OnCameraMoveCanceledListener listener) {
|
||||
if (onCameraMoveCanceledListenerList.contains(listener)) {
|
||||
onCameraMoveCanceledListenerList.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
void addOnCameraMoveStartedListener(OnCameraMoveStartedListener listener) {
|
||||
onCameraMoveStartedListenerList.add(listener);
|
||||
}
|
||||
|
||||
void removeOnCameraMoveStartedListener(OnCameraMoveStartedListener listener) {
|
||||
if (onCameraMoveStartedListenerList.contains(listener)) {
|
||||
onCameraMoveStartedListenerList.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
void addOnCameraMoveListener(OnCameraMoveListener listener) {
|
||||
onCameraMoveListenerList.add(listener);
|
||||
}
|
||||
|
||||
void removeOnCameraMoveListener(OnCameraMoveListener listener) {
|
||||
if (onCameraMoveListenerList.contains(listener)) {
|
||||
onCameraMoveListenerList.remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,11 +143,14 @@ class IconManager {
|
||||
}
|
||||
|
||||
void iconCleanup(Icon icon) {
|
||||
int refCounter = iconMap.get(icon) - 1;
|
||||
if (refCounter == 0) {
|
||||
remove(icon);
|
||||
} else {
|
||||
updateIconRefCounter(icon, refCounter);
|
||||
Integer refCounter = iconMap.get(icon);
|
||||
if (refCounter != null) {
|
||||
refCounter--;
|
||||
if (refCounter == 0) {
|
||||
remove(icon);
|
||||
} else {
|
||||
updateIconRefCounter(icon, refCounter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.mapbox.mapboxsdk.maps;
|
||||
|
||||
class Image {
|
||||
private final byte[] buffer;
|
||||
private final float pixelRatio;
|
||||
private final String name;
|
||||
private final int width;
|
||||
private final int height;
|
||||
|
||||
public Image(byte[] buffer, float pixelRatio, String name, int width, int height) {
|
||||
this.buffer = buffer;
|
||||
this.pixelRatio = pixelRatio;
|
||||
this.name = name;
|
||||
this.width = width;
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,19 @@
|
||||
package com.mapbox.mapboxsdk.maps;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.location.Location;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v4.view.GestureDetectorCompat;
|
||||
import android.support.v4.view.ScaleGestureDetectorCompat;
|
||||
import android.support.v4.view.animation.FastOutSlowInInterpolator;
|
||||
import android.view.InputDevice;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ScaleGestureDetector;
|
||||
import android.view.VelocityTracker;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
import com.almeros.android.multitouch.gesturedetectors.RotateGestureDetector;
|
||||
@@ -57,8 +62,14 @@ final class MapGestureDetector {
|
||||
|
||||
private boolean scaleGestureOccurred;
|
||||
private boolean recentScaleGestureOccurred;
|
||||
private boolean scaleAnimating;
|
||||
private long scaleBeginTime;
|
||||
|
||||
private VelocityTracker velocityTracker;
|
||||
private boolean wasZoomingIn;
|
||||
private boolean wasClockwiseRotating;
|
||||
private boolean rotateGestureOccurred;
|
||||
|
||||
MapGestureDetector(Context context, Transform transform, Projection projection, UiSettings uiSettings,
|
||||
TrackingSettings trackingSettings, AnnotationManager annotationManager,
|
||||
CameraChangeDispatcher cameraChangeDispatcher) {
|
||||
@@ -153,6 +164,12 @@ final class MapGestureDetector {
|
||||
// Handle two finger tap
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
if (velocityTracker == null) {
|
||||
velocityTracker = VelocityTracker.obtain();
|
||||
} else {
|
||||
velocityTracker.clear();
|
||||
}
|
||||
velocityTracker.addMovement(event);
|
||||
// First pointer down, reset scaleGestureOccurred, used to avoid triggering a fling after a scale gesture #7666
|
||||
recentScaleGestureOccurred = false;
|
||||
transform.setGestureInProgress(true);
|
||||
@@ -203,11 +220,23 @@ final class MapGestureDetector {
|
||||
|
||||
twoTap = false;
|
||||
transform.setGestureInProgress(false);
|
||||
if (velocityTracker != null) {
|
||||
velocityTracker.recycle();
|
||||
}
|
||||
velocityTracker = null;
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
twoTap = false;
|
||||
transform.setGestureInProgress(false);
|
||||
if (velocityTracker != null) {
|
||||
velocityTracker.recycle();
|
||||
}
|
||||
velocityTracker = null;
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
velocityTracker.addMovement(event);
|
||||
velocityTracker.computeCurrentVelocity(1000);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -430,7 +459,11 @@ final class MapGestureDetector {
|
||||
*/
|
||||
private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
|
||||
|
||||
private static final int ANIMATION_TIME_MULTIPLIER = 77;
|
||||
private static final double ZOOM_DISTANCE_DIVIDER = 5;
|
||||
|
||||
private float scaleFactor = 1.0f;
|
||||
private PointF scalePointBegin;
|
||||
|
||||
// Called when two fingers first touch the screen
|
||||
@Override
|
||||
@@ -440,6 +473,7 @@ final class MapGestureDetector {
|
||||
}
|
||||
|
||||
recentScaleGestureOccurred = true;
|
||||
scalePointBegin = new PointF(detector.getFocusX(), detector.getFocusY());
|
||||
scaleBeginTime = detector.getEventTime();
|
||||
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
|
||||
getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
|
||||
@@ -447,15 +481,6 @@ final class MapGestureDetector {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called when fingers leave screen
|
||||
@Override
|
||||
public void onScaleEnd(ScaleGestureDetector detector) {
|
||||
scaleGestureOccurred = false;
|
||||
scaleBeginTime = 0;
|
||||
scaleFactor = 1.0f;
|
||||
cameraChangeDispatcher.onCameraIdle();
|
||||
}
|
||||
|
||||
// Called each time a finger moves
|
||||
// Called for pinch zooms and quickzooms/quickscales
|
||||
@Override
|
||||
@@ -464,6 +489,7 @@ final class MapGestureDetector {
|
||||
return super.onScale(detector);
|
||||
}
|
||||
|
||||
wasZoomingIn = (Math.log(detector.getScaleFactor()) / Math.log(Math.PI / 2)) >= 0;
|
||||
if (tiltGestureOccurred) {
|
||||
return false;
|
||||
}
|
||||
@@ -478,7 +504,7 @@ final class MapGestureDetector {
|
||||
|
||||
// If scale is large enough ignore a tap
|
||||
scaleFactor *= detector.getScaleFactor();
|
||||
if ((scaleFactor > 1.05f) || (scaleFactor < 0.95f)) {
|
||||
if ((scaleFactor > 1.1f) || (scaleFactor < 0.9f)) {
|
||||
// notify camera change listener
|
||||
cameraChangeDispatcher.onCameraMoveStarted(REASON_API_GESTURE);
|
||||
scaleGestureOccurred = true;
|
||||
@@ -497,7 +523,6 @@ final class MapGestureDetector {
|
||||
// make an assumption here; if the zoom center is specified by the gesture, it's NOT going
|
||||
// to be in the center of the map. Therefore the zoom will translate the map center, so tracking
|
||||
// should be disabled.
|
||||
|
||||
trackingSettings.resetTrackingModesIfRequired(!quickZoom, false, false);
|
||||
// Scale the map
|
||||
if (focalPoint != null) {
|
||||
@@ -506,19 +531,79 @@ final class MapGestureDetector {
|
||||
} else if (quickZoom) {
|
||||
cameraChangeDispatcher.onCameraMove();
|
||||
// clamp scale factors we feed to core #7514
|
||||
float scaleFactor = MathUtils.clamp(detector.getScaleFactor(),
|
||||
float scaleFactor = detector.getScaleFactor();
|
||||
// around center map
|
||||
double zoomBy = Math.log(scaleFactor) / Math.log(Math.PI / 2);
|
||||
boolean negative = zoomBy < 0;
|
||||
zoomBy = MathUtils.clamp(Math.abs(zoomBy),
|
||||
MapboxConstants.MINIMUM_SCALE_FACTOR_CLAMP,
|
||||
MapboxConstants.MAXIMUM_SCALE_FACTOR_CLAMP);
|
||||
// around center map
|
||||
transform.zoomBy(Math.log(scaleFactor) / Math.log(Math.PI / 2),
|
||||
uiSettings.getWidth() / 2, uiSettings.getHeight() / 2);
|
||||
transform.zoomBy(negative ? -zoomBy : zoomBy, uiSettings.getWidth() / 2, uiSettings.getHeight() / 2);
|
||||
recentScaleGestureOccurred = true;
|
||||
} else {
|
||||
// around gesture
|
||||
transform.zoomBy(Math.log(detector.getScaleFactor()) / Math.log(Math.PI / 2),
|
||||
detector.getFocusX(), detector.getFocusY());
|
||||
scalePointBegin.x, scalePointBegin.y);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called when fingers leave screen
|
||||
@Override
|
||||
public void onScaleEnd(final ScaleGestureDetector detector) {
|
||||
if (rotateGestureOccurred || quickZoom) {
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
double velocityXY = Math.abs(velocityTracker.getYVelocity()) + Math.abs(velocityTracker.getXVelocity());
|
||||
if (velocityXY > MapboxConstants.VELOCITY_THRESHOLD_IGNORE_FLING / 2) {
|
||||
scaleAnimating = true;
|
||||
double zoomAddition = calculateScale(velocityXY);
|
||||
double currentZoom = transform.getRawZoom();
|
||||
long animationTime = (long) (Math.log(velocityXY) * ANIMATION_TIME_MULTIPLIER);
|
||||
createScaleAnimator(currentZoom, zoomAddition, animationTime).start();
|
||||
} else if (!scaleAnimating) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
scaleAnimating = false;
|
||||
scaleGestureOccurred = false;
|
||||
scaleBeginTime = 0;
|
||||
scaleFactor = 1.0f;
|
||||
cameraChangeDispatcher.onCameraIdle();
|
||||
}
|
||||
|
||||
private double calculateScale(double velocityXY) {
|
||||
double zoomAddition = (float) (Math.log(velocityXY) / ZOOM_DISTANCE_DIVIDER);
|
||||
if (!wasZoomingIn) {
|
||||
zoomAddition = -zoomAddition;
|
||||
}
|
||||
return zoomAddition;
|
||||
}
|
||||
|
||||
private Animator createScaleAnimator(double currentZoom, double zoomAddition, long animationTime) {
|
||||
ValueAnimator animator = ValueAnimator.ofFloat((float) currentZoom, (float) (currentZoom + zoomAddition));
|
||||
animator.setDuration(animationTime);
|
||||
animator.setInterpolator(new FastOutSlowInInterpolator());
|
||||
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
transform.setZoom((Float) animation.getAnimatedValue(), scalePointBegin);
|
||||
}
|
||||
});
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
reset();
|
||||
}
|
||||
});
|
||||
return animator;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -526,11 +611,13 @@ final class MapGestureDetector {
|
||||
*/
|
||||
private class RotateGestureListener extends RotateGestureDetector.SimpleOnRotateGestureListener {
|
||||
|
||||
private static final long ROTATE_INVOKE_WAIT_TIME = 1500;
|
||||
private static final float ROTATE_INVOKE_ANGLE = 15.30f;
|
||||
private static final float ROTATE_LIMITATION_ANGLE = 3.35f;
|
||||
private static final float ROTATE_LIMITATION_DURATION = ROTATE_LIMITATION_ANGLE * 1.85f;
|
||||
|
||||
private long beginTime = 0;
|
||||
private float totalAngle = 0.0f;
|
||||
private boolean started = false;
|
||||
private boolean animating = false;
|
||||
|
||||
// Called when two fingers first touch the screen
|
||||
@Override
|
||||
@@ -546,15 +633,6 @@ final class MapGestureDetector {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Called when the fingers leave the screen
|
||||
@Override
|
||||
public void onRotateEnd(RotateGestureDetector detector) {
|
||||
// notify camera change listener
|
||||
beginTime = 0;
|
||||
totalAngle = 0.0f;
|
||||
started = false;
|
||||
}
|
||||
|
||||
// Called each time one of the two fingers moves
|
||||
// Called for rotation
|
||||
@Override
|
||||
@@ -563,18 +641,10 @@ final class MapGestureDetector {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Ignore short touches in case it is a tap
|
||||
// Also ignore small rotate
|
||||
long time = detector.getEventTime();
|
||||
long interval = time - beginTime;
|
||||
if (!started && (interval <= ViewConfiguration.getTapTimeout() || isScaleGestureActive(time))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If rotate is large enough ignore a tap
|
||||
// Also is zoom already started, don't rotate
|
||||
totalAngle += detector.getRotationDegreesDelta();
|
||||
if (totalAngle > 35.0f || totalAngle < -35.0f) {
|
||||
float angle = detector.getRotationDegreesDelta();
|
||||
if (Math.abs(angle) >= ROTATE_INVOKE_ANGLE) {
|
||||
MapboxTelemetry.getInstance().pushEvent(MapboxEventWrapper.buildMapClickEvent(
|
||||
getLocationFromGesture(detector.getFocusX(), detector.getFocusY()),
|
||||
MapboxEvent.GESTURE_ROTATION_START, transform));
|
||||
@@ -585,13 +655,17 @@ final class MapGestureDetector {
|
||||
return false;
|
||||
}
|
||||
|
||||
wasClockwiseRotating = detector.getRotationDegreesDelta() > 0;
|
||||
if (scaleBeginTime != 0) {
|
||||
rotateGestureOccurred = true;
|
||||
}
|
||||
|
||||
// rotation constitutes translation of anything except the center of
|
||||
// rotation, so cancel both location and bearing tracking if required
|
||||
trackingSettings.resetTrackingModesIfRequired(true, true, false);
|
||||
|
||||
// Get rotate value
|
||||
double bearing = transform.getRawBearing();
|
||||
bearing += detector.getRotationDegreesDelta();
|
||||
// Calculate map bearing value
|
||||
double bearing = transform.getRawBearing() + angle;
|
||||
|
||||
// Rotate the map
|
||||
if (focalPoint != null) {
|
||||
@@ -604,11 +678,81 @@ final class MapGestureDetector {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isScaleGestureActive(long time) {
|
||||
long scaleExecutionTime = time - scaleBeginTime;
|
||||
boolean scaleGestureStarted = scaleBeginTime != 0;
|
||||
boolean scaleOffsetTimeValid = scaleExecutionTime > ROTATE_INVOKE_WAIT_TIME;
|
||||
return (scaleGestureStarted && scaleOffsetTimeValid) || scaleGestureOccurred;
|
||||
// Called when the fingers leave the screen
|
||||
@Override
|
||||
public void onRotateEnd(RotateGestureDetector detector) {
|
||||
long interval = detector.getEventTime() - beginTime;
|
||||
if ((!started && (interval <= ViewConfiguration.getTapTimeout())) || scaleAnimating || interval > 500) {
|
||||
reset();
|
||||
return;
|
||||
}
|
||||
|
||||
double angularVelocity = calculateVelocityVector(detector);
|
||||
if (Math.abs(angularVelocity) > 0.001 && rotateGestureOccurred && !animating) {
|
||||
animateRotateVelocity();
|
||||
} else if (!animating) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
beginTime = 0;
|
||||
started = false;
|
||||
animating = false;
|
||||
rotateGestureOccurred = false;
|
||||
}
|
||||
|
||||
private void animateRotateVelocity() {
|
||||
animating = true;
|
||||
double currentRotation = transform.getRawBearing();
|
||||
double rotateAdditionDegrees = calculateVelocityInDegrees();
|
||||
createAnimator(currentRotation, rotateAdditionDegrees).start();
|
||||
}
|
||||
|
||||
private double calculateVelocityVector(RotateGestureDetector detector) {
|
||||
return ((detector.getFocusX() * velocityTracker.getYVelocity())
|
||||
+ (detector.getFocusY() * velocityTracker.getXVelocity()))
|
||||
/ (Math.pow(detector.getFocusX(), 2) + Math.pow(detector.getFocusY(), 2));
|
||||
}
|
||||
|
||||
private double calculateVelocityInDegrees() {
|
||||
double angleRadians = Math.atan2(velocityTracker.getXVelocity(), velocityTracker.getYVelocity());
|
||||
double angle = angleRadians / (Math.PI / 180);
|
||||
if (angle <= 0) {
|
||||
angle += 360;
|
||||
}
|
||||
|
||||
// limit the angle
|
||||
angle = angle / ROTATE_LIMITATION_ANGLE;
|
||||
|
||||
// correct direction
|
||||
if (!wasClockwiseRotating) {
|
||||
angle = -angle;
|
||||
}
|
||||
|
||||
return angle;
|
||||
}
|
||||
|
||||
private Animator createAnimator(double currentRotation, double rotateAdditionDegrees) {
|
||||
ValueAnimator animator = ValueAnimator.ofFloat(
|
||||
(float) currentRotation,
|
||||
(float) (currentRotation + rotateAdditionDegrees)
|
||||
);
|
||||
animator.setDuration((long) (Math.abs(rotateAdditionDegrees) * ROTATE_LIMITATION_DURATION));
|
||||
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
transform.setBearing((Float) animation.getAnimatedValue());
|
||||
}
|
||||
});
|
||||
animator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
super.onAnimationEnd(animation);
|
||||
reset();
|
||||
}
|
||||
});
|
||||
return animator;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,13 +28,14 @@ import com.mapbox.mapboxsdk.annotations.Annotation;
|
||||
import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
|
||||
import com.mapbox.mapboxsdk.constants.MapboxConstants;
|
||||
import com.mapbox.mapboxsdk.constants.Style;
|
||||
import com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.GLSurfaceViewMapRenderer;
|
||||
import com.mapbox.mapboxsdk.maps.renderer.MapRenderer;
|
||||
import com.mapbox.mapboxsdk.maps.renderer.glsurfaceview.GLSurfaceViewMapRenderer;
|
||||
import com.mapbox.mapboxsdk.maps.renderer.textureview.TextureViewMapRenderer;
|
||||
import com.mapbox.mapboxsdk.maps.widgets.CompassView;
|
||||
import com.mapbox.mapboxsdk.maps.widgets.MyLocationView;
|
||||
import com.mapbox.mapboxsdk.maps.widgets.MyLocationViewSettings;
|
||||
import com.mapbox.mapboxsdk.net.ConnectivityReceiver;
|
||||
import com.mapbox.mapboxsdk.storage.FileSource;
|
||||
import com.mapbox.services.android.telemetry.MapboxTelemetry;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -175,8 +176,9 @@ public class MapView extends FrameLayout {
|
||||
Markers markers = new MarkerContainer(nativeMapView, this, annotationsArray, iconManager, markerViewManager);
|
||||
Polygons polygons = new PolygonContainer(nativeMapView, annotationsArray);
|
||||
Polylines polylines = new PolylineContainer(nativeMapView, annotationsArray);
|
||||
ShapeAnnotations shapeAnnotations = new ShapeAnnotationContainer(nativeMapView, annotationsArray);
|
||||
AnnotationManager annotationManager = new AnnotationManager(nativeMapView, this, annotationsArray,
|
||||
markerViewManager, iconManager, annotations, markers, polygons, polylines);
|
||||
markerViewManager, iconManager, annotations, markers, polygons, polylines, shapeAnnotations);
|
||||
Transform transform = new Transform(nativeMapView, annotationManager.getMarkerViewManager(), trackingSettings,
|
||||
cameraChangeDispatcher);
|
||||
|
||||
@@ -191,8 +193,10 @@ public class MapView extends FrameLayout {
|
||||
annotationManager, cameraChangeDispatcher);
|
||||
mapKeyListener = new MapKeyListener(transform, trackingSettings, uiSettings);
|
||||
|
||||
// overlain zoom buttons
|
||||
mapZoomButtonController = new MapZoomButtonController(new ZoomButtonsController(this));
|
||||
MapZoomControllerListener zoomListener = new MapZoomControllerListener(mapGestureDetector, uiSettings, transform);
|
||||
MapZoomControllerListener zoomListener = new MapZoomControllerListener(mapGestureDetector, uiSettings, transform,
|
||||
cameraChangeDispatcher, getWidth(), getHeight());
|
||||
mapZoomButtonController.bind(uiSettings, zoomListener);
|
||||
|
||||
compassView.injectCompassAnimationListener(createCompassAnimationListener(cameraChangeDispatcher));
|
||||
@@ -345,8 +349,10 @@ public class MapView extends FrameLayout {
|
||||
*/
|
||||
@UiThread
|
||||
public void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
outState.putBoolean(MapboxConstants.STATE_HAS_SAVED_STATE, true);
|
||||
mapboxMap.onSaveInstanceState(outState);
|
||||
if (mapboxMap != null) {
|
||||
outState.putBoolean(MapboxConstants.STATE_HAS_SAVED_STATE, true);
|
||||
mapboxMap.onSaveInstanceState(outState);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -355,6 +361,7 @@ public class MapView extends FrameLayout {
|
||||
@UiThread
|
||||
public void onStart() {
|
||||
ConnectivityReceiver.instance(getContext()).activate();
|
||||
FileSource.getInstance(getContext()).activate();
|
||||
if (mapboxMap != null) {
|
||||
mapboxMap.onStart();
|
||||
}
|
||||
@@ -385,8 +392,12 @@ public class MapView extends FrameLayout {
|
||||
*/
|
||||
@UiThread
|
||||
public void onStop() {
|
||||
mapboxMap.onStop();
|
||||
if (mapboxMap != null) {
|
||||
// map was destroyed before it was started
|
||||
mapboxMap.onStop();
|
||||
}
|
||||
ConnectivityReceiver.instance(getContext()).deactivate();
|
||||
FileSource.getInstance(getContext()).deactivate();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -406,6 +417,10 @@ public class MapView extends FrameLayout {
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
if (!isMapInitialized() || !isZoomButtonControllerInitialized()) {
|
||||
return super.onTouchEvent(event);
|
||||
}
|
||||
|
||||
if (event.getAction() == MotionEvent.ACTION_DOWN) {
|
||||
mapZoomButtonController.setVisible(true);
|
||||
}
|
||||
@@ -434,11 +449,18 @@ public class MapView extends FrameLayout {
|
||||
|
||||
@Override
|
||||
public boolean onGenericMotionEvent(MotionEvent event) {
|
||||
if (mapGestureDetector == null) {
|
||||
return super.onGenericMotionEvent(event);
|
||||
}
|
||||
return mapGestureDetector.onGenericMotionEvent(event) || super.onGenericMotionEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHoverEvent(MotionEvent event) {
|
||||
if (!isZoomButtonControllerInitialized()) {
|
||||
return super.onHoverEvent(event);
|
||||
}
|
||||
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_HOVER_ENTER:
|
||||
case MotionEvent.ACTION_HOVER_MOVE:
|
||||
@@ -495,7 +517,7 @@ public class MapView extends FrameLayout {
|
||||
if (destroyed) {
|
||||
return;
|
||||
}
|
||||
if (nativeMapView == null) {
|
||||
if (!isMapInitialized()) {
|
||||
mapboxMapOptions.styleUrl(url);
|
||||
return;
|
||||
}
|
||||
@@ -512,7 +534,7 @@ public class MapView extends FrameLayout {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isInEditMode() && nativeMapView != null) {
|
||||
if (!isInEditMode() && isMapInitialized()) {
|
||||
nativeMapView.resizeView(width, height);
|
||||
}
|
||||
}
|
||||
@@ -526,7 +548,9 @@ public class MapView extends FrameLayout {
|
||||
@CallSuper
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mapZoomButtonController.setVisible(false);
|
||||
if (isZoomButtonControllerInitialized()) {
|
||||
mapZoomButtonController.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Called when view is hidden and shown
|
||||
@@ -536,7 +560,7 @@ public class MapView extends FrameLayout {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mapZoomButtonController != null) {
|
||||
if (isZoomButtonControllerInitialized()) {
|
||||
mapZoomButtonController.setVisible(visibility == View.VISIBLE);
|
||||
}
|
||||
}
|
||||
@@ -598,6 +622,14 @@ public class MapView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isMapInitialized() {
|
||||
return nativeMapView != null;
|
||||
}
|
||||
|
||||
private boolean isZoomButtonControllerInitialized() {
|
||||
return mapZoomButtonController != null;
|
||||
}
|
||||
|
||||
MapboxMap getMapboxMap() {
|
||||
return mapboxMap;
|
||||
}
|
||||
@@ -883,16 +915,23 @@ public class MapView extends FrameLayout {
|
||||
}
|
||||
}
|
||||
|
||||
private class MapZoomControllerListener implements ZoomButtonsController.OnZoomListener {
|
||||
private static class MapZoomControllerListener implements ZoomButtonsController.OnZoomListener {
|
||||
|
||||
private final MapGestureDetector mapGestureDetector;
|
||||
private final UiSettings uiSettings;
|
||||
private final Transform transform;
|
||||
private final CameraChangeDispatcher cameraChangeDispatcher;
|
||||
private final float mapWidth;
|
||||
private final float mapHeight;
|
||||
|
||||
MapZoomControllerListener(MapGestureDetector detector, UiSettings uiSettings, Transform transform) {
|
||||
MapZoomControllerListener(MapGestureDetector detector, UiSettings uiSettings, Transform transform,
|
||||
CameraChangeDispatcher dispatcher, float mapWidth, float mapHeight) {
|
||||
this.mapGestureDetector = detector;
|
||||
this.uiSettings = uiSettings;
|
||||
this.transform = transform;
|
||||
this.cameraChangeDispatcher = dispatcher;
|
||||
this.mapWidth = mapWidth;
|
||||
this.mapHeight = mapHeight;
|
||||
}
|
||||
|
||||
// Not used
|
||||
@@ -905,6 +944,7 @@ public class MapView extends FrameLayout {
|
||||
@Override
|
||||
public void onZoom(boolean zoomIn) {
|
||||
if (uiSettings.isZoomGesturesEnabled()) {
|
||||
cameraChangeDispatcher.onCameraMoveStarted(CameraChangeDispatcher.REASON_API_ANIMATION);
|
||||
onZoom(zoomIn, mapGestureDetector.getFocalPoint());
|
||||
}
|
||||
}
|
||||
@@ -913,7 +953,7 @@ public class MapView extends FrameLayout {
|
||||
if (focalPoint != null) {
|
||||
transform.zoom(zoomIn, focalPoint);
|
||||
} else {
|
||||
PointF centerPoint = new PointF(getMeasuredWidth() / 2, getMeasuredHeight() / 2);
|
||||
PointF centerPoint = new PointF(mapWidth / 2, mapHeight / 2);
|
||||
transform.zoom(zoomIn, centerPoint);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,6 +47,7 @@ import com.mapbox.services.commons.geojson.Feature;
|
||||
import com.mapbox.services.commons.geojson.Geometry;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import timber.log.Timber;
|
||||
@@ -462,6 +463,13 @@ public final class MapboxMap {
|
||||
nativeMapView.addImage(name, image);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an images to be used in the map's style
|
||||
*/
|
||||
public void addImages(@NonNull HashMap<String, Bitmap> images) {
|
||||
nativeMapView.addImages(images);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an image from the map's style
|
||||
*
|
||||
@@ -709,6 +717,10 @@ public final class MapboxMap {
|
||||
// MapChange.REGION_DID_CHANGE_ANIMATED is not called for `jumpTo`
|
||||
// invalidate camera position to provide OnCameraChange event.
|
||||
invalidateCameraPosition();
|
||||
|
||||
if (callback != null) {
|
||||
callback.onFinish();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1753,38 +1765,122 @@ public final class MapboxMap {
|
||||
* Sets a callback that is invoked when camera movement has ended.
|
||||
*
|
||||
* @param listener the listener to notify
|
||||
* @deprecated use {@link #addOnCameraIdleListener(OnCameraIdleListener)}
|
||||
* and {@link #removeOnCameraIdleListener(OnCameraIdleListener)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setOnCameraIdleListener(@Nullable OnCameraIdleListener listener) {
|
||||
cameraChangeDispatcher.setOnCameraIdleListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a callback that is invoked when camera movement has ended.
|
||||
*
|
||||
* @param listener the listener to notify
|
||||
*/
|
||||
public void addOnCameraIdleListener(@Nullable OnCameraIdleListener listener) {
|
||||
cameraChangeDispatcher.addOnCameraIdleListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a callback that is invoked when camera movement has ended.
|
||||
*
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
public void removeOnCameraIdleListener(@Nullable OnCameraIdleListener listener) {
|
||||
cameraChangeDispatcher.removeOnCameraIdleListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a callback that is invoked when camera movement was cancelled.
|
||||
*
|
||||
* @param listener the listener to notify
|
||||
* @deprecated use {@link #addOnCameraMoveCancelListener(OnCameraMoveCanceledListener)} and
|
||||
* {@link #removeOnCameraMoveCancelListener(OnCameraMoveCanceledListener)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setOnCameraMoveCancelListener(@Nullable OnCameraMoveCanceledListener listener) {
|
||||
cameraChangeDispatcher.setOnCameraMoveCanceledListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a callback that is invoked when camera movement was cancelled.
|
||||
*
|
||||
* @param listener the listener to notify
|
||||
*/
|
||||
public void addOnCameraMoveCancelListener(@Nullable OnCameraMoveCanceledListener listener) {
|
||||
cameraChangeDispatcher.addOnCameraMoveCancelListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a callback that is invoked when camera movement was cancelled.
|
||||
*
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
public void removeOnCameraMoveCancelListener(@Nullable OnCameraMoveCanceledListener listener) {
|
||||
cameraChangeDispatcher.removeOnCameraMoveCancelListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a callback that is invoked when camera movement has started.
|
||||
*
|
||||
* @param listener the listener to notify
|
||||
* @deprecated use {@link #addOnCameraMoveStartedListener(OnCameraMoveStartedListener)} and
|
||||
* {@link #removeOnCameraMoveStartedListener(OnCameraMoveStartedListener)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setOnCameraMoveStartedListener(@Nullable OnCameraMoveStartedListener listener) {
|
||||
cameraChangeDispatcher.setOnCameraMoveStartedListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a callback that is invoked when camera movement has started.
|
||||
*
|
||||
* @param listener the listener to notify
|
||||
*/
|
||||
public void addOnCameraMoveStartedListener(@Nullable OnCameraMoveStartedListener listener) {
|
||||
cameraChangeDispatcher.addOnCameraMoveStartedListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a callback that is invoked when camera movement has started.
|
||||
*
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
public void removeOnCameraMoveStartedListener(@Nullable OnCameraMoveStartedListener listener) {
|
||||
cameraChangeDispatcher.removeOnCameraMoveStartedListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a callback that is invoked when camera position changes.
|
||||
*
|
||||
* @param listener the listener to notify
|
||||
* @deprecated use {@link #addOnCameraMoveListener(OnCameraMoveListener)} and
|
||||
* {@link #removeOnCameraMoveListener(OnCameraMoveListener)}instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setOnCameraMoveListener(@Nullable OnCameraMoveListener listener) {
|
||||
cameraChangeDispatcher.setOnCameraMoveListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a callback that is invoked when camera position changes.
|
||||
*
|
||||
* @param listener the listener to notify
|
||||
*/
|
||||
public void addOnCameraMoveListener(@Nullable OnCameraMoveListener listener) {
|
||||
cameraChangeDispatcher.addOnCameraMoveListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a callback that is invoked when camera position changes.
|
||||
*
|
||||
* @param listener the listener to remove
|
||||
*/
|
||||
public void removeOnCameraMoveListener(@Nullable OnCameraMoveListener listener) {
|
||||
cameraChangeDispatcher.removeOnCameraMoveListener(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a callback that's invoked on every frame rendered to the map view.
|
||||
*
|
||||
|
||||
@@ -98,15 +98,8 @@ class MarkerContainer implements Markers {
|
||||
@NonNull
|
||||
@Override
|
||||
public List<Marker> obtainAllIn(@NonNull RectF rectangle) {
|
||||
// convert Rectangle to be density depedent
|
||||
float pixelRatio = nativeMapView.getPixelRatio();
|
||||
RectF rect = new RectF(rectangle.left / pixelRatio,
|
||||
rectangle.top / pixelRatio,
|
||||
rectangle.right / pixelRatio,
|
||||
rectangle.bottom / pixelRatio);
|
||||
|
||||
RectF rect = nativeMapView.getDensityDependantRectangle(rectangle);
|
||||
long[] ids = nativeMapView.queryPointAnnotations(rect);
|
||||
|
||||
List<Long> idsList = new ArrayList<>(ids.length);
|
||||
for (long id : ids) {
|
||||
idsList.add(id);
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.PointF;
|
||||
import android.graphics.RectF;
|
||||
import android.os.AsyncTask;
|
||||
import android.support.annotation.IntRange;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
@@ -34,7 +35,9 @@ import com.mapbox.services.commons.geojson.Geometry;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
@@ -468,6 +471,13 @@ final class NativeMapView {
|
||||
return nativeQueryPointAnnotations(rect);
|
||||
}
|
||||
|
||||
public long[] queryShapeAnnotations(RectF rectF) {
|
||||
if (isDestroyedOn("queryShapeAnnotations")) {
|
||||
return new long[] {};
|
||||
}
|
||||
return nativeQueryShapeAnnotations(rectF);
|
||||
}
|
||||
|
||||
public void addAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels) {
|
||||
if (isDestroyedOn("addAnnotationIcon")) {
|
||||
return;
|
||||
@@ -746,6 +756,7 @@ final class NativeMapView {
|
||||
if (isDestroyedOn("addImage")) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check/correct config
|
||||
if (image.getConfig() != Bitmap.Config.ARGB_8888) {
|
||||
image = image.copy(Bitmap.Config.ARGB_8888, false);
|
||||
@@ -762,6 +773,14 @@ final class NativeMapView {
|
||||
nativeAddImage(name, image.getWidth(), image.getHeight(), pixelRatio, buffer.array());
|
||||
}
|
||||
|
||||
public void addImages(@NonNull HashMap<String, Bitmap> bitmapHashMap) {
|
||||
if (isDestroyedOn("addImages")) {
|
||||
return;
|
||||
}
|
||||
//noinspection unchecked
|
||||
new BitmapImageConversionTask(this).execute(bitmapHashMap);
|
||||
}
|
||||
|
||||
public void removeImage(String name) {
|
||||
if (isDestroyedOn("removeImage")) {
|
||||
return;
|
||||
@@ -825,6 +844,15 @@ final class NativeMapView {
|
||||
return pixelRatio;
|
||||
}
|
||||
|
||||
RectF getDensityDependantRectangle(final RectF rectangle) {
|
||||
return new RectF(
|
||||
rectangle.left / pixelRatio,
|
||||
rectangle.top / pixelRatio,
|
||||
rectangle.right / pixelRatio,
|
||||
rectangle.bottom / pixelRatio
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Callbacks
|
||||
//
|
||||
@@ -927,6 +955,8 @@ final class NativeMapView {
|
||||
|
||||
private native long[] nativeQueryPointAnnotations(RectF rect);
|
||||
|
||||
private native long[] nativeQueryShapeAnnotations(RectF rect);
|
||||
|
||||
private native void nativeAddAnnotationIcon(String symbol, int width, int height, float scale, byte[] pixels);
|
||||
|
||||
private native void nativeRemoveAnnotationIcon(String symbol);
|
||||
@@ -1006,6 +1036,8 @@ final class NativeMapView {
|
||||
private native void nativeAddImage(String name, int width, int height, float pixelRatio,
|
||||
byte[] array);
|
||||
|
||||
private native void nativeAddImages(Image[] images);
|
||||
|
||||
private native void nativeRemoveImage(String name);
|
||||
|
||||
private native Bitmap nativeGetImage(String name);
|
||||
@@ -1093,4 +1125,55 @@ final class NativeMapView {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Image conversion
|
||||
//
|
||||
|
||||
private static class BitmapImageConversionTask extends AsyncTask<HashMap<String, Bitmap>, Void, List<Image>> {
|
||||
|
||||
private NativeMapView nativeMapView;
|
||||
|
||||
BitmapImageConversionTask(NativeMapView nativeMapView) {
|
||||
this.nativeMapView = nativeMapView;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Image> doInBackground(HashMap<String, Bitmap>... params) {
|
||||
HashMap<String, Bitmap> bitmapHashMap = params[0];
|
||||
|
||||
List<Image> images = new ArrayList<>();
|
||||
ByteBuffer buffer;
|
||||
String name;
|
||||
Bitmap bitmap;
|
||||
|
||||
for (Map.Entry<String, Bitmap> stringBitmapEntry : bitmapHashMap.entrySet()) {
|
||||
name = stringBitmapEntry.getKey();
|
||||
bitmap = stringBitmapEntry.getValue();
|
||||
|
||||
if (bitmap.getConfig() != Bitmap.Config.ARGB_8888) {
|
||||
bitmap = bitmap.copy(Bitmap.Config.ARGB_8888, false);
|
||||
}
|
||||
|
||||
buffer = ByteBuffer.allocate(bitmap.getByteCount());
|
||||
bitmap.copyPixelsToBuffer(buffer);
|
||||
|
||||
float density = bitmap.getDensity() == Bitmap.DENSITY_NONE ? Bitmap.DENSITY_NONE : bitmap.getDensity();
|
||||
float pixelRatio = density / DisplayMetrics.DENSITY_DEFAULT;
|
||||
|
||||
images.add(new Image(buffer.array(), pixelRatio, name, bitmap.getWidth(), bitmap.getHeight()));
|
||||
}
|
||||
|
||||
return images;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(List<Image> images) {
|
||||
super.onPostExecute(images);
|
||||
if (nativeMapView != null && !nativeMapView.isDestroyedOn("nativeAddImages")) {
|
||||
nativeMapView.nativeAddImages(images.toArray(new Image[images.size()]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.mapbox.mapboxsdk.maps;
|
||||
|
||||
import android.graphics.RectF;
|
||||
import android.support.v4.util.LongSparseArray;
|
||||
|
||||
import com.mapbox.mapboxsdk.annotations.Annotation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
class ShapeAnnotationContainer implements ShapeAnnotations {
|
||||
|
||||
private final NativeMapView nativeMapView;
|
||||
private final LongSparseArray<Annotation> annotations;
|
||||
|
||||
ShapeAnnotationContainer(NativeMapView nativeMapView, LongSparseArray<Annotation> annotations) {
|
||||
this.nativeMapView = nativeMapView;
|
||||
this.annotations = annotations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Annotation> obtainAllIn(RectF rectangle) {
|
||||
RectF rect = nativeMapView.getDensityDependantRectangle(rectangle);
|
||||
long[] annotationIds = nativeMapView.queryShapeAnnotations(rect);
|
||||
return getAnnotationsFromIds(annotationIds);
|
||||
}
|
||||
|
||||
private List<Annotation> getAnnotationsFromIds(long[] annotationIds) {
|
||||
List<Annotation> shapeAnnotations = new ArrayList<>();
|
||||
for (long annotationId : annotationIds) {
|
||||
Annotation annotation = annotations.get(annotationId);
|
||||
if (annotation != null) {
|
||||
shapeAnnotations.add(annotation);
|
||||
}
|
||||
}
|
||||
return shapeAnnotations;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.mapbox.mapboxsdk.maps;
|
||||
|
||||
import android.graphics.RectF;
|
||||
|
||||
import com.mapbox.mapboxsdk.annotations.Annotation;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
interface ShapeAnnotations {
|
||||
|
||||
List<Annotation> obtainAllIn(RectF rectF);
|
||||
|
||||
}
|
||||
@@ -98,9 +98,6 @@ final class Transform implements MapView.OnMapChangedListener {
|
||||
cancelTransitions();
|
||||
cameraChangeDispatcher.onCameraMoveStarted(OnCameraMoveStartedListener.REASON_API_ANIMATION);
|
||||
mapView.jumpTo(cameraPosition.bearing, cameraPosition.target, cameraPosition.tilt, cameraPosition.zoom);
|
||||
if (callback != null) {
|
||||
callback.onFinish();
|
||||
}
|
||||
cameraChangeDispatcher.onCameraIdle();
|
||||
}
|
||||
}
|
||||
@@ -210,6 +207,10 @@ final class Transform implements MapView.OnMapChangedListener {
|
||||
return cameraPosition.zoom;
|
||||
}
|
||||
|
||||
double getRawZoom() {
|
||||
return mapView.getZoom();
|
||||
}
|
||||
|
||||
void zoom(boolean zoomIn, @NonNull PointF focalPoint) {
|
||||
CameraPosition cameraPosition = invalidateCameraPosition();
|
||||
if (cameraPosition != null) {
|
||||
@@ -221,6 +222,17 @@ final class Transform implements MapView.OnMapChangedListener {
|
||||
}
|
||||
}
|
||||
|
||||
void zoom(double zoomAddition, @NonNull PointF focalPoint, long duration) {
|
||||
CameraPosition cameraPosition = invalidateCameraPosition();
|
||||
if (cameraPosition != null) {
|
||||
int newZoom = (int) Math.round(cameraPosition.zoom + zoomAddition);
|
||||
setZoom(newZoom, focalPoint, duration);
|
||||
} else {
|
||||
// we are not transforming, notify about being idle
|
||||
cameraChangeDispatcher.onCameraIdle();
|
||||
}
|
||||
}
|
||||
|
||||
void setZoom(double zoom, @NonNull PointF focalPoint) {
|
||||
setZoom(zoom, focalPoint, 0);
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@ import android.support.annotation.NonNull;
|
||||
import android.support.v4.view.ViewCompat;
|
||||
import android.support.v4.view.ViewPropertyAnimatorCompat;
|
||||
import android.support.v4.view.ViewPropertyAnimatorListenerAdapter;
|
||||
import android.support.v7.widget.AppCompatImageView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
|
||||
@@ -22,7 +22,7 @@ import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
* use {@link com.mapbox.mapboxsdk.maps.UiSettings}.
|
||||
* </p>
|
||||
*/
|
||||
public final class CompassView extends AppCompatImageView implements Runnable {
|
||||
public final class CompassView extends ImageView implements Runnable {
|
||||
|
||||
public static final long TIME_WAIT_IDLE = 500;
|
||||
public static final long TIME_MAP_NORTH_ANIMATION = 150;
|
||||
|
||||
@@ -300,10 +300,19 @@ public class OfflineRegion {
|
||||
|
||||
/**
|
||||
* Pause or resume downloading of regional resources.
|
||||
* <p>
|
||||
* After a download has been completed, you are required to reset the state of the region to STATE_INACTIVE.
|
||||
* </p>
|
||||
*
|
||||
* @param state the download state
|
||||
*/
|
||||
public void setDownloadState(@DownloadState int state) {
|
||||
if (state == STATE_ACTIVE) {
|
||||
fileSource.activate();
|
||||
} else {
|
||||
fileSource.deactivate();
|
||||
}
|
||||
|
||||
this.state = state;
|
||||
setOfflineRegionDownloadState(state);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Matrix;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.annotation.UiThread;
|
||||
@@ -262,35 +263,59 @@ public class MapSnapshotter {
|
||||
nativeCancel();
|
||||
}
|
||||
|
||||
protected void addOverlay(Bitmap original) {
|
||||
/**
|
||||
* Draw an overlay on the map snapshot.
|
||||
*
|
||||
* @param mapSnapshot the map snapshot to draw the overlay on
|
||||
*/
|
||||
protected void addOverlay(MapSnapshot mapSnapshot) {
|
||||
Bitmap original = mapSnapshot.getBitmap();
|
||||
Canvas canvas = new Canvas(original);
|
||||
addLogo(canvas, original);
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw a logo on the canvas created from the map snapshot.
|
||||
*
|
||||
* @param canvas the canvas to draw the bitmap on
|
||||
* @param original the map snapshot image
|
||||
*/
|
||||
private void addLogo(Canvas canvas, Bitmap original) {
|
||||
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
|
||||
float margin = displayMetrics.density * LOGO_MARGIN_DP;
|
||||
Canvas canvas = new Canvas(original);
|
||||
Bitmap logo = createScaledLogo(original);
|
||||
canvas.drawBitmap(logo, margin, original.getHeight() - logo.getHeight() - margin, null);
|
||||
}
|
||||
|
||||
// Decode just the boundaries
|
||||
BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
|
||||
bitmapOptions.inJustDecodeBounds = true;
|
||||
BitmapFactory.decodeResource(context.getResources(), R.drawable.mapbox_logo_icon, bitmapOptions);
|
||||
int srcWidth = bitmapOptions.outWidth;
|
||||
int srcHeight = bitmapOptions.outHeight;
|
||||
/**
|
||||
* Create a scaled logo for a map snapshot.
|
||||
*
|
||||
* @param snapshot the map snapshot where the logo should be placed on
|
||||
* @return the scaled bitmap logo
|
||||
*/
|
||||
private Bitmap createScaledLogo(Bitmap snapshot) {
|
||||
Bitmap logo = BitmapFactory.decodeResource(context.getResources(), R.drawable.mapbox_logo_icon, null);
|
||||
float scale = calculateLogoScale(snapshot, logo);
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postScale(scale, scale);
|
||||
return Bitmap.createBitmap(logo, 0, 0, logo.getWidth(), logo.getHeight(), matrix, true);
|
||||
}
|
||||
|
||||
// Ratio, preferred dimensions and resulting sample size
|
||||
float widthRatio = displayMetrics.widthPixels / original.getWidth();
|
||||
float heightRatio = displayMetrics.heightPixels / original.getHeight();
|
||||
float prefWidth = srcWidth / widthRatio;
|
||||
float prefHeight = srcHeight / heightRatio;
|
||||
int sampleSize = MapSnaphotUtil.calculateInSampleSize(bitmapOptions, (int) prefWidth, (int) prefHeight);
|
||||
|
||||
// Scale bitmap
|
||||
bitmapOptions.inJustDecodeBounds = false;
|
||||
bitmapOptions.inScaled = true;
|
||||
bitmapOptions.inSampleSize = sampleSize;
|
||||
bitmapOptions.inDensity = srcWidth;
|
||||
bitmapOptions.inTargetDensity = (int) prefWidth * bitmapOptions.inSampleSize;
|
||||
Bitmap logo = BitmapFactory.decodeResource(context.getResources(), R.drawable.mapbox_logo_icon, bitmapOptions);
|
||||
|
||||
float scaledHeight = bitmapOptions.outHeight * heightRatio / bitmapOptions.inSampleSize;
|
||||
canvas.drawBitmap(logo, margin, original.getHeight() - scaledHeight - margin, null);
|
||||
/**
|
||||
* Calculates the scale of the logo, only allow downscaling.
|
||||
*
|
||||
* @param snapshot the bitmap of the map snapshot
|
||||
* @param logo the bitmap of the mapbox logo
|
||||
* @return the scale value
|
||||
*/
|
||||
private float calculateLogoScale(Bitmap snapshot, Bitmap logo) {
|
||||
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
|
||||
float widthRatio = displayMetrics.widthPixels / snapshot.getWidth();
|
||||
float heightRatio = displayMetrics.heightPixels / snapshot.getHeight();
|
||||
float prefWidth = logo.getWidth() / widthRatio;
|
||||
float prefHeight = logo.getHeight() / heightRatio;
|
||||
float calculatedScale = Math.min(prefWidth / logo.getWidth(), prefHeight / logo.getHeight()) * 2;
|
||||
return calculatedScale < 1 ? calculatedScale : 1.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -302,7 +327,7 @@ public class MapSnapshotter {
|
||||
protected void onSnapshotReady(MapSnapshot snapshot) {
|
||||
if (callback != null) {
|
||||
if (snapshot.isShowLogo()) {
|
||||
addOverlay(snapshot.getBitmap());
|
||||
addOverlay(snapshot);
|
||||
}
|
||||
callback.onSnapshotReady(snapshot);
|
||||
reset();
|
||||
|
||||
@@ -72,7 +72,7 @@ public class FileSource {
|
||||
MapboxConstants.KEY_META_DATA_SET_STORAGE_EXTERNAL,
|
||||
MapboxConstants.DEFAULT_SET_STORAGE_EXTERNAL);
|
||||
} catch (PackageManager.NameNotFoundException exception) {
|
||||
Timber.e(exception,"Failed to read the package metadata: ");
|
||||
Timber.e(exception, "Failed to read the package metadata: ");
|
||||
} catch (Exception exception) {
|
||||
Timber.e(exception, "Failed to read the storage key: ");
|
||||
}
|
||||
@@ -119,17 +119,39 @@ public class FileSource {
|
||||
}
|
||||
|
||||
private long nativePtr;
|
||||
private long activeCounter;
|
||||
private boolean wasPaused;
|
||||
|
||||
private FileSource(String cachePath, AssetManager assetManager) {
|
||||
initialize(Mapbox.getAccessToken(), cachePath, assetManager);
|
||||
}
|
||||
|
||||
public void activate() {
|
||||
activeCounter++;
|
||||
if (activeCounter == 1 && wasPaused) {
|
||||
wasPaused = false;
|
||||
resume();
|
||||
}
|
||||
}
|
||||
|
||||
public void deactivate() {
|
||||
activeCounter--;
|
||||
if (activeCounter == 0) {
|
||||
wasPaused = true;
|
||||
pause();
|
||||
}
|
||||
}
|
||||
|
||||
public native void setAccessToken(@NonNull String accessToken);
|
||||
|
||||
public native String getAccessToken();
|
||||
|
||||
public native void setApiBaseUrl(String baseUrl);
|
||||
|
||||
private native void resume();
|
||||
|
||||
private native void pause();
|
||||
|
||||
/**
|
||||
* Sets a callback for transforming URLs requested from the internet
|
||||
* <p>
|
||||
|
||||
@@ -5,6 +5,7 @@ import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.ColorInt;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.graphics.drawable.DrawableCompat;
|
||||
@@ -30,10 +31,15 @@ public class ColorUtils {
|
||||
*/
|
||||
@ColorInt
|
||||
public static int getPrimaryColor(@NonNull Context context) {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
Resources.Theme theme = context.getTheme();
|
||||
theme.resolveAttribute(R.attr.colorPrimary, typedValue, true);
|
||||
return typedValue.data;
|
||||
try {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
Resources.Theme theme = context.getTheme();
|
||||
int id = context.getResources().getIdentifier("colorPrimary", "attrs", context.getPackageName());
|
||||
theme.resolveAttribute(id, typedValue, true);
|
||||
return typedValue.data;
|
||||
} catch (Exception exception) {
|
||||
return getColorCompat(context, R.color.mapbox_blue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -44,10 +50,15 @@ public class ColorUtils {
|
||||
*/
|
||||
@ColorInt
|
||||
public static int getPrimaryDarkColor(@NonNull Context context) {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
Resources.Theme theme = context.getTheme();
|
||||
theme.resolveAttribute(R.attr.colorPrimaryDark, typedValue, true);
|
||||
return typedValue.data;
|
||||
try {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
Resources.Theme theme = context.getTheme();
|
||||
int id = context.getResources().getIdentifier("colorPrimaryDark", "attrs", context.getPackageName());
|
||||
theme.resolveAttribute(id, typedValue, true);
|
||||
return typedValue.data;
|
||||
} catch (Exception exception) {
|
||||
return getColorCompat(context, R.color.mapbox_blue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -58,10 +69,15 @@ public class ColorUtils {
|
||||
*/
|
||||
@ColorInt
|
||||
public static int getAccentColor(@NonNull Context context) {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
Resources.Theme theme = context.getTheme();
|
||||
theme.resolveAttribute(R.attr.colorAccent, typedValue, true);
|
||||
return typedValue.data;
|
||||
try {
|
||||
TypedValue typedValue = new TypedValue();
|
||||
Resources.Theme theme = context.getTheme();
|
||||
int id = context.getResources().getIdentifier("colorAccent", "attrs", context.getPackageName());
|
||||
theme.resolveAttribute(id, typedValue, true);
|
||||
return typedValue.data;
|
||||
} catch (Exception exception) {
|
||||
return getColorCompat(context, R.color.mapbox_gray);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -122,4 +138,12 @@ public class ColorUtils {
|
||||
throw new ConversionException("Not a valid rgb/rgba value");
|
||||
}
|
||||
}
|
||||
|
||||
private static int getColorCompat(Context context, int id) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
return context.getResources().getColor(id, context.getTheme());
|
||||
} else {
|
||||
return context.getResources().getColor(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="mapbox_compassContentDescription">Компас на картата. Активирай, за да насочиш картата на север.</string>
|
||||
<string name="mapbox_attributionsIconContentDescription">Иконка функции. Активирай, за да покажеш диалог функции.</string>
|
||||
<string name="mapbox_myLocationViewContentDescription">Изглед локация. Това показва местоположението ти на картата.</string>
|
||||
<string name="mapbox_mapActionDescription">Показва карта създадена с Mapbox. Скролни с два пръста. Мащабирай с два пръста.</string>
|
||||
<string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
|
||||
<string name="mapbox_attributionTelemetryTitle">Направи Mapbox картите по-добри.</string>
|
||||
<string name="mapbox_attributionTelemetryMessage">Помагаш OpenStreetMap и Mapbox картите да станат по-добри, като предоставяш анонимни данни за потребление.</string>
|
||||
<string name="mapbox_attributionTelemetryPositive">Съгласявам се</string>
|
||||
<string name="mapbox_attributionTelemetryNegative">Не се съгласявам</string>
|
||||
<string name="mapbox_attributionTelemetryNeutral">Повече инфо</string>
|
||||
<string name="mapbox_offline_error_region_definition_invalid">Предоставените OfflineRegionDefinition не пасват в границите на света: %s</string>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="mapbox_myLocationViewContentDescription">Hely nézet. Megmutatja, hol vagy a térképen.</string>
|
||||
<string name="mapbox_mapActionDescription">Egy Mapbox-szal készült térkép megjelenítése. Húzd két ujjadat a görgetéshez. Csippentsd össze a nagyításhoz.</string>
|
||||
<string name="mapbox_attributionsDialogTitle">Mapbox Android SDK</string>
|
||||
<string name="mapbox_attributionTelemetryTitle">Tedd jobbá a Mapbox térképeket</string>
|
||||
<string name="mapbox_attributionTelemetryMessage">Segítesz az OpenStreetMap és Mapbox térképek jobbá tételében névtelen felhasználási adatok elküldésével.</string>
|
||||
<string name="mapbox_attributionTelemetryPositive">Egyetértek</string>
|
||||
<string name="mapbox_attributionTelemetryNegative">Nem értek egyet</string>
|
||||
<string name="mapbox_attributionTelemetryNeutral">Több infó</string>
|
||||
<string name="mapbox_offline_error_region_definition_invalid">A megadott OfflineRegionDefinition nem fér bele a világ kereteibe: %s</string>
|
||||
|
||||
</resources>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="mapbox_AlertDialogStyle" parent="Theme.AppCompat.Light.Dialog.Alert"/>
|
||||
|
||||
</resources>
|
||||
@@ -73,15 +73,6 @@ public class LatLngBoundsTest {
|
||||
assertEquals("Center should match", new LatLng(1, 1), center);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void emptySpan() {
|
||||
latLngBounds = new LatLngBounds.Builder()
|
||||
.include(LAT_LNG_NOT_NULL_ISLAND)
|
||||
.include(LAT_LNG_NOT_NULL_ISLAND)
|
||||
.build();
|
||||
assertTrue("Should be empty", latLngBounds.isEmptySpan());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void notEmptySpan() {
|
||||
latLngBounds = new LatLngBounds.Builder()
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.mapbox.mapboxsdk.annotations.MarkerViewManager;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
@@ -32,8 +33,9 @@ public class AnnotationManagerTest {
|
||||
Markers markers = new MarkerContainer(aNativeMapView, aMapView, annotationsArray, aIconManager, aMarkerViewManager);
|
||||
Polygons polygons = new PolygonContainer(aNativeMapView, annotationsArray);
|
||||
Polylines polylines = new PolylineContainer(aNativeMapView, annotationsArray);
|
||||
ShapeAnnotations shapeAnnotations = new ShapeAnnotationContainer(aNativeMapView, annotationsArray);
|
||||
AnnotationManager annotationManager = new AnnotationManager(aNativeMapView, aMapView, annotationsArray,
|
||||
aMarkerViewManager, aIconManager, annotations, markers, polygons, polylines);
|
||||
aMarkerViewManager, aIconManager, annotations, markers, polygons, polylines, shapeAnnotations);
|
||||
Marker aMarker = mock(Marker.class);
|
||||
long aId = 5L;
|
||||
when(aNativeMapView.addMarker(aMarker)).thenReturn(aId);
|
||||
@@ -58,18 +60,23 @@ public class AnnotationManagerTest {
|
||||
Markers markers = new MarkerContainer(aNativeMapView, aMapView, annotationsArray, aIconManager, aMarkerViewManager);
|
||||
Polygons polygons = new PolygonContainer(aNativeMapView, annotationsArray);
|
||||
Polylines polylines = new PolylineContainer(aNativeMapView, annotationsArray);
|
||||
ShapeAnnotations shapeAnnotations = new ShapeAnnotationContainer(aNativeMapView, annotationsArray);
|
||||
AnnotationManager annotationManager = new AnnotationManager(aNativeMapView, aMapView, annotationsArray,
|
||||
aMarkerViewManager, aIconManager, annotations, markers, polygons, polylines);
|
||||
aMarkerViewManager, aIconManager, annotations, markers, polygons, polylines, shapeAnnotations);
|
||||
long firstId = 1L;
|
||||
long secondId = 2L;
|
||||
List<BaseMarkerOptions> markerList = new ArrayList<>();
|
||||
MarkerOptions firstMarkerOption = new MarkerOptions().position(new LatLng()).title("first");
|
||||
MarkerOptions secondMarkerOption = new MarkerOptions().position(new LatLng()).title("second");
|
||||
|
||||
markerList.add(firstMarkerOption);
|
||||
markerList.add(secondMarkerOption);
|
||||
MapboxMap aMapboxMap = mock(MapboxMap.class);
|
||||
when(aNativeMapView.addMarker(any(Marker.class))).thenReturn(firstId, secondId);
|
||||
|
||||
when(aNativeMapView.addMarkers(ArgumentMatchers.<Marker>anyList()))
|
||||
.thenReturn(new long[]{firstId, secondId});
|
||||
|
||||
annotationManager.addMarkers(markerList, aMapboxMap);
|
||||
|
||||
assertEquals(2, annotationManager.getAnnotations().size());
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.mapbox.mapboxsdk.maps;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
public class CameraChangeDispatcherTest {
|
||||
|
||||
@Test
|
||||
public void testSetCameraIdleListener() {
|
||||
CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
|
||||
MapboxMap.OnCameraIdleListener listener = mock(MapboxMap.OnCameraIdleListener.class);
|
||||
dispatcher.setOnCameraIdleListener(listener);
|
||||
dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
|
||||
dispatcher.onCameraIdle();
|
||||
verify(listener).onCameraIdle();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCameraMoveStartedListener() {
|
||||
CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
|
||||
MapboxMap.OnCameraMoveStartedListener listener = mock(MapboxMap.OnCameraMoveStartedListener.class);
|
||||
dispatcher.setOnCameraMoveStartedListener(listener);
|
||||
dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
|
||||
verify(listener).onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCameraMoveCancelListener() {
|
||||
CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
|
||||
MapboxMap.OnCameraMoveCanceledListener listener = mock(MapboxMap.OnCameraMoveCanceledListener.class);
|
||||
dispatcher.setOnCameraMoveCanceledListener(listener);
|
||||
dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
|
||||
dispatcher.onCameraMoveCanceled();
|
||||
verify(listener).onCameraMoveCanceled();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetCameraMoveListener() {
|
||||
CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
|
||||
MapboxMap.OnCameraMoveListener listener = mock(MapboxMap.OnCameraMoveListener.class);
|
||||
dispatcher.setOnCameraMoveListener(listener);
|
||||
dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
|
||||
dispatcher.onCameraMove();
|
||||
verify(listener).onCameraMove();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddCameraIdleListener() {
|
||||
CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
|
||||
MapboxMap.OnCameraIdleListener listener = mock(MapboxMap.OnCameraIdleListener.class);
|
||||
dispatcher.addOnCameraIdleListener(listener);
|
||||
dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
|
||||
dispatcher.onCameraIdle();
|
||||
verify(listener).onCameraIdle();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddCameraMoveStartedListener() {
|
||||
CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
|
||||
MapboxMap.OnCameraMoveStartedListener listener = mock(MapboxMap.OnCameraMoveStartedListener.class);
|
||||
dispatcher.addOnCameraMoveStartedListener(listener);
|
||||
dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
|
||||
verify(listener).onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddCameraMoveCancelListener() {
|
||||
CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
|
||||
MapboxMap.OnCameraMoveCanceledListener listener = mock(MapboxMap.OnCameraMoveCanceledListener.class);
|
||||
dispatcher.addOnCameraMoveCancelListener(listener);
|
||||
dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
|
||||
dispatcher.onCameraMoveCanceled();
|
||||
verify(listener).onCameraMoveCanceled();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddCameraMoveListener() {
|
||||
CameraChangeDispatcher dispatcher = new CameraChangeDispatcher();
|
||||
MapboxMap.OnCameraMoveListener listener = mock(MapboxMap.OnCameraMoveListener.class);
|
||||
dispatcher.addOnCameraMoveListener(listener);
|
||||
dispatcher.onCameraMoveStarted(MapboxMap.OnCameraMoveStartedListener.REASON_API_GESTURE);
|
||||
dispatcher.onCameraMove();
|
||||
verify(listener).onCameraMove();
|
||||
}
|
||||
}
|
||||
@@ -59,6 +59,7 @@ dependencies {
|
||||
// Support libraries
|
||||
compile rootProject.ext.dep.supportAppcompatV7
|
||||
compile rootProject.ext.dep.supportRecyclerView
|
||||
compile rootProject.ext.dep.supportDesign
|
||||
|
||||
// Leak Canary
|
||||
debugCompile rootProject.ext.dep.leakCanaryDebug
|
||||
@@ -71,7 +72,6 @@ dependencies {
|
||||
compile rootProject.ext.dep.lost
|
||||
|
||||
// Testing dependencies
|
||||
androidTestCompile rootProject.ext.dep.testSpoonRunner
|
||||
androidTestCompile rootProject.ext.dep.supportAnnotations
|
||||
androidTestCompile rootProject.ext.dep.testRunner
|
||||
androidTestCompile rootProject.ext.dep.testRules
|
||||
@@ -81,8 +81,6 @@ dependencies {
|
||||
|
||||
apply from: 'gradle-make.gradle'
|
||||
apply from: 'gradle-config.gradle'
|
||||
apply from: 'gradle-device-farm.gradle'
|
||||
apply from: 'gradle-spoon.gradle'
|
||||
apply from: 'gradle-checkstyle.gradle'
|
||||
apply from: '../gradle-lint.gradle'
|
||||
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
apply plugin: 'devicefarm'
|
||||
|
||||
def getAccessKeyDeviceFarm() {
|
||||
if (project.hasProperty('AWS_ACCESS_KEY_ID_DEVICE_FARM')) {
|
||||
return AWS_ACCESS_KEY_ID_DEVICE_FARM
|
||||
} else {
|
||||
println("Could not locate AWS_ACCESS_KEY_ID_DEVICE_FARM in gradle.properties")
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
def getSecretAccessKeyDeviceFarm() {
|
||||
if (project.hasProperty('AWS_SECRET_ACCESS_KEY_DEVICE_FARM')) {
|
||||
return AWS_SECRET_ACCESS_KEY_DEVICE_FARM
|
||||
} else {
|
||||
println("Could not locate AWS_SECRET_ACCESS_KEY_DEVICE_FARM in gradle.properties")
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
devicefarm {
|
||||
|
||||
projectName "Mapbox GL Android" // required: Must already exists.
|
||||
devicePool "sanity" // optional: Defaults to "Top Devices"
|
||||
|
||||
authentication {
|
||||
accessKey getAccessKeyDeviceFarm()
|
||||
secretKey getSecretAccessKeyDeviceFarm()
|
||||
}
|
||||
|
||||
devicestate {
|
||||
wifi "on"
|
||||
bluetooth "off"
|
||||
gps "on"
|
||||
nfc "on"
|
||||
latitude 47.6204 // default
|
||||
longitude - 122.3491 // default
|
||||
}
|
||||
|
||||
instrumentation {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
println "configuring spoon"
|
||||
apply plugin: 'spoon'
|
||||
spoon {
|
||||
// Spoon: distributes instrumentation tests to all your Androids
|
||||
// for more options see https://github.com/stanfy/spoon-gradle-plugin
|
||||
grantAllPermissions = true
|
||||
debug = true
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import com.mapbox.mapboxsdk.annotations.Polygon;
|
||||
import com.mapbox.mapboxsdk.annotations.PolygonOptions;
|
||||
import com.mapbox.mapboxsdk.annotations.Polyline;
|
||||
import com.mapbox.mapboxsdk.annotations.PolylineOptions;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
|
||||
import com.mapbox.mapboxsdk.constants.MapboxConstants;
|
||||
import com.mapbox.mapboxsdk.exceptions.InvalidMarkerPositionException;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
@@ -31,9 +32,12 @@ import org.junit.Test;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
import static android.support.test.espresso.Espresso.onView;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
|
||||
import static android.support.test.espresso.matcher.ViewMatchers.withId;
|
||||
import static com.mapbox.mapboxsdk.testapp.utils.TestConstants.LAT_LNG_DELTA;
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static junit.framework.TestCase.assertNotNull;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
@@ -90,8 +94,33 @@ public class MapboxMapTest extends BaseActivityTest {
|
||||
}
|
||||
|
||||
//
|
||||
// CameraForLatLngBounds
|
||||
// Camera tests
|
||||
//
|
||||
@Test
|
||||
public void testCameraPositionOnFinish() {
|
||||
ViewUtils.checkViewIsDisplayed(R.id.mapView);
|
||||
onView(withId(R.id.mapView)).perform(new MapboxMapAction(new InvokeViewAction() {
|
||||
@Override
|
||||
public void onViewAction(UiController uiController, View view) {
|
||||
|
||||
final LatLng latLng = new LatLng(30.0, 30.0);
|
||||
mapboxMap.moveCamera(CameraUpdateFactory.newLatLng(latLng), new MapboxMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
LatLng cameraPositionLatLng = mapboxMap.getCameraPosition().target;
|
||||
Timber.d(cameraPositionLatLng.toString());
|
||||
assertEquals(cameraPositionLatLng.getLatitude(), latLng.getLatitude(), LAT_LNG_DELTA);
|
||||
assertEquals(cameraPositionLatLng.getLongitude(), latLng.getLongitude(), LAT_LNG_DELTA);
|
||||
}
|
||||
});
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCameraForLatLngBounds() {
|
||||
ViewUtils.checkViewIsDisplayed(R.id.mapView);
|
||||
|
||||
@@ -49,8 +49,9 @@ public abstract class BaseActivityTest {
|
||||
throw new RuntimeException("Could not start test for " + getActivityClass().getSimpleName() + ".\n"
|
||||
+ "The ViewHierarchy doesn't contain a view with resource id = R.id.mapView or \n"
|
||||
+ "the Activity doesn't contain an instance variable with a name equal to mapboxMap.\n"
|
||||
+ "You can resolve this issue be implementing the requirements above or\n add "
|
||||
+ getActivityClass().getSimpleName() + " to the excludeActivities array in `generate-test-code.js`.\n");
|
||||
+ "You can resolve this issue by adding the requirements above or\n add "
|
||||
+ getActivityClass().getSimpleName() + " to the platform/android/scripts/exclude-activity-gen.json to blacklist"
|
||||
+ " the Activity from being generated.\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,8 +68,7 @@ public abstract class BaseActivityTest {
|
||||
protected abstract Class getActivityClass();
|
||||
|
||||
protected void checkViewIsDisplayed(int id) {
|
||||
onView(withId(id))
|
||||
.check(matches(isDisplayed()));
|
||||
onView(withId(id)).check(matches(isDisplayed()));
|
||||
}
|
||||
|
||||
protected void waitLoop() {
|
||||
|
||||
@@ -21,6 +21,7 @@ import com.mapbox.mapboxsdk.testapp.activity.espresso.EspressoTestActivity;
|
||||
import org.hamcrest.Matcher;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import static android.support.test.espresso.Espresso.onData;
|
||||
@@ -67,6 +68,7 @@ public class AttributionTest extends BaseActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testMapboxStreetsMapboxAttributionLink() {
|
||||
validateTestSetup();
|
||||
if (urlSpans == null) {
|
||||
@@ -87,6 +89,7 @@ public class AttributionTest extends BaseActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testMapboxStreetsOpenStreetMapAttributionLink() {
|
||||
validateTestSetup();
|
||||
if (urlSpans == null) {
|
||||
@@ -107,6 +110,7 @@ public class AttributionTest extends BaseActivityTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testImproveMapLink() {
|
||||
validateTestSetup();
|
||||
if (urlSpans == null) {
|
||||
|
||||
@@ -13,10 +13,8 @@ public class OnMapReadyIdlingResource implements IdlingResource, OnMapReadyCallb
|
||||
|
||||
private MapboxMap mapboxMap;
|
||||
private IdlingResource.ResourceCallback resourceCallback;
|
||||
private Activity activity;
|
||||
|
||||
public OnMapReadyIdlingResource(Activity activity) {
|
||||
this.activity = activity;
|
||||
try {
|
||||
Field field = activity.getClass().getDeclaredField("mapView");
|
||||
field.setAccessible(true);
|
||||
@@ -24,7 +22,6 @@ public class OnMapReadyIdlingResource implements IdlingResource, OnMapReadyCallb
|
||||
} catch (Exception err) {
|
||||
throw new RuntimeException(err);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -53,4 +50,4 @@ public class OnMapReadyIdlingResource implements IdlingResource, OnMapReadyCallb
|
||||
resourceCallback.onTransitionToIdle();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,20 @@ import android.animation.AnimatorSet;
|
||||
import android.animation.TypeEvaluator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.util.LongSparseArray;
|
||||
import android.support.v4.view.animation.FastOutLinearInInterpolator;
|
||||
import android.support.v4.view.animation.FastOutSlowInInterpolator;
|
||||
import android.support.v4.view.animation.PathInterpolatorCompat;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.animation.AnticipateOvershootInterpolator;
|
||||
import android.view.animation.BounceInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.mapbox.mapboxsdk.camera.CameraPosition;
|
||||
import com.mapbox.mapboxsdk.camera.CameraUpdateFactory;
|
||||
import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.maps.MapView;
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
@@ -24,6 +31,51 @@ import com.mapbox.mapboxsdk.testapp.R;
|
||||
public class CameraAnimatorActivity extends AppCompatActivity implements OnMapReadyCallback {
|
||||
|
||||
private static final double ANIMATION_DELAY_FACTOR = 1.5;
|
||||
private static final LatLng START_LAT_LNG = new LatLng(37.787947, -122.407432);
|
||||
|
||||
private final LongSparseArray<AnimatorBuilder> animators = new LongSparseArray<AnimatorBuilder>() {
|
||||
{
|
||||
put(R.id.menu_action_accelerate_decelerate_interpolator, new AnimatorBuilder() {
|
||||
@Override
|
||||
public Animator build() {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
animatorSet.playTogether(
|
||||
createLatLngAnimator(START_LAT_LNG, new LatLng(37.826715, -122.422795)),
|
||||
obtainExampleInterpolator(new FastOutSlowInInterpolator(), 2500)
|
||||
);
|
||||
return animatorSet;
|
||||
}
|
||||
});
|
||||
|
||||
put(R.id.menu_action_bounce_interpolator, new AnimatorBuilder() {
|
||||
@Override
|
||||
public Animator build() {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
animatorSet.playTogether(
|
||||
createLatLngAnimator(START_LAT_LNG, new LatLng(37.787947, -122.407432)),
|
||||
obtainExampleInterpolator(new BounceInterpolator(), 3750)
|
||||
);
|
||||
return animatorSet;
|
||||
}
|
||||
});
|
||||
|
||||
put(R.id.menu_action_anticipate_overshoot_interpolator, new AnimatorBuilder() {
|
||||
@Override
|
||||
public Animator build() {
|
||||
return obtainExampleInterpolator(new AnticipateOvershootInterpolator(), 2500);
|
||||
}
|
||||
});
|
||||
|
||||
put(R.id.menu_action_path_interpolator, new AnimatorBuilder() {
|
||||
@Override
|
||||
public Animator build() {
|
||||
return obtainExampleInterpolator(
|
||||
PathInterpolatorCompat.create(.22f, .68f, 0, 1.71f), 2500);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
private MapView mapView;
|
||||
private MapboxMap mapboxMap;
|
||||
@@ -32,7 +84,6 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.activity_camera_animator);
|
||||
|
||||
mapView = (MapView) findViewById(R.id.mapView);
|
||||
if (mapView != null) {
|
||||
mapView.onCreate(savedInstanceState);
|
||||
@@ -43,27 +94,42 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
|
||||
@Override
|
||||
public void onMapReady(final MapboxMap map) {
|
||||
mapboxMap = map;
|
||||
initFab();
|
||||
}
|
||||
|
||||
private void initFab() {
|
||||
findViewById(R.id.fab).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
view.setVisibility(View.GONE);
|
||||
createAnimator(mapboxMap.getCameraPosition()).start();
|
||||
|
||||
CameraPosition animatedPosition = new CameraPosition.Builder()
|
||||
.target(new LatLng(37.789992, -122.402214))
|
||||
.tilt(60)
|
||||
.zoom(14.5f)
|
||||
.bearing(135)
|
||||
.build();
|
||||
|
||||
createExampleAnimator(mapboxMap.getCameraPosition(), animatedPosition).start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private Animator createAnimator(CameraPosition currentPosition) {
|
||||
//
|
||||
// Animator API used for the animation on the FAB
|
||||
//
|
||||
|
||||
private Animator createExampleAnimator(CameraPosition currentPosition, CameraPosition targetPosition) {
|
||||
AnimatorSet animatorSet = new AnimatorSet();
|
||||
animatorSet.play(createLatLngAnimator(currentPosition.target));
|
||||
animatorSet.play(createZoomAnimator(currentPosition.zoom));
|
||||
animatorSet.play(createBearingAnimator(currentPosition.bearing));
|
||||
animatorSet.play(createTiltAnimator(currentPosition.tilt));
|
||||
animatorSet.play(createLatLngAnimator(currentPosition.target, targetPosition.target));
|
||||
animatorSet.play(createZoomAnimator(currentPosition.zoom, targetPosition.zoom));
|
||||
animatorSet.play(createBearingAnimator(currentPosition.bearing, targetPosition.bearing));
|
||||
animatorSet.play(createTiltAnimator(currentPosition.tilt, targetPosition.tilt));
|
||||
return animatorSet;
|
||||
}
|
||||
|
||||
private Animator createLatLngAnimator(LatLng currentPosition) {
|
||||
LatLng target = new LatLng(37.789992, -122.402214);
|
||||
ValueAnimator latLngAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), currentPosition, target);
|
||||
private Animator createLatLngAnimator(LatLng currentPosition, LatLng targetPosition) {
|
||||
ValueAnimator latLngAnimator = ValueAnimator.ofObject(new LatLngEvaluator(), currentPosition, targetPosition);
|
||||
latLngAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR));
|
||||
latLngAnimator.setInterpolator(new FastOutSlowInInterpolator());
|
||||
latLngAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@@ -75,8 +141,8 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
|
||||
return latLngAnimator;
|
||||
}
|
||||
|
||||
private Animator createZoomAnimator(double currentZoom) {
|
||||
ValueAnimator zoomAnimator = ValueAnimator.ofFloat((float) currentZoom, 14.5f);
|
||||
private Animator createZoomAnimator(double currentZoom, double targetZoom) {
|
||||
ValueAnimator zoomAnimator = ValueAnimator.ofFloat((float) currentZoom, (float) targetZoom);
|
||||
zoomAnimator.setDuration((long) (2200 * ANIMATION_DELAY_FACTOR));
|
||||
zoomAnimator.setStartDelay((long) (600 * ANIMATION_DELAY_FACTOR));
|
||||
zoomAnimator.setInterpolator(new AnticipateOvershootInterpolator());
|
||||
@@ -89,8 +155,8 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
|
||||
return zoomAnimator;
|
||||
}
|
||||
|
||||
private Animator createBearingAnimator(double currentBearing) {
|
||||
ValueAnimator bearingAnimator = ValueAnimator.ofFloat((float) currentBearing, 135);
|
||||
private Animator createBearingAnimator(double currentBearing, double targetBearing) {
|
||||
ValueAnimator bearingAnimator = ValueAnimator.ofFloat((float) currentBearing, (float) targetBearing);
|
||||
bearingAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR));
|
||||
bearingAnimator.setStartDelay((long) (1000 * ANIMATION_DELAY_FACTOR));
|
||||
bearingAnimator.setInterpolator(new FastOutLinearInInterpolator());
|
||||
@@ -103,8 +169,8 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
|
||||
return bearingAnimator;
|
||||
}
|
||||
|
||||
private Animator createTiltAnimator(double currentTilt) {
|
||||
ValueAnimator tiltAnimator = ValueAnimator.ofFloat((float) currentTilt, 60);
|
||||
private Animator createTiltAnimator(double currentTilt, double targetTilt) {
|
||||
ValueAnimator tiltAnimator = ValueAnimator.ofFloat((float) currentTilt, (float) targetTilt);
|
||||
tiltAnimator.setDuration((long) (1000 * ANIMATION_DELAY_FACTOR));
|
||||
tiltAnimator.setStartDelay((long) (1500 * ANIMATION_DELAY_FACTOR));
|
||||
tiltAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@@ -116,20 +182,66 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
|
||||
return tiltAnimator;
|
||||
}
|
||||
|
||||
private static class LatLngEvaluator implements TypeEvaluator<LatLng> {
|
||||
//
|
||||
// Interpolator examples
|
||||
//
|
||||
|
||||
private final LatLng latLng = new LatLng();
|
||||
private Animator obtainExampleInterpolator(int menuItemId) {
|
||||
return animators.get(menuItemId).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
|
||||
latLng.setLatitude(startValue.getLatitude()
|
||||
+ ((endValue.getLatitude() - startValue.getLatitude()) * fraction));
|
||||
latLng.setLongitude(startValue.getLongitude()
|
||||
+ ((endValue.getLongitude() - startValue.getLongitude()) * fraction));
|
||||
return latLng;
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_animator, menu);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (mapboxMap == null) {
|
||||
return false;
|
||||
}
|
||||
findViewById(R.id.fab).setVisibility(View.GONE);
|
||||
resetCameraPosition();
|
||||
playAnimation(item.getItemId());
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
private void resetCameraPosition() {
|
||||
mapboxMap.moveCamera(CameraUpdateFactory.newCameraPosition(
|
||||
new CameraPosition.Builder()
|
||||
.target(START_LAT_LNG)
|
||||
.zoom(11)
|
||||
.bearing(0)
|
||||
.tilt(0)
|
||||
.build()
|
||||
));
|
||||
}
|
||||
|
||||
private void playAnimation(int itemId) {
|
||||
Animator animator = obtainExampleInterpolator(itemId);
|
||||
if (animator != null) {
|
||||
animator.start();
|
||||
}
|
||||
}
|
||||
|
||||
private Animator obtainExampleInterpolator(Interpolator interpolator, long duration) {
|
||||
ValueAnimator zoomAnimator = ValueAnimator.ofFloat(11.0f, 16.0f);
|
||||
zoomAnimator.setDuration((long) (duration * ANIMATION_DELAY_FACTOR));
|
||||
zoomAnimator.setInterpolator(interpolator);
|
||||
zoomAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
mapboxMap.setZoom((Float) animation.getAnimatedValue());
|
||||
}
|
||||
});
|
||||
return zoomAnimator;
|
||||
}
|
||||
|
||||
//
|
||||
// MapView lifecycle
|
||||
//
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
@@ -171,4 +283,25 @@ public class CameraAnimatorActivity extends AppCompatActivity implements OnMapRe
|
||||
super.onLowMemory();
|
||||
mapView.onLowMemory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to evaluate LatLng objects with a ValueAnimator
|
||||
*/
|
||||
private static class LatLngEvaluator implements TypeEvaluator<LatLng> {
|
||||
|
||||
private final LatLng latLng = new LatLng();
|
||||
|
||||
@Override
|
||||
public LatLng evaluate(float fraction, LatLng startValue, LatLng endValue) {
|
||||
latLng.setLatitude(startValue.getLatitude()
|
||||
+ ((endValue.getLatitude() - startValue.getLatitude()) * fraction));
|
||||
latLng.setLongitude(startValue.getLongitude()
|
||||
+ ((endValue.getLongitude() - startValue.getLongitude()) * fraction));
|
||||
return latLng;
|
||||
}
|
||||
}
|
||||
|
||||
interface AnimatorBuilder {
|
||||
Animator build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package com.mapbox.mapboxsdk.testapp.activity.camera;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
@@ -28,11 +27,13 @@ import timber.log.Timber;
|
||||
/**
|
||||
* Test activity showcasing how to listen to camera change events.
|
||||
*/
|
||||
public class CameraPositionActivity extends AppCompatActivity implements OnMapReadyCallback {
|
||||
public class CameraPositionActivity extends AppCompatActivity implements OnMapReadyCallback, View.OnClickListener,
|
||||
MapboxMap.OnMapLongClickListener {
|
||||
|
||||
private MapView mapView;
|
||||
private MapboxMap mapboxMap;
|
||||
private FloatingActionButton fab;
|
||||
private boolean logCameraChanges;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -47,96 +48,48 @@ public class CameraPositionActivity extends AppCompatActivity implements OnMapRe
|
||||
@Override
|
||||
public void onMapReady(@NonNull final MapboxMap map) {
|
||||
mapboxMap = map;
|
||||
|
||||
mapboxMap.setOnCameraIdleListener(new MapboxMap.OnCameraIdleListener() {
|
||||
@Override
|
||||
public void onCameraIdle() {
|
||||
Timber.e("OnCameraIdle");
|
||||
fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_green_dark));
|
||||
}
|
||||
});
|
||||
|
||||
mapboxMap.setOnCameraMoveCancelListener(new MapboxMap.OnCameraMoveCanceledListener() {
|
||||
@Override
|
||||
public void onCameraMoveCanceled() {
|
||||
Timber.e("OnCameraMoveCanceled");
|
||||
}
|
||||
});
|
||||
|
||||
mapboxMap.setOnCameraMoveListener(new MapboxMap.OnCameraMoveListener() {
|
||||
@Override
|
||||
public void onCameraMove() {
|
||||
Timber.e("OnCameraMove");
|
||||
fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_orange_dark));
|
||||
}
|
||||
});
|
||||
|
||||
mapboxMap.setOnCameraMoveStartedListener(new MapboxMap.OnCameraMoveStartedListener() {
|
||||
|
||||
private final String[] REASONS = {"REASON_API_GESTURE", "REASON_DEVELOPER_ANIMATION", "REASON_API_ANIMATION"};
|
||||
|
||||
@Override
|
||||
public void onCameraMoveStarted(int reason) {
|
||||
// reason ranges from 1 <-> 3
|
||||
fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_red_dark));
|
||||
Timber.e("OnCameraMoveStarted: %s", REASONS[reason - 1]);
|
||||
}
|
||||
});
|
||||
toggleLogCameraChanges();
|
||||
|
||||
// add a listener to FAB
|
||||
fab = (FloatingActionButton) findViewById(R.id.fab);
|
||||
fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, R.color.primary));
|
||||
fab.setOnClickListener(new View.OnClickListener() {
|
||||
@SuppressLint("InflateParams")
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Context context = view.getContext();
|
||||
final View dialogContent = LayoutInflater.from(context).inflate(R.layout.dialog_camera_position, null);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(
|
||||
context, com.mapbox.mapboxsdk.R.style.mapbox_AlertDialogStyle);
|
||||
builder.setTitle(R.string.dialog_camera_position);
|
||||
builder.setView(onInflateDialogContent(dialogContent));
|
||||
builder.setPositiveButton("Animate", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
double latitude = Double.parseDouble(
|
||||
((TextView) dialogContent.findViewById(R.id.value_lat)).getText().toString());
|
||||
double longitude = Double.parseDouble(
|
||||
((TextView) dialogContent.findViewById(R.id.value_lon)).getText().toString());
|
||||
double zoom = Double.parseDouble(
|
||||
((TextView) dialogContent.findViewById(R.id.value_zoom)).getText().toString());
|
||||
double bearing = Double.parseDouble(
|
||||
((TextView) dialogContent.findViewById(R.id.value_bearing)).getText().toString());
|
||||
double tilt = Double.parseDouble(
|
||||
((TextView) dialogContent.findViewById(R.id.value_tilt)).getText().toString());
|
||||
fab.setOnClickListener(this);
|
||||
|
||||
CameraPosition cameraPosition = new CameraPosition.Builder()
|
||||
.target(new LatLng(latitude, longitude))
|
||||
.zoom(zoom)
|
||||
.bearing(bearing)
|
||||
.tilt(tilt)
|
||||
.build();
|
||||
// listen to long click events to toggle logging camera changes
|
||||
mapboxMap.setOnMapLongClickListener(this);
|
||||
}
|
||||
|
||||
mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), 5000,
|
||||
new MapboxMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
Timber.v("OnCancel called");
|
||||
}
|
||||
@Override
|
||||
public void onMapLongClick(@NonNull LatLng point) {
|
||||
toggleLogCameraChanges();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
Timber.v("OnFinish called");
|
||||
}
|
||||
});
|
||||
Timber.v(cameraPosition.toString());
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton("Cancel", null);
|
||||
builder.setCancelable(false);
|
||||
builder.show();
|
||||
}
|
||||
});
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
Context context = view.getContext();
|
||||
final View dialogContent = LayoutInflater.from(context).inflate(R.layout.dialog_camera_position, null);
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.dialog_camera_position);
|
||||
builder.setView(onInflateDialogContent(dialogContent));
|
||||
builder.setPositiveButton("Animate", new DialogClickListener(mapboxMap, dialogContent));
|
||||
builder.setNegativeButton("Cancel", null);
|
||||
builder.setCancelable(false);
|
||||
builder.show();
|
||||
}
|
||||
|
||||
private void toggleLogCameraChanges() {
|
||||
logCameraChanges = !logCameraChanges;
|
||||
if (logCameraChanges) {
|
||||
mapboxMap.addOnCameraIdleListener(idleListener);
|
||||
mapboxMap.addOnCameraMoveCancelListener(moveCanceledListener);
|
||||
mapboxMap.addOnCameraMoveListener(moveListener);
|
||||
mapboxMap.addOnCameraMoveStartedListener(moveStartedListener);
|
||||
} else {
|
||||
mapboxMap.removeOnCameraIdleListener(idleListener);
|
||||
mapboxMap.removeOnCameraMoveCancelListener(moveCanceledListener);
|
||||
mapboxMap.removeOnCameraMoveListener(moveListener);
|
||||
mapboxMap.removeOnCameraMoveStartedListener(moveStartedListener);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -193,6 +146,42 @@ public class CameraPositionActivity extends AppCompatActivity implements OnMapRe
|
||||
seekBar.setProgress(defaultValue);
|
||||
}
|
||||
|
||||
private MapboxMap.OnCameraIdleListener idleListener = new MapboxMap.OnCameraIdleListener() {
|
||||
@Override
|
||||
public void onCameraIdle() {
|
||||
Timber.e("OnCameraIdle");
|
||||
fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_green_dark));
|
||||
}
|
||||
};
|
||||
|
||||
private MapboxMap.OnCameraMoveListener moveListener = new MapboxMap.OnCameraMoveListener() {
|
||||
@Override
|
||||
public void onCameraMove() {
|
||||
Timber.e("OnCameraMove");
|
||||
fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_orange_dark));
|
||||
}
|
||||
};
|
||||
|
||||
private MapboxMap.OnCameraMoveCanceledListener moveCanceledListener = new MapboxMap.OnCameraMoveCanceledListener() {
|
||||
@Override
|
||||
public void onCameraMoveCanceled() {
|
||||
Timber.e("OnCameraMoveCanceled");
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
private MapboxMap.OnCameraMoveStartedListener moveStartedListener = new MapboxMap.OnCameraMoveStartedListener() {
|
||||
|
||||
private final String[] REASONS = {"REASON_API_GESTURE", "REASON_DEVELOPER_ANIMATION", "REASON_API_ANIMATION"};
|
||||
|
||||
@Override
|
||||
public void onCameraMoveStarted(int reason) {
|
||||
// reason ranges from 1 <-> 3
|
||||
fab.setColorFilter(ContextCompat.getColor(CameraPositionActivity.this, android.R.color.holo_red_dark));
|
||||
Timber.e("OnCameraMoveStarted: %s", REASONS[reason - 1]);
|
||||
}
|
||||
};
|
||||
|
||||
private class ValueChangeListener implements SeekBar.OnSeekBarChangeListener {
|
||||
|
||||
protected TextView textView;
|
||||
@@ -224,4 +213,50 @@ public class CameraPositionActivity extends AppCompatActivity implements OnMapRe
|
||||
super.onProgressChanged(seekBar, progress - 180, fromUser);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DialogClickListener implements DialogInterface.OnClickListener {
|
||||
|
||||
private MapboxMap mapboxMap;
|
||||
private View dialogContent;
|
||||
|
||||
public DialogClickListener(MapboxMap mapboxMap, View view) {
|
||||
this.mapboxMap = mapboxMap;
|
||||
this.dialogContent = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
double latitude = Double.parseDouble(
|
||||
((TextView) dialogContent.findViewById(R.id.value_lat)).getText().toString());
|
||||
double longitude = Double.parseDouble(
|
||||
((TextView) dialogContent.findViewById(R.id.value_lon)).getText().toString());
|
||||
double zoom = Double.parseDouble(
|
||||
((TextView) dialogContent.findViewById(R.id.value_zoom)).getText().toString());
|
||||
double bearing = Double.parseDouble(
|
||||
((TextView) dialogContent.findViewById(R.id.value_bearing)).getText().toString());
|
||||
double tilt = Double.parseDouble(
|
||||
((TextView) dialogContent.findViewById(R.id.value_tilt)).getText().toString());
|
||||
|
||||
CameraPosition cameraPosition = new CameraPosition.Builder()
|
||||
.target(new LatLng(latitude, longitude))
|
||||
.zoom(zoom)
|
||||
.bearing(bearing)
|
||||
.tilt(tilt)
|
||||
.build();
|
||||
|
||||
mapboxMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition), 5000,
|
||||
new MapboxMap.CancelableCallback() {
|
||||
@Override
|
||||
public void onCancel() {
|
||||
Timber.v("OnCancel called");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinish() {
|
||||
Timber.v("OnFinish called");
|
||||
}
|
||||
});
|
||||
Timber.v(cameraPosition.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -264,6 +264,7 @@ public class OfflineActivity extends AppCompatActivity
|
||||
if (status.isComplete()) {
|
||||
// Download complete
|
||||
endProgress("Region downloaded successfully.");
|
||||
offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE);
|
||||
offlineRegion.setObserver(null);
|
||||
return;
|
||||
} else if (status.isRequiredResourceCountPrecise()) {
|
||||
@@ -281,11 +282,13 @@ public class OfflineActivity extends AppCompatActivity
|
||||
@Override
|
||||
public void onError(OfflineRegionError error) {
|
||||
Timber.e("onError: %s, %s", error.getReason(), error.getMessage());
|
||||
offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mapboxTileCountLimitExceeded(long limit) {
|
||||
Timber.e("Mapbox tile count limit exceeded: %s", limit);
|
||||
offlineRegion.setDownloadState(OfflineRegion.STATE_INACTIVE);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
package com.mapbox.mapboxsdk.testapp.activity.style;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PointF;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
@@ -32,7 +33,7 @@ import com.mapbox.services.commons.geojson.custom.PositionDeserializer;
|
||||
import com.mapbox.services.commons.models.Position;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import timber.log.Timber;
|
||||
@@ -64,49 +65,10 @@ public class SymbolGeneratorActivity extends AppCompatActivity implements OnMapR
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMapReady(MapboxMap map) {
|
||||
public void onMapReady(final MapboxMap map) {
|
||||
mapboxMap = map;
|
||||
try {
|
||||
// read local geojson from raw folder
|
||||
String tinyCountriesJson = ResourceUtils.readRawResource(this, R.raw.tiny_countries);
|
||||
|
||||
// convert geojson to a model
|
||||
FeatureCollection featureCollection = new GsonBuilder()
|
||||
.registerTypeAdapter(Geometry.class, new GeometryDeserializer())
|
||||
.registerTypeAdapter(Position.class, new PositionDeserializer())
|
||||
.create().fromJson(tinyCountriesJson, FeatureCollection.class);
|
||||
|
||||
// add a geojson to the map
|
||||
Source source = new GeoJsonSource(SOURCE_ID, featureCollection);
|
||||
mapboxMap.addSource(source);
|
||||
|
||||
// for each feature add a symbolLayer
|
||||
for (Feature feature : featureCollection.getFeatures()) {
|
||||
String countryName = feature.getStringProperty(FEATURE_ID);
|
||||
|
||||
// create View
|
||||
TextView textView = new TextView(this);
|
||||
textView.setBackgroundColor(getResources().getColor(R.color.blueAccent));
|
||||
textView.setPadding(10, 5, 10, 5);
|
||||
textView.setTextColor(Color.WHITE);
|
||||
textView.setText(countryName);
|
||||
|
||||
// create bitmap from view
|
||||
mapboxMap.addImage(countryName, SymbolGenerator.generate(textView));
|
||||
}
|
||||
|
||||
// create layer use
|
||||
mapboxMap.addLayer(new SymbolLayer(LAYER_ID, SOURCE_ID)
|
||||
.withProperties(
|
||||
iconImage("{" + FEATURE_ID + "}"), // { } is a token notation
|
||||
iconAllowOverlap(false)
|
||||
)
|
||||
);
|
||||
|
||||
addSymbolClickListener();
|
||||
} catch (IOException exception) {
|
||||
Timber.e(exception);
|
||||
}
|
||||
addSymbolClickListener();
|
||||
new LoadDataTask(map, SymbolGeneratorActivity.this).execute();
|
||||
}
|
||||
|
||||
private void addSymbolClickListener() {
|
||||
@@ -213,4 +175,91 @@ public class SymbolGeneratorActivity extends AppCompatActivity implements OnMapR
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class LoadDataTask extends AsyncTask<Void, Void, FeatureCollection> {
|
||||
|
||||
private final MapboxMap mapboxMap;
|
||||
private final Context context;
|
||||
|
||||
LoadDataTask(MapboxMap mapboxMap, Context context) {
|
||||
this.mapboxMap = mapboxMap;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FeatureCollection doInBackground(Void... params) {
|
||||
try {
|
||||
// read local geojson from raw folder
|
||||
String tinyCountriesJson = ResourceUtils.readRawResource(context, R.raw.tiny_countries);
|
||||
|
||||
// convert geojson to a model
|
||||
FeatureCollection featureCollection = new GsonBuilder()
|
||||
.registerTypeAdapter(Geometry.class, new GeometryDeserializer())
|
||||
.registerTypeAdapter(Position.class, new PositionDeserializer())
|
||||
.create().fromJson(tinyCountriesJson, FeatureCollection.class);
|
||||
|
||||
return featureCollection;
|
||||
} catch (IOException exception) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(FeatureCollection featureCollection) {
|
||||
super.onPostExecute(featureCollection);
|
||||
if (featureCollection == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add a geojson to the map
|
||||
Source source = new GeoJsonSource(SOURCE_ID, featureCollection);
|
||||
mapboxMap.addSource(source);
|
||||
|
||||
// create layer use
|
||||
mapboxMap.addLayer(new SymbolLayer(LAYER_ID, SOURCE_ID)
|
||||
.withProperties(
|
||||
iconImage("{" + FEATURE_ID + "}"), // { } is a token notation
|
||||
iconAllowOverlap(false)
|
||||
)
|
||||
);
|
||||
|
||||
new GenerateSymbolTask(mapboxMap, context).execute(featureCollection);
|
||||
}
|
||||
}
|
||||
|
||||
private static class GenerateSymbolTask extends AsyncTask<FeatureCollection, Void, HashMap<String, Bitmap>> {
|
||||
|
||||
private MapboxMap mapboxMap;
|
||||
private Context context;
|
||||
|
||||
GenerateSymbolTask(MapboxMap mapboxMap, Context context) {
|
||||
this.mapboxMap = mapboxMap;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@SuppressWarnings("WrongThread")
|
||||
@Override
|
||||
protected HashMap<String, Bitmap> doInBackground(FeatureCollection... params) {
|
||||
FeatureCollection featureCollection = params[0];
|
||||
|
||||
HashMap<String, Bitmap> imagesMap = new HashMap<>();
|
||||
for (Feature feature : featureCollection.getFeatures()) {
|
||||
String countryName = feature.getStringProperty(FEATURE_ID);
|
||||
TextView textView = new TextView(context);
|
||||
textView.setBackgroundColor(context.getResources().getColor(R.color.blueAccent));
|
||||
textView.setPadding(10, 5, 10, 5);
|
||||
textView.setTextColor(Color.WHITE);
|
||||
textView.setText(countryName);
|
||||
imagesMap.put(countryName, SymbolGenerator.generate(textView));
|
||||
}
|
||||
return imagesMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(HashMap<String, Bitmap> bitmapHashMap) {
|
||||
super.onPostExecute(bitmapHashMap);
|
||||
mapboxMap.addImages(bitmapHashMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,7 @@ import com.mapbox.mapboxsdk.geometry.LatLng;
|
||||
import com.mapbox.mapboxsdk.maps.MapView;
|
||||
import com.mapbox.mapboxsdk.maps.MapboxMap;
|
||||
import com.mapbox.mapboxsdk.maps.OnMapReadyCallback;
|
||||
import com.mapbox.mapboxsdk.style.layers.Property;
|
||||
import com.mapbox.mapboxsdk.style.layers.SymbolLayer;
|
||||
import com.mapbox.mapboxsdk.style.sources.GeoJsonSource;
|
||||
import com.mapbox.mapboxsdk.testapp.R;
|
||||
@@ -32,6 +33,7 @@ import static com.mapbox.mapboxsdk.style.functions.stops.Stops.interval;
|
||||
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconAllowOverlap;
|
||||
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconImage;
|
||||
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.iconSize;
|
||||
import static com.mapbox.mapboxsdk.style.layers.PropertyFactory.visibility;
|
||||
|
||||
/**
|
||||
* Test activity showcasing changing the icon with a zoom function and adding selection state to a SymbolLayer.
|
||||
@@ -49,9 +51,11 @@ public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity {
|
||||
private MapView mapView;
|
||||
private MapboxMap mapboxMap;
|
||||
private GeoJsonSource source;
|
||||
private SymbolLayer layer;
|
||||
|
||||
private boolean isInitialPosition = true;
|
||||
private boolean isSelected = false;
|
||||
private boolean isShowingSymbolLayer = true;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
@@ -81,6 +85,13 @@ public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity {
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleSymbolLayerVisibility() {
|
||||
layer.setProperties(
|
||||
visibility(isShowingSymbolLayer ? Property.NONE : Property.VISIBLE)
|
||||
);
|
||||
isShowingSymbolLayer = !isShowingSymbolLayer;
|
||||
}
|
||||
|
||||
private FeatureCollection createFeatureCollection() {
|
||||
Position position = isInitialPosition
|
||||
? Position.fromCoordinates(-74.01618140, 40.701745)
|
||||
@@ -95,7 +106,7 @@ public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity {
|
||||
}
|
||||
|
||||
private void addLayer() {
|
||||
SymbolLayer layer = new SymbolLayer(LAYER_ID, SOURCE_ID);
|
||||
layer = new SymbolLayer(LAYER_ID, SOURCE_ID);
|
||||
layer.setProperties(
|
||||
iconImage(
|
||||
zoom(
|
||||
@@ -145,9 +156,13 @@ public class ZoomFunctionSymbolLayerActivity extends AppCompatActivity {
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (mapboxMap != null && item.getItemId() == R.id.menu_action_change_location) {
|
||||
isInitialPosition = !isInitialPosition;
|
||||
updateSource();
|
||||
if (mapboxMap != null) {
|
||||
if (item.getItemId() == R.id.menu_action_change_location) {
|
||||
isInitialPosition = !isInitialPosition;
|
||||
updateSource();
|
||||
} else if (item.getItemId() == R.id.menu_action_toggle_source) {
|
||||
toggleSymbolLayerVisibility();
|
||||
}
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
android:id="@id/mapView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:mapbox_cameraTargetLat="37.774913"
|
||||
app:mapbox_cameraTargetLng="-122.419368"
|
||||
app:mapbox_cameraTargetLat="37.787947"
|
||||
app:mapbox_cameraTargetLng="-122.407432"
|
||||
app:mapbox_cameraZoom="11"
|
||||
app:mapbox_styleUrl="@string/mapbox_style_mapbox_streets"/>
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item
|
||||
android:id="@+id/menu_action_accelerate_decelerate_interpolator"
|
||||
android:title="@string/menuitem_title_accelerate_decelerate"
|
||||
app:showAsAction="never"/>
|
||||
<item
|
||||
android:id="@+id/menu_action_bounce_interpolator"
|
||||
android:title="@string/menuitem_title_bounce"
|
||||
app:showAsAction="never"/>
|
||||
<item
|
||||
android:id="@+id/menu_action_anticipate_overshoot_interpolator"
|
||||
android:title="@string/menuitem_title_anticipate_overshoot"
|
||||
app:showAsAction="never"/>
|
||||
<item
|
||||
android:id="@+id/menu_action_path_interpolator"
|
||||
android:title="@string/menuitem_title_path"
|
||||
app:showAsAction="never"/>
|
||||
</menu>
|
||||
@@ -5,4 +5,8 @@
|
||||
android:id="@+id/menu_action_change_location"
|
||||
android:title="@string/menuitem_change_location"
|
||||
app:showAsAction="never"/>
|
||||
<item
|
||||
android:id="@+id/menu_action_toggle_source"
|
||||
android:title="@string/menuitem_toggle_symbol_layer_visibility"
|
||||
app:showAsAction="never"/>
|
||||
</menu>
|
||||
|
||||
@@ -12,6 +12,11 @@
|
||||
<string name="menuitem_title_change_location_source_null">Reset location source to null</string>
|
||||
<string name="menuitem_change_icon_overlap">Toggle icon overlap</string>
|
||||
<string name="menuitem_change_location">Change location</string>
|
||||
<string name="menuitem_title_accelerate_decelerate">Accelerate/Decelerate interpolator</string>
|
||||
<string name="menuitem_title_bounce">Bounce interpolator</string>
|
||||
<string name="menuitem_title_anticipate_overshoot">Anticipate/Overshoot interpolator</string>
|
||||
<string name="menuitem_title_path">PathInterpolator interpolator</string>
|
||||
<string name="menuitem_toggle_symbol_layer_visibility">Toggle Symbol Layer Visibility</string>
|
||||
<string name="button_camera_move">Move</string>
|
||||
<string name="button_camera_ease">Ease</string>
|
||||
<string name="button_camera_animate">Animate</string>
|
||||
|
||||
@@ -4,8 +4,6 @@ buildscript {
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.3.1'
|
||||
classpath 'com.amazonaws:aws-devicefarm-gradle-plugin:1.2'
|
||||
classpath 'com.stanfy.spoon:spoon-gradle-plugin:1.2.1'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -142,6 +142,8 @@ add_library(mbgl-android STATIC
|
||||
platform/android/src/style/conversion/types_string_values.hpp
|
||||
platform/android/src/map/camera_position.cpp
|
||||
platform/android/src/map/camera_position.hpp
|
||||
platform/android/src/map/image.cpp
|
||||
platform/android/src/map/image.hpp
|
||||
|
||||
# Style conversion Java -> C++
|
||||
platform/android/src/style/android_conversion.hpp
|
||||
|
||||
@@ -27,7 +27,6 @@ ext {
|
||||
mockito : 'org.mockito:mockito-core:2.10.0',
|
||||
|
||||
// instrumentation test
|
||||
testSpoonRunner : 'com.squareup.spoon:spoon-client:1.7.1',
|
||||
testRunner : "com.android.support.test:runner:${testRunnerVersion}",
|
||||
testRules : "com.android.support.test:rules:${testRunnerVersion}",
|
||||
testEspressoCore : "com.android.support.test.espresso:espresso-core:${espressoVersion}",
|
||||
@@ -36,7 +35,7 @@ ext {
|
||||
// support
|
||||
supportAnnotations : "com.android.support:support-annotations:${supportLibVersion}",
|
||||
supportAppcompatV7 : "com.android.support:appcompat-v7:${supportLibVersion}",
|
||||
supportV4 : "com.android.support:support-v4:${supportLibVersion}",
|
||||
supportFragmentV4 : "com.android.support:support-fragment:${supportLibVersion}",
|
||||
supportDesign : "com.android.support:design:${supportLibVersion}",
|
||||
supportRecyclerView : "com.android.support:recyclerview-v7:${supportLibVersion}",
|
||||
|
||||
|
||||
31
platform/android/scripts/exclude-activity-gen.json
Normal file
31
platform/android/scripts/exclude-activity-gen.json
Normal file
@@ -0,0 +1,31 @@
|
||||
[
|
||||
"BaseLocationActivity",
|
||||
"MapSnapshotterMarkerActivity",
|
||||
"MapSnapshotterReuseActivity",
|
||||
"LatLngBoundsActivity",
|
||||
"BottomSheetActivity",
|
||||
"MapSnapshotterActivity",
|
||||
"MockLocationEngine",
|
||||
"DeleteRegionActivity",
|
||||
"RealTimeGeoJsonActivity",
|
||||
"UpdateMetadataActivity",
|
||||
"CarDrivingActivity",
|
||||
"MyLocationTrackingModeActivity",
|
||||
"MyLocationToggleActivity",
|
||||
"MyLocationTintActivity",
|
||||
"MyLocationDrawableActivity",
|
||||
"DoubleMapActivity",
|
||||
"LocationPickerActivity",
|
||||
"GeoJsonClusteringActivity",
|
||||
"RuntimeStyleTestActivity",
|
||||
"AnimatedMarkerActivity",
|
||||
"ViewPagerActivity",
|
||||
"MapFragmentActivity",
|
||||
"SupportMapFragmentActivity",
|
||||
"SnapshotActivity",
|
||||
"NavigationDrawerActivity",
|
||||
"QueryRenderedFeaturesBoxHighlightActivity",
|
||||
"MultiMapActivity",
|
||||
"MapInDialogActivity",
|
||||
"SimpleMapActivity"
|
||||
]
|
||||
@@ -13,8 +13,7 @@ global.camelize = function (str) {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
const excludeActivities = ["BaseLocationActivity","MockLocationEngine","DeleteRegionActivity","RealTimeGeoJsonActivity","UpdateMetadataActivity","CarDrivingActivity","MyLocationTrackingModeActivity","MyLocationToggleActivity","MyLocationTintActivity","MyLocationDrawableActivity","DoubleMapActivity", "LocationPickerActivity","GeoJsonClusteringActivity","RuntimeStyleTestActivity", "AnimatedMarkerActivity", "ViewPagerActivity","MapFragmentActivity","SupportMapFragmentActivity","SnapshotActivity","NavigationDrawerActivity", "QueryRenderedFeaturesBoxHighlightActivity", "MultiMapActivity", "MapInDialogActivity", "SimpleMapActivity"];
|
||||
const excludeClasses = JSON.parse(fs.readFileSync('platform/android/scripts/exclude-activity-gen.json', 'utf8'));
|
||||
const appBasePath = 'platform/android/MapboxGLAndroidSDKTestApp/src/main/java/com/mapbox/mapboxsdk/testapp/activity';
|
||||
const testBasePath = 'platform/android/MapboxGLAndroidSDKTestApp/src/androidTest/java/com/mapbox/mapboxsdk/testapp/activity/gen';
|
||||
const subPackages = fs.readdirSync(appBasePath);
|
||||
@@ -24,7 +23,9 @@ if (!fs.existsSync(testBasePath)){
|
||||
fs.mkdirSync(testBasePath);
|
||||
}
|
||||
|
||||
console.log("Generating test activities:");
|
||||
console.log("\nGenerating test activities:\n");
|
||||
var generatedClasses = [];
|
||||
var excludedClasses = [];
|
||||
for(const subPackage of subPackages) {
|
||||
if(!(subPackage.slice(-5) == '.java')) {
|
||||
const activities = fs.readdirSync(appBasePath+'/'+subPackage);
|
||||
@@ -45,18 +46,22 @@ for(const subPackage of subPackages) {
|
||||
try {
|
||||
fs.accessSync(filePath, fs.F_OK);
|
||||
fs.unlinkSync(filePath);
|
||||
console.log("Removed file: "+filePath);
|
||||
} catch (e) {
|
||||
console.log("No file found: "+filePath);
|
||||
}
|
||||
|
||||
// only generate test file if not part of exclude list
|
||||
if (!(excludeActivities.indexOf(activityName) > -1)) {
|
||||
console.log("Created file: "+filePath);
|
||||
// only generate test file if not part of exclude list + if contains Activity in name
|
||||
if ((!(excludeClasses.indexOf(activityName) > -1)) && activityName.includes("Activity")) {
|
||||
fs.writeFileSync(filePath, ejsConversionTask([activityName, subPackage]));
|
||||
generatedClasses.push(activityName);
|
||||
}else{
|
||||
console.log("Excluding file: "+filePath);
|
||||
excludedClasses.push(activityName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(const generatedClass of generatedClasses){
|
||||
console.log(generatedClass+"Test");
|
||||
}
|
||||
|
||||
console.log("\nFinished generating " + generatedClasses.length + " activity sanity tests, excluded " + excludeClasses.length + " classes.\n");
|
||||
@@ -112,6 +112,11 @@ AnnotationIDs AndroidRendererFrontend::queryPointAnnotations(const ScreenBox& bo
|
||||
return mapRenderer.actor().ask(&Renderer::queryPointAnnotations, box).get();
|
||||
}
|
||||
|
||||
AnnotationIDs AndroidRendererFrontend::queryShapeAnnotations(const ScreenBox& box) const {
|
||||
// Waits for the result from the orchestration thread and returns
|
||||
return mapRenderer.actor().ask(&Renderer::queryShapeAnnotations, box).get();
|
||||
}
|
||||
|
||||
} // namespace android
|
||||
} // namespace mbgl
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ public:
|
||||
std::vector<Feature> queryRenderedFeatures(const ScreenBox&, const RenderedQueryOptions&) const;
|
||||
std::vector<Feature> querySourceFeatures(const std::string& sourceID, const SourceQueryOptions&) const;
|
||||
AnnotationIDs queryPointAnnotations(const ScreenBox& box) const;
|
||||
AnnotationIDs queryShapeAnnotations(const ScreenBox& box) const;
|
||||
|
||||
// Memory
|
||||
void onLowMemory();
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
#include "asset_manager_file_source.hpp"
|
||||
#include "jni/generic_global_ref_deleter.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
|
||||
@@ -64,6 +62,14 @@ void FileSource::setResourceTransform(jni::JNIEnv& env, jni::Object<FileSource::
|
||||
}
|
||||
}
|
||||
|
||||
void FileSource::resume(jni::JNIEnv&) {
|
||||
fileSource->resume();
|
||||
}
|
||||
|
||||
void FileSource::pause(jni::JNIEnv&) {
|
||||
fileSource->pause();
|
||||
}
|
||||
|
||||
jni::Class<FileSource> FileSource::javaClass;
|
||||
|
||||
FileSource* FileSource::getNativePeer(jni::JNIEnv& env, jni::Object<FileSource> jFileSource) {
|
||||
@@ -93,7 +99,9 @@ void FileSource::registerNative(jni::JNIEnv& env) {
|
||||
METHOD(&FileSource::getAccessToken, "getAccessToken"),
|
||||
METHOD(&FileSource::setAccessToken, "setAccessToken"),
|
||||
METHOD(&FileSource::setAPIBaseUrl, "setApiBaseUrl"),
|
||||
METHOD(&FileSource::setResourceTransform, "setResourceTransform")
|
||||
METHOD(&FileSource::setResourceTransform, "setResourceTransform"),
|
||||
METHOD(&FileSource::resume, "resume"),
|
||||
METHOD(&FileSource::pause, "pause")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -41,6 +41,10 @@ public:
|
||||
|
||||
void setResourceTransform(jni::JNIEnv&, jni::Object<FileSource::ResourceTransformCallback>);
|
||||
|
||||
void resume(jni::JNIEnv&);
|
||||
|
||||
void pause(jni::JNIEnv&);
|
||||
|
||||
static jni::Class<FileSource> javaClass;
|
||||
|
||||
static FileSource* getNativePeer(jni::JNIEnv&, jni::Object<FileSource>);
|
||||
|
||||
@@ -172,6 +172,7 @@ void registerNatives(JavaVM *vm) {
|
||||
|
||||
// Map
|
||||
CameraPosition::registerNative(env);
|
||||
Image::registerNative(env);
|
||||
|
||||
// Connectivity
|
||||
ConnectivityListener::registerNative(env);
|
||||
|
||||
44
platform/android/src/map/image.cpp
Normal file
44
platform/android/src/map/image.cpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#include <mbgl/style/image.hpp>
|
||||
#include <mbgl/util/exception.hpp>
|
||||
#include "image.hpp"
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
|
||||
mbgl::style::Image Image::getImage(jni::JNIEnv& env, jni::Object<Image> image) {
|
||||
static auto widthField = Image::javaClass.GetField<jni::jint>(env, "width");
|
||||
static auto heightField = Image::javaClass.GetField<jni::jint>(env, "height");
|
||||
static auto pixelRatioField = Image::javaClass.GetField<jni::jfloat>(env, "pixelRatio");
|
||||
static auto bufferField = Image::javaClass.GetField<jni::Array<jbyte>>(env, "buffer");
|
||||
static auto nameField = Image::javaClass.GetField<jni::String>(env, "name");
|
||||
|
||||
auto height = image.Get(env, heightField);
|
||||
auto width = image.Get(env, widthField);
|
||||
auto pixelRatio = image.Get(env, pixelRatioField);
|
||||
auto pixels = image.Get(env, bufferField);
|
||||
auto name = jni::Make<std::string>(env, image.Get(env, nameField));
|
||||
|
||||
jni::NullCheck(env, &pixels);
|
||||
std::size_t size = pixels.Length(env);
|
||||
|
||||
mbgl::PremultipliedImage premultipliedImage({ static_cast<uint32_t>(width), static_cast<uint32_t>(height) });
|
||||
if (premultipliedImage.bytes() != uint32_t(size)) {
|
||||
throw mbgl::util::SpriteImageException("Sprite image pixel count mismatch");
|
||||
}
|
||||
|
||||
jni::GetArrayRegion(env, *pixels, 0, size, reinterpret_cast<jbyte*>(premultipliedImage.data.get()));
|
||||
|
||||
return mbgl::style::Image {name, std::move(premultipliedImage), pixelRatio};
|
||||
}
|
||||
|
||||
void Image::registerNative(jni::JNIEnv &env) {
|
||||
// Lookup the class
|
||||
Image::javaClass = *jni::Class<Image>::Find(env).NewGlobalRef(env).release();
|
||||
}
|
||||
|
||||
jni::Class<Image> Image::javaClass;
|
||||
|
||||
|
||||
} // namespace android
|
||||
} // namespace mb
|
||||
|
||||
26
platform/android/src/map/image.hpp
Normal file
26
platform/android/src/map/image.hpp
Normal file
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <mbgl/util/noncopyable.hpp>
|
||||
|
||||
#include <jni/jni.hpp>
|
||||
#include <mbgl/style/image.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
|
||||
class Image : private mbgl::util::noncopyable {
|
||||
public:
|
||||
|
||||
static constexpr auto Name() { return "com/mapbox/mapboxsdk/maps/Image"; };
|
||||
|
||||
static mbgl::style::Image getImage(jni::JNIEnv&, jni::Object<Image>);
|
||||
|
||||
static jni::Class<Image> javaClass;
|
||||
|
||||
static void registerNative(jni::JNIEnv&);
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // namespace android
|
||||
} // namespace mbgl
|
||||
@@ -49,6 +49,7 @@
|
||||
#include "java/util.hpp"
|
||||
#include "geometry/lat_lng_bounds.hpp"
|
||||
#include "map/camera_position.hpp"
|
||||
#include "map/image.hpp"
|
||||
#include "style/light.hpp"
|
||||
#include "bitmap_factory.hpp"
|
||||
|
||||
@@ -633,6 +634,26 @@ jni::Array<jlong> NativeMapView::queryPointAnnotations(JNIEnv& env, jni::Object<
|
||||
return result;
|
||||
}
|
||||
|
||||
jni::Array<jlong> NativeMapView::queryShapeAnnotations(JNIEnv &env, jni::Object<RectF> rect) {
|
||||
using namespace mbgl::style;
|
||||
using namespace mbgl::style::conversion;
|
||||
|
||||
// Convert input
|
||||
mbgl::ScreenBox box = {
|
||||
{RectF::getLeft(env, rect), RectF::getTop(env, rect)},
|
||||
{RectF::getRight(env, rect), RectF::getBottom(env, rect)},
|
||||
};
|
||||
|
||||
mbgl::AnnotationIDs ids = rendererFrontend->queryShapeAnnotations(box);
|
||||
|
||||
// Convert result
|
||||
std::vector<jlong> longIds(ids.begin(), ids.end());
|
||||
auto result = jni::Array<jni::jlong>::New(env, ids.size());
|
||||
result.SetRegion<std::vector<jni::jlong>>(env, 0, longIds);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
jni::Array<jni::Object<geojson::Feature>> NativeMapView::queryRenderedFeaturesForPoint(JNIEnv& env, jni::jfloat x, jni::jfloat y,
|
||||
jni::Array<jni::String> layerIds,
|
||||
jni::Array<jni::Object<>> jfilter) {
|
||||
@@ -904,6 +925,18 @@ void NativeMapView::addImage(JNIEnv& env, jni::String name, jni::jint w, jni::ji
|
||||
float(scale)));
|
||||
}
|
||||
|
||||
void NativeMapView::addImages(JNIEnv& env, jni::Array<jni::Object<mbgl::android::Image>> jimages) {
|
||||
jni::NullCheck(env, &jimages);
|
||||
std::size_t len = jimages.Length(env);
|
||||
|
||||
for (std::size_t i = 0; i < len; i++) {
|
||||
jni::Object<mbgl::android::Image> jimage = jimages.Get(env, i);
|
||||
auto image = mbgl::android::Image::getImage(env, jimage);
|
||||
map->getStyle().addImage(std::make_unique<mbgl::style::Image>(image));
|
||||
jni::DeleteLocalRef(env, jimage);
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMapView::removeImage(JNIEnv& env, jni::String name) {
|
||||
map->getStyle().removeImage(jni::Make<std::string>(env, name));
|
||||
}
|
||||
@@ -1000,6 +1033,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
|
||||
METHOD(&NativeMapView::getTransitionDelay, "nativeGetTransitionDelay"),
|
||||
METHOD(&NativeMapView::setTransitionDelay, "nativeSetTransitionDelay"),
|
||||
METHOD(&NativeMapView::queryPointAnnotations, "nativeQueryPointAnnotations"),
|
||||
METHOD(&NativeMapView::queryShapeAnnotations, "nativeQueryShapeAnnotations"),
|
||||
METHOD(&NativeMapView::queryRenderedFeaturesForPoint, "nativeQueryRenderedFeaturesForPoint"),
|
||||
METHOD(&NativeMapView::queryRenderedFeaturesForBox, "nativeQueryRenderedFeaturesForBox"),
|
||||
METHOD(&NativeMapView::getLight, "nativeGetLight"),
|
||||
@@ -1017,6 +1051,7 @@ void NativeMapView::registerNative(jni::JNIEnv& env) {
|
||||
METHOD(&NativeMapView::removeSourceById, "nativeRemoveSourceById"),
|
||||
METHOD(&NativeMapView::removeSource, "nativeRemoveSource"),
|
||||
METHOD(&NativeMapView::addImage, "nativeAddImage"),
|
||||
METHOD(&NativeMapView::addImages, "nativeAddImages"),
|
||||
METHOD(&NativeMapView::removeImage, "nativeRemoveImage"),
|
||||
METHOD(&NativeMapView::getImage, "nativeGetImage"),
|
||||
METHOD(&NativeMapView::setLatLngBounds, "nativeSetLatLngBounds"),
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "style/sources/sources.hpp"
|
||||
#include "geometry/lat_lng_bounds.hpp"
|
||||
#include "map/camera_position.hpp"
|
||||
#include "map/image.hpp"
|
||||
#include "style/light.hpp"
|
||||
#include "bitmap.hpp"
|
||||
|
||||
@@ -197,6 +198,8 @@ public:
|
||||
|
||||
jni::Array<jlong> queryPointAnnotations(JNIEnv&, jni::Object<RectF>);
|
||||
|
||||
jni::Array<jlong> queryShapeAnnotations(JNIEnv&, jni::Object<RectF>);
|
||||
|
||||
jni::Array<jni::Object<geojson::Feature>> queryRenderedFeaturesForPoint(JNIEnv&, jni::jfloat, jni::jfloat,
|
||||
jni::Array<jni::String>,
|
||||
jni::Array<jni::Object<>> jfilter);
|
||||
@@ -235,6 +238,8 @@ public:
|
||||
|
||||
void addImage(JNIEnv&, jni::String, jni::jint, jni::jint, jni::jfloat, jni::Array<jbyte>);
|
||||
|
||||
void addImages(JNIEnv&, jni::Array<jni::Object<mbgl::android::Image>>);
|
||||
|
||||
void removeImage(JNIEnv&, jni::String);
|
||||
|
||||
jni::Object<Bitmap> getImage(JNIEnv&, jni::String);
|
||||
|
||||
291
platform/darwin/resources/bg.lproj/Foundation.strings
Normal file
291
platform/darwin/resources/bg.lproj/Foundation.strings
Normal file
@@ -0,0 +1,291 @@
|
||||
/* Clock position format, long: {hours} o’clock */
|
||||
"CLOCK_FMT_LONG" = "%@ часа";
|
||||
|
||||
/* Clock position format, medium: {hours} o’clock */
|
||||
"CLOCK_FMT_MEDIUM" = "%@ часа";
|
||||
|
||||
/* Clock position format, short: {hours}:00 */
|
||||
"CLOCK_FMT_SHORT" = "%@:00";
|
||||
|
||||
/* East, long */
|
||||
"COMPASS_E_LONG" = "изток";
|
||||
|
||||
/* East, short */
|
||||
"COMPASS_E_SHORT" = "И";
|
||||
|
||||
/* East by north, long */
|
||||
"COMPASS_EbN_LONG" = "ийст-тен-уест";
|
||||
|
||||
/* East by north, short */
|
||||
"COMPASS_EbN_SHORT" = "EbN";
|
||||
|
||||
/* East by south, long */
|
||||
"COMPASS_EbS_LONG" = "ийст-тен-саут";
|
||||
|
||||
/* East by south, short */
|
||||
"COMPASS_EbS_SHORT" = "EbS";
|
||||
|
||||
/* East-northeast, long */
|
||||
"COMPASS_ENE_LONG" = "север-североизток";
|
||||
|
||||
/* East-northeast, short */
|
||||
"COMPASS_ENE_SHORT" = "ССИ";
|
||||
|
||||
/* East-southeast, long */
|
||||
"COMPASS_ESE_LONG" = "изток-югоизток";
|
||||
|
||||
/* East-southeast, short */
|
||||
"COMPASS_ESE_SHORT" = "ИЮИ";
|
||||
|
||||
/* North, long */
|
||||
"COMPASS_N_LONG" = "север";
|
||||
|
||||
/* North, short */
|
||||
"COMPASS_N_SHORT" = "С";
|
||||
|
||||
/* North by east, long */
|
||||
"COMPASS_NbE_LONG" = "норд-тен-ийст";
|
||||
|
||||
/* North by east, short */
|
||||
"COMPASS_NbE_SHORT" = "NbE";
|
||||
|
||||
/* North by west, long */
|
||||
"COMPASS_NbW_LONG" = "норд-тен-уест";
|
||||
|
||||
/* North by west, short */
|
||||
"COMPASS_NbW_SHORT" = "NbW";
|
||||
|
||||
/* Northeast, long */
|
||||
"COMPASS_NE_LONG" = "североизток";
|
||||
|
||||
/* Northeast, short */
|
||||
"COMPASS_NE_SHORT" = "СИ";
|
||||
|
||||
/* Northeast by east, long */
|
||||
"COMPASS_NEbE_LONG" = "нордийст-тен-ийст";
|
||||
|
||||
/* Northeast by east, short */
|
||||
"COMPASS_NEbE_SHORT" = "NEbE";
|
||||
|
||||
/* Northeast by north, long */
|
||||
"COMPASS_NEbN_LONG" = "нордийст-тен-норд";
|
||||
|
||||
/* Northeast by north, short */
|
||||
"COMPASS_NEbN_SHORT" = "NEnN";
|
||||
|
||||
/* North-northeast, long */
|
||||
"COMPASS_NNE_LONG" = "север-североизток";
|
||||
|
||||
/* North-northeast, short */
|
||||
"COMPASS_NNE_SHORT" = "ССИ";
|
||||
|
||||
/* North-northwest, long */
|
||||
"COMPASS_NNW_LONG" = "север-северозапад";
|
||||
|
||||
/* North-northwest, short */
|
||||
"COMPASS_NNW_SHORT" = "ССЗ";
|
||||
|
||||
/* Northwest, long */
|
||||
"COMPASS_NW_LONG" = "северозапад";
|
||||
|
||||
/* Northwest, short */
|
||||
"COMPASS_NW_SHORT" = "СЗ";
|
||||
|
||||
/* Northwest by north, long */
|
||||
"COMPASS_NWbN_LONG" = "нордуест-тен-норд";
|
||||
|
||||
/* Northwest by north, short */
|
||||
"COMPASS_NWbN_SHORT" = "NWbN";
|
||||
|
||||
/* Northwest by west, long */
|
||||
"COMPASS_NWbW_LONG" = "нордуест-тен-уест";
|
||||
|
||||
/* Northwest by west, short */
|
||||
"COMPASS_NWbW_SHORT" = "NWbW";
|
||||
|
||||
/* South, long */
|
||||
"COMPASS_S_LONG" = "юг";
|
||||
|
||||
/* South, short */
|
||||
"COMPASS_S_SHORT" = "Ю";
|
||||
|
||||
/* South by east, long */
|
||||
"COMPASS_SbE_LONG" = "саут-тен-ийст";
|
||||
|
||||
/* South by east, short */
|
||||
"COMPASS_SbE_SHORT" = "SbE";
|
||||
|
||||
/* South by west, long */
|
||||
"COMPASS_SbW_LONG" = "саут-тен-уест";
|
||||
|
||||
/* South by west, short */
|
||||
"COMPASS_SbW_SHORT" = "SbW";
|
||||
|
||||
/* Southeast, long */
|
||||
"COMPASS_SE_LONG" = "югоизток";
|
||||
|
||||
/* Southeast, short */
|
||||
"COMPASS_SE_SHORT" = "ЮИ";
|
||||
|
||||
/* Southeast by east, long */
|
||||
"COMPASS_SEbE_LONG" = "саутийст-тен-ийст";
|
||||
|
||||
/* Southeast by east, short */
|
||||
"COMPASS_SEbE_SHORT" = "SEbE";
|
||||
|
||||
/* Southeast by south, long */
|
||||
"COMPASS_SEbS_LONG" = "саутийст-тен-саут";
|
||||
|
||||
/* Southeast by south, short */
|
||||
"COMPASS_SEbS_SHORT" = "SEbS";
|
||||
|
||||
/* South-southeast, long */
|
||||
"COMPASS_SSE_LONG" = "юг-югоизток";
|
||||
|
||||
/* South-southeast, short */
|
||||
"COMPASS_SSE_SHORT" = "ЮЮИ";
|
||||
|
||||
/* South-southwest, long */
|
||||
"COMPASS_SSW_LONG" = "юг-югозапад";
|
||||
|
||||
/* South-southwest, short */
|
||||
"COMPASS_SSW_SHORT" = "ЮЮЗ";
|
||||
|
||||
/* Southwest, long */
|
||||
"COMPASS_SW_LONG" = "югозапад";
|
||||
|
||||
/* Southwest, short */
|
||||
"COMPASS_SW_SHORT" = "ЮЗ";
|
||||
|
||||
/* Southwest by south, long */
|
||||
"COMPASS_SWbS_LONG" = "саутуест-тен-саут";
|
||||
|
||||
/* Southwest by south, short */
|
||||
"COMPASS_SWbS_SHORT" = "SWbS";
|
||||
|
||||
/* Southwest by west, long */
|
||||
"COMPASS_SWbW_LONG" = "саутуест-тен-уест";
|
||||
|
||||
/* Southwest by west, short */
|
||||
"COMPASS_SWbW_SHORT" = "SWbW";
|
||||
|
||||
/* West, long */
|
||||
"COMPASS_W_LONG" = "запад";
|
||||
|
||||
/* West, short */
|
||||
"COMPASS_W_SHORT" = "З";
|
||||
|
||||
/* West by north, long */
|
||||
"COMPASS_WbN_LONG" = "уест-тен-норд";
|
||||
|
||||
/* West by north, short */
|
||||
"COMPASS_WbN_SHORT" = "WbN";
|
||||
|
||||
/* West by south, long */
|
||||
"COMPASS_WbS_LONG" = "уест-тен-саут";
|
||||
|
||||
/* West by south, short */
|
||||
"COMPASS_WbS_SHORT" = "WbS";
|
||||
|
||||
/* West-northwest, long */
|
||||
"COMPASS_WNW_LONG" = "запад-северозапад";
|
||||
|
||||
/* West-northwest, short */
|
||||
"COMPASS_WNW_SHORT" = "ЗСЗ";
|
||||
|
||||
/* West-southwest, long */
|
||||
"COMPASS_WSW_LONG" = "запад-югозапад";
|
||||
|
||||
/* West-southwest, short */
|
||||
"COMPASS_WSW_SHORT" = "ЗСЗ";
|
||||
|
||||
/* Degrees format, long */
|
||||
"COORD_DEG_LONG" = "%d градус(а)";
|
||||
|
||||
/* Degrees format, medium: {degrees} */
|
||||
"COORD_DEG_MEDIUM" = "%d°";
|
||||
|
||||
/* Degrees format, short: {degrees} */
|
||||
"COORD_DEG_SHORT" = "%d°";
|
||||
|
||||
/* Coordinate format, long: {degrees}{minutes} */
|
||||
"COORD_DM_LONG" = "%1$@ и %2$@";
|
||||
|
||||
/* Coordinate format, medium: {degrees}{minutes} */
|
||||
"COORD_DM_MEDIUM" = "%1$@%2$@";
|
||||
|
||||
/* Coordinate format, short: {degrees}{minutes} */
|
||||
"COORD_DM_SHORT" = "%1$@%2$@";
|
||||
|
||||
/* Coordinate format, long: {degrees}{minutes}{seconds} */
|
||||
"COORD_DMS_LONG" = "%1$@, %2$@ и %3$@";
|
||||
|
||||
/* Coordinate format, medium: {degrees}{minutes}{seconds} */
|
||||
"COORD_DMS_MEDIUM" = "%1$@%2$@%3$@";
|
||||
|
||||
/* Coordinate format, short: {degrees}{minutes}{seconds} */
|
||||
"COORD_DMS_SHORT" = "%1$@%2$@%3$@";
|
||||
|
||||
/* East longitude format, long: {longitude} */
|
||||
"COORD_E_LONG" = "%@ изток";
|
||||
|
||||
/* East longitude format, medium: {longitude} */
|
||||
"COORD_E_MEDIUM" = "%@ изток";
|
||||
|
||||
/* East longitude format, short: {longitude} */
|
||||
"COORD_E_SHORT" = "%@И";
|
||||
|
||||
/* Coordinate pair format, long: {latitude}, {longitude} */
|
||||
"COORD_FMT_LONG" = "%1$@ на %2$@";
|
||||
|
||||
/* Coordinate pair format, medium: {latitude}, {longitude} */
|
||||
"COORD_FMT_MEDIUM" = "%1$@, %2$@";
|
||||
|
||||
/* Coordinate pair format, short: {latitude}, {longitude} */
|
||||
"COORD_FMT_SHORT" = "%1$@, %2$@";
|
||||
|
||||
/* Minutes format, long */
|
||||
"COORD_MIN_LONG" = "%d минута(и)";
|
||||
|
||||
/* Minutes format, medium: {minutes} */
|
||||
"COORD_MIN_MEDIUM" = "%d′";
|
||||
|
||||
/* Minutes format, short: {minutes} */
|
||||
"COORD_MIN_SHORT" = "%d′";
|
||||
|
||||
/* North latitude format, long: {latitude} */
|
||||
"COORD_N_LONG" = "%@ север";
|
||||
|
||||
/* North latitude format, medium: {latitude} */
|
||||
"COORD_N_MEDIUM" = "%@ север";
|
||||
|
||||
/* North latitude format, short: {latitude} */
|
||||
"COORD_N_SHORT" = "%@С";
|
||||
|
||||
/* South latitude format, long: {latitude} */
|
||||
"COORD_S_LONG" = "%@ юг";
|
||||
|
||||
/* South latitude format, medium: {latitude} */
|
||||
"COORD_S_MEDIUM" = "%@ юг";
|
||||
|
||||
/* South latitude format, short: {latitude} */
|
||||
"COORD_S_SHORT" = "%@Ю";
|
||||
|
||||
/* Seconds format, long */
|
||||
"COORD_SEC_LONG" = "%d секунда(и)";
|
||||
|
||||
/* Seconds format, medium: {seconds} */
|
||||
"COORD_SEC_MEDIUM" = "%d″";
|
||||
|
||||
/* Seconds format, short: {seconds} */
|
||||
"COORD_SEC_SHORT" = "%d″";
|
||||
|
||||
/* West longitude format, long: {longitude} */
|
||||
"COORD_W_LONG" = "%@ запад";
|
||||
|
||||
/* West longitude format, medium: {longitude} */
|
||||
"COORD_W_MEDIUM" = "%@ запад";
|
||||
|
||||
/* West longitude format, short: {longitude} */
|
||||
"COORD_W_SHORT" = "%@З";
|
||||
|
||||
54
platform/darwin/resources/bg.lproj/Foundation.stringsdict
Normal file
54
platform/darwin/resources/bg.lproj/Foundation.stringsdict
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>COORD_DEG_LONG</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@degrees@</string>
|
||||
<key>degrees</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%d градус</string>
|
||||
<key>other</key>
|
||||
<string>%d градуса</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>COORD_MIN_LONG</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@minutes@</string>
|
||||
<key>minutes</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%d минута</string>
|
||||
<key>other</key>
|
||||
<string>%d минути</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>COORD_SEC_LONG</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@seconds@</string>
|
||||
<key>seconds</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%d секунда</string>
|
||||
<key>other</key>
|
||||
<string>%d секунди</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
54
platform/darwin/resources/hu.lproj/Foundation.stringsdict
Normal file
54
platform/darwin/resources/hu.lproj/Foundation.stringsdict
Normal file
@@ -0,0 +1,54 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>COORD_DEG_LONG</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@degrees@</string>
|
||||
<key>degrees</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%d fok</string>
|
||||
<key>other</key>
|
||||
<string>%d fok</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>COORD_MIN_LONG</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@minutes@</string>
|
||||
<key>minutes</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%d perc</string>
|
||||
<key>other</key>
|
||||
<string>%d perc</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>COORD_SEC_LONG</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@seconds@</string>
|
||||
<key>seconds</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>%d másodperc</string>
|
||||
<key>other</key>
|
||||
<string>%d másodperc</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
291
platform/darwin/resources/pt-BR.lproj/Foundation.strings
Normal file
291
platform/darwin/resources/pt-BR.lproj/Foundation.strings
Normal file
@@ -0,0 +1,291 @@
|
||||
/* Clock position format, long: {hours} o’clock */
|
||||
"CLOCK_FMT_LONG" = "São %@ horas";
|
||||
|
||||
/* Clock position format, medium: {hours} o’clock */
|
||||
"CLOCK_FMT_MEDIUM" = "São %@ horas";
|
||||
|
||||
/* Clock position format, short: {hours}:00 */
|
||||
"CLOCK_FMT_SHORT" = "%@:00";
|
||||
|
||||
/* East, long */
|
||||
"COMPASS_E_LONG" = "leste";
|
||||
|
||||
/* East, short */
|
||||
"COMPASS_E_SHORT" = "L";
|
||||
|
||||
/* East by north, long */
|
||||
"COMPASS_EbN_LONG" = "lest pelo norte";
|
||||
|
||||
/* East by north, short */
|
||||
"COMPASS_EbN_SHORT" = "LpN";
|
||||
|
||||
/* East by south, long */
|
||||
"COMPASS_EbS_LONG" = "leste pelo sul";
|
||||
|
||||
/* East by south, short */
|
||||
"COMPASS_EbS_SHORT" = "LpS";
|
||||
|
||||
/* East-northeast, long */
|
||||
"COMPASS_ENE_LONG" = "lés-nordeste";
|
||||
|
||||
/* East-northeast, short */
|
||||
"COMPASS_ENE_SHORT" = "ENE";
|
||||
|
||||
/* East-southeast, long */
|
||||
"COMPASS_ESE_LONG" = "lés-sudeste";
|
||||
|
||||
/* East-southeast, short */
|
||||
"COMPASS_ESE_SHORT" = "ESE";
|
||||
|
||||
/* North, long */
|
||||
"COMPASS_N_LONG" = "norte";
|
||||
|
||||
/* North, short */
|
||||
"COMPASS_N_SHORT" = "N";
|
||||
|
||||
/* North by east, long */
|
||||
"COMPASS_NbE_LONG" = "norte pelo leste";
|
||||
|
||||
/* North by east, short */
|
||||
"COMPASS_NbE_SHORT" = "NpL";
|
||||
|
||||
/* North by west, long */
|
||||
"COMPASS_NbW_LONG" = "norte pelo oeste";
|
||||
|
||||
/* North by west, short */
|
||||
"COMPASS_NbW_SHORT" = "NpO";
|
||||
|
||||
/* Northeast, long */
|
||||
"COMPASS_NE_LONG" = "nordeste";
|
||||
|
||||
/* Northeast, short */
|
||||
"COMPASS_NE_SHORT" = "NE";
|
||||
|
||||
/* Northeast by east, long */
|
||||
"COMPASS_NEbE_LONG" = "nordeste pelo leste";
|
||||
|
||||
/* Northeast by east, short */
|
||||
"COMPASS_NEbE_SHORT" = "NEpL";
|
||||
|
||||
/* Northeast by north, long */
|
||||
"COMPASS_NEbN_LONG" = "nordeste pelo norte";
|
||||
|
||||
/* Northeast by north, short */
|
||||
"COMPASS_NEbN_SHORT" = "NEpN";
|
||||
|
||||
/* North-northeast, long */
|
||||
"COMPASS_NNE_LONG" = "nor-nordeste";
|
||||
|
||||
/* North-northeast, short */
|
||||
"COMPASS_NNE_SHORT" = "NNE";
|
||||
|
||||
/* North-northwest, long */
|
||||
"COMPASS_NNW_LONG" = "nor-noroeste";
|
||||
|
||||
/* North-northwest, short */
|
||||
"COMPASS_NNW_SHORT" = "NNO";
|
||||
|
||||
/* Northwest, long */
|
||||
"COMPASS_NW_LONG" = "noroeste";
|
||||
|
||||
/* Northwest, short */
|
||||
"COMPASS_NW_SHORT" = "NO";
|
||||
|
||||
/* Northwest by north, long */
|
||||
"COMPASS_NWbN_LONG" = "noroeste pelo norte";
|
||||
|
||||
/* Northwest by north, short */
|
||||
"COMPASS_NWbN_SHORT" = "NOpN";
|
||||
|
||||
/* Northwest by west, long */
|
||||
"COMPASS_NWbW_LONG" = "noroeste pelo oeste";
|
||||
|
||||
/* Northwest by west, short */
|
||||
"COMPASS_NWbW_SHORT" = "NOpO";
|
||||
|
||||
/* South, long */
|
||||
"COMPASS_S_LONG" = "sul";
|
||||
|
||||
/* South, short */
|
||||
"COMPASS_S_SHORT" = "S";
|
||||
|
||||
/* South by east, long */
|
||||
"COMPASS_SbE_LONG" = "sul pelo leste";
|
||||
|
||||
/* South by east, short */
|
||||
"COMPASS_SbE_SHORT" = "SpL";
|
||||
|
||||
/* South by west, long */
|
||||
"COMPASS_SbW_LONG" = "sul pelo oeste";
|
||||
|
||||
/* South by west, short */
|
||||
"COMPASS_SbW_SHORT" = "SbO";
|
||||
|
||||
/* Southeast, long */
|
||||
"COMPASS_SE_LONG" = "sudeste";
|
||||
|
||||
/* Southeast, short */
|
||||
"COMPASS_SE_SHORT" = "SE";
|
||||
|
||||
/* Southeast by east, long */
|
||||
"COMPASS_SEbE_LONG" = "sudeste pelo leste";
|
||||
|
||||
/* Southeast by east, short */
|
||||
"COMPASS_SEbE_SHORT" = "SEpL";
|
||||
|
||||
/* Southeast by south, long */
|
||||
"COMPASS_SEbS_LONG" = "sudeste pelo sul";
|
||||
|
||||
/* Southeast by south, short */
|
||||
"COMPASS_SEbS_SHORT" = "SEpS";
|
||||
|
||||
/* South-southeast, long */
|
||||
"COMPASS_SSE_LONG" = "sul-sudeste";
|
||||
|
||||
/* South-southeast, short */
|
||||
"COMPASS_SSE_SHORT" = "SSE";
|
||||
|
||||
/* South-southwest, long */
|
||||
"COMPASS_SSW_LONG" = "su-sudoeste";
|
||||
|
||||
/* South-southwest, short */
|
||||
"COMPASS_SSW_SHORT" = "SSO";
|
||||
|
||||
/* Southwest, long */
|
||||
"COMPASS_SW_LONG" = "sudoeste";
|
||||
|
||||
/* Southwest, short */
|
||||
"COMPASS_SW_SHORT" = "SO";
|
||||
|
||||
/* Southwest by south, long */
|
||||
"COMPASS_SWbS_LONG" = "sudoeste pelo sul";
|
||||
|
||||
/* Southwest by south, short */
|
||||
"COMPASS_SWbS_SHORT" = "SOpS";
|
||||
|
||||
/* Southwest by west, long */
|
||||
"COMPASS_SWbW_LONG" = "sudoeste pelo oeste";
|
||||
|
||||
/* Southwest by west, short */
|
||||
"COMPASS_SWbW_SHORT" = "SOpO";
|
||||
|
||||
/* West, long */
|
||||
"COMPASS_W_LONG" = "oeste";
|
||||
|
||||
/* West, short */
|
||||
"COMPASS_W_SHORT" = "O";
|
||||
|
||||
/* West by north, long */
|
||||
"COMPASS_WbN_LONG" = "oeste pelo norte";
|
||||
|
||||
/* West by north, short */
|
||||
"COMPASS_WbN_SHORT" = "OpN";
|
||||
|
||||
/* West by south, long */
|
||||
"COMPASS_WbS_LONG" = "oeste pelo sul";
|
||||
|
||||
/* West by south, short */
|
||||
"COMPASS_WbS_SHORT" = "OpS";
|
||||
|
||||
/* West-northwest, long */
|
||||
"COMPASS_WNW_LONG" = "oés-noroeste";
|
||||
|
||||
/* West-northwest, short */
|
||||
"COMPASS_WNW_SHORT" = "ONO";
|
||||
|
||||
/* West-southwest, long */
|
||||
"COMPASS_WSW_LONG" = "oés-sudoeste";
|
||||
|
||||
/* West-southwest, short */
|
||||
"COMPASS_WSW_SHORT" = "OSO";
|
||||
|
||||
/* Degrees format, long */
|
||||
"COORD_DEG_LONG" = "%d grau(s)";
|
||||
|
||||
/* Degrees format, medium: {degrees} */
|
||||
"COORD_DEG_MEDIUM" = "%d°";
|
||||
|
||||
/* Degrees format, short: {degrees} */
|
||||
"COORD_DEG_SHORT" = "%d°";
|
||||
|
||||
/* Coordinate format, long: {degrees}{minutes} */
|
||||
"COORD_DM_LONG" = "%1$@ e %2$@";
|
||||
|
||||
/* Coordinate format, medium: {degrees}{minutes} */
|
||||
"COORD_DM_MEDIUM" = "%1$@%2$@";
|
||||
|
||||
/* Coordinate format, short: {degrees}{minutes} */
|
||||
"COORD_DM_SHORT" = "%1$@%2$@";
|
||||
|
||||
/* Coordinate format, long: {degrees}{minutes}{seconds} */
|
||||
"COORD_DMS_LONG" = "%1$@, %2$@, e %3$@";
|
||||
|
||||
/* Coordinate format, medium: {degrees}{minutes}{seconds} */
|
||||
"COORD_DMS_MEDIUM" = "%1$@%2$@%3$@";
|
||||
|
||||
/* Coordinate format, short: {degrees}{minutes}{seconds} */
|
||||
"COORD_DMS_SHORT" = "%1$@%2$@%3$@";
|
||||
|
||||
/* East longitude format, long: {longitude} */
|
||||
"COORD_E_LONG" = "%@ leste";
|
||||
|
||||
/* East longitude format, medium: {longitude} */
|
||||
"COORD_E_MEDIUM" = "%@ leste";
|
||||
|
||||
/* East longitude format, short: {longitude} */
|
||||
"COORD_E_SHORT" = "%@L";
|
||||
|
||||
/* Coordinate pair format, long: {latitude}, {longitude} */
|
||||
"COORD_FMT_LONG" = "%1$@ por %2$@";
|
||||
|
||||
/* Coordinate pair format, medium: {latitude}, {longitude} */
|
||||
"COORD_FMT_MEDIUM" = "%1$@, %2$@";
|
||||
|
||||
/* Coordinate pair format, short: {latitude}, {longitude} */
|
||||
"COORD_FMT_SHORT" = "%1$@, %2$@";
|
||||
|
||||
/* Minutes format, long */
|
||||
"COORD_MIN_LONG" = "%d minuto(s)";
|
||||
|
||||
/* Minutes format, medium: {minutes} */
|
||||
"COORD_MIN_MEDIUM" = "%d′";
|
||||
|
||||
/* Minutes format, short: {minutes} */
|
||||
"COORD_MIN_SHORT" = "%d′";
|
||||
|
||||
/* North latitude format, long: {latitude} */
|
||||
"COORD_N_LONG" = "%@ norte";
|
||||
|
||||
/* North latitude format, medium: {latitude} */
|
||||
"COORD_N_MEDIUM" = "%@ norte";
|
||||
|
||||
/* North latitude format, short: {latitude} */
|
||||
"COORD_N_SHORT" = "%@N";
|
||||
|
||||
/* South latitude format, long: {latitude} */
|
||||
"COORD_S_LONG" = "%@ sul";
|
||||
|
||||
/* South latitude format, medium: {latitude} */
|
||||
"COORD_S_MEDIUM" = "%@ sul";
|
||||
|
||||
/* South latitude format, short: {latitude} */
|
||||
"COORD_S_SHORT" = "%@S";
|
||||
|
||||
/* Seconds format, long */
|
||||
"COORD_SEC_LONG" = "%d segundo(s)";
|
||||
|
||||
/* Seconds format, medium: {seconds} */
|
||||
"COORD_SEC_MEDIUM" = "%d″";
|
||||
|
||||
/* Seconds format, short: {seconds} */
|
||||
"COORD_SEC_SHORT" = "%d″";
|
||||
|
||||
/* West longitude format, long: {longitude} */
|
||||
"COORD_W_LONG" = "%@ oeste";
|
||||
|
||||
/* West longitude format, medium: {longitude} */
|
||||
"COORD_W_MEDIUM" = "%@ oeste";
|
||||
|
||||
/* West longitude format, short: {longitude} */
|
||||
"COORD_W_SHORT" = "%@O";
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
|
||||
#import <mbgl/util/projection.hpp>
|
||||
|
||||
#if !TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#endif
|
||||
|
||||
/** Vertical field of view, measured in degrees, for determining the altitude
|
||||
of the viewpoint.
|
||||
|
||||
@@ -57,3 +61,48 @@ double MGLZoomLevelForAltitude(CLLocationDistance altitude, CGFloat pitch, CLLoc
|
||||
CGFloat mapPixelWidthAtZoom = std::cos(MGLRadiansFromDegrees(latitude)) * mbgl::util::M2PI * mbgl::util::EARTH_RADIUS_M / metersPerPixel;
|
||||
return ::log2(mapPixelWidthAtZoom / mbgl::util::tileSize);
|
||||
}
|
||||
|
||||
MGLRadianDistance MGLDistanceBetweenRadianCoordinates(MGLRadianCoordinate2D from, MGLRadianCoordinate2D to) {
|
||||
double a = pow(sin((to.latitude - from.latitude) / 2), 2)
|
||||
+ pow(sin((to.longitude - from.longitude) / 2), 2) * cos(from.latitude) * cos(to.latitude);
|
||||
|
||||
return 2 * atan2(sqrt(a), sqrt(1 - a));
|
||||
}
|
||||
|
||||
MGLRadianDirection MGLRadianCoordinatesDirection(MGLRadianCoordinate2D from, MGLRadianCoordinate2D to) {
|
||||
double a = sin(to.longitude - from.longitude) * cos(to.latitude);
|
||||
double b = cos(from.latitude) * sin(to.latitude)
|
||||
- sin(from.latitude) * cos(to.latitude) * cos(to.longitude - from.longitude);
|
||||
return atan2(a, b);
|
||||
}
|
||||
|
||||
MGLRadianCoordinate2D MGLRadianCoordinateAtDistanceFacingDirection(MGLRadianCoordinate2D coordinate,
|
||||
MGLRadianDistance distance,
|
||||
MGLRadianDirection direction) {
|
||||
double otherLatitude = asin(sin(coordinate.latitude) * cos(distance)
|
||||
+ cos(coordinate.latitude) * sin(distance) * cos(direction));
|
||||
double otherLongitude = coordinate.longitude + atan2(sin(direction) * sin(distance) * cos(coordinate.latitude),
|
||||
cos(distance) - sin(coordinate.latitude) * sin(otherLatitude));
|
||||
return MGLRadianCoordinate2DMake(otherLatitude, otherLongitude);
|
||||
}
|
||||
|
||||
CLLocationDirection MGLDirectionBetweenCoordinates(CLLocationCoordinate2D firstCoordinate, CLLocationCoordinate2D secondCoordinate) {
|
||||
// Ported from https://github.com/mapbox/turf-swift/blob/857e2e8060678ef4a7a9169d4971b0788fdffc37/Turf/Turf.swift#L23-L31
|
||||
MGLRadianCoordinate2D firstRadianCoordinate = MGLRadianCoordinateFromLocationCoordinate(firstCoordinate);
|
||||
MGLRadianCoordinate2D secondRadianCoordinate = MGLRadianCoordinateFromLocationCoordinate(secondCoordinate);
|
||||
|
||||
CGFloat a = sin(secondRadianCoordinate.longitude - firstRadianCoordinate.longitude) * cos(secondRadianCoordinate.latitude);
|
||||
CGFloat b = (cos(firstRadianCoordinate.latitude) * sin(secondRadianCoordinate.latitude)
|
||||
- sin(firstRadianCoordinate.latitude) * cos(secondRadianCoordinate.latitude) * cos(secondRadianCoordinate.longitude - firstRadianCoordinate.longitude));
|
||||
MGLRadianDirection radianDirection = atan2(a, b);
|
||||
return radianDirection * 180 / M_PI;
|
||||
}
|
||||
|
||||
CGPoint MGLPointRounded(CGPoint point) {
|
||||
#if TARGET_OS_IPHONE || TARGET_OS_SIMULATOR
|
||||
CGFloat scaleFactor = [UIScreen instancesRespondToSelector:@selector(nativeScale)] ? [UIScreen mainScreen].nativeScale : [UIScreen mainScreen].scale;
|
||||
#elif TARGET_OS_MAC
|
||||
CGFloat scaleFactor = [NSScreen mainScreen].backingScaleFactor;
|
||||
#endif
|
||||
return CGPointMake(round(point.x * scaleFactor) / scaleFactor, round(point.y * scaleFactor) / scaleFactor);
|
||||
}
|
||||
|
||||
@@ -105,36 +105,26 @@ NS_INLINE MGLRadianCoordinate2D MGLRadianCoordinateFromLocationCoordinate(CLLoca
|
||||
MGLRadiansFromDegrees(locationCoordinate.longitude));
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
Returns the distance in radians given two coordinates.
|
||||
*/
|
||||
NS_INLINE MGLRadianDistance MGLDistanceBetweenRadianCoordinates(MGLRadianCoordinate2D from, MGLRadianCoordinate2D to)
|
||||
{
|
||||
double a = pow(sin((to.latitude - from.latitude) / 2), 2)
|
||||
+ pow(sin((to.longitude - from.longitude) / 2), 2) * cos(from.latitude) * cos(to.latitude);
|
||||
|
||||
return 2 * atan2(sqrt(a), sqrt(1 - a));
|
||||
}
|
||||
MGLRadianDistance MGLDistanceBetweenRadianCoordinates(MGLRadianCoordinate2D from, MGLRadianCoordinate2D to);
|
||||
|
||||
/*
|
||||
/**
|
||||
Returns direction in radians given two coordinates.
|
||||
*/
|
||||
NS_INLINE MGLRadianDirection MGLRadianCoordinatesDirection(MGLRadianCoordinate2D from, MGLRadianCoordinate2D to) {
|
||||
double a = sin(to.longitude - from.longitude) * cos(to.latitude);
|
||||
double b = cos(from.latitude) * sin(to.latitude)
|
||||
- sin(from.latitude) * cos(to.latitude) * cos(to.longitude - from.longitude);
|
||||
return atan2(a, b);
|
||||
}
|
||||
MGLRadianDirection MGLRadianCoordinatesDirection(MGLRadianCoordinate2D from, MGLRadianCoordinate2D to);
|
||||
|
||||
/*
|
||||
Returns coordinate at a given distance and direction away from coordinate.
|
||||
/**
|
||||
Returns a coordinate at a given distance and direction away from coordinate.
|
||||
*/
|
||||
NS_INLINE MGLRadianCoordinate2D MGLRadianCoordinateAtDistanceFacingDirection(MGLRadianCoordinate2D coordinate,
|
||||
MGLRadianDistance distance,
|
||||
MGLRadianDirection direction) {
|
||||
double otherLatitude = asin(sin(coordinate.latitude) * cos(distance)
|
||||
+ cos(coordinate.latitude) * sin(distance) * cos(direction));
|
||||
double otherLongitude = coordinate.longitude + atan2(sin(direction) * sin(distance) * cos(coordinate.latitude),
|
||||
cos(distance) - sin(coordinate.latitude) * sin(otherLatitude));
|
||||
return MGLRadianCoordinate2DMake(otherLatitude, otherLongitude);
|
||||
}
|
||||
MGLRadianCoordinate2D MGLRadianCoordinateAtDistanceFacingDirection(MGLRadianCoordinate2D coordinate,
|
||||
MGLRadianDistance distance,
|
||||
MGLRadianDirection direction);
|
||||
|
||||
/**
|
||||
Returns the direction from one coordinate to another.
|
||||
*/
|
||||
CLLocationDirection MGLDirectionBetweenCoordinates(CLLocationCoordinate2D firstCoordinate, CLLocationCoordinate2D secondCoordinate);
|
||||
|
||||
CGPoint MGLPointRounded(CGPoint point);
|
||||
|
||||
@@ -38,8 +38,11 @@ MGL_EXPORT
|
||||
bottomLeft: CLLocationCoordinate2D(latitude: 37.936, longitude: -80.425),
|
||||
bottomRight: CLLocationCoordinate2D(latitude: 37.936, longitude: -71.516),
|
||||
topRight: CLLocationCoordinate2D(latitude: 46.437, longitude: -71.516))
|
||||
let source = MGLImageSource(identifier: "radar", coordinateQuad: coordinates, url: URL(string: "https://www.mapbox.com/mapbox-gl-js/assets/radar.gif")!)
|
||||
let source = MGLImageSource(identifier: "radar-source", coordinateQuad: coordinates, url: URL(string: "https://www.mapbox.com/mapbox-gl-js/assets/radar.gif")!)
|
||||
mapView.style?.addSource(source)
|
||||
|
||||
let layer = MGLRasterStyleLayer(identifier: "radar-layer", source: source)
|
||||
style.addLayer(layer)
|
||||
```
|
||||
*/
|
||||
MGL_EXPORT
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
MGL_EXPORT
|
||||
/**
|
||||
The options to use when creating images with the `MGLMapsnapshotter`.
|
||||
The options to use when creating images with the `MGLMapSnapshotter`.
|
||||
*/
|
||||
MGL_EXPORT
|
||||
@interface MGLMapSnapshotOptions : NSObject
|
||||
|
||||
/**
|
||||
@@ -63,7 +63,8 @@ MGL_EXPORT
|
||||
|
||||
/**
|
||||
The scale of the output image. Defaults to the main screen scale.
|
||||
Minimum is 1.
|
||||
|
||||
The minimum scale is 1.
|
||||
*/
|
||||
@property (nonatomic) CGFloat scale;
|
||||
|
||||
@@ -196,7 +197,7 @@ MGL_EXPORT
|
||||
@property (nonatomic) CGSize size;
|
||||
|
||||
/**
|
||||
Indicates whether as snapshot is currently being generated.
|
||||
Indicates whether a snapshot is currently being generated.
|
||||
*/
|
||||
@property (nonatomic, readonly, getter=isLoading) BOOL loading;
|
||||
|
||||
|
||||
@@ -14,11 +14,14 @@
|
||||
#import "MGLGeometry_Private.h"
|
||||
#import "NSBundle+MGLAdditions.h"
|
||||
#import "MGLStyle.h"
|
||||
#import "MGLAttributionInfo_Private.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
#import "UIImage+MGLAdditions.h"
|
||||
#else
|
||||
#import "NSImage+MGLAdditions.h"
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
#endif
|
||||
|
||||
const CGPoint MGLLogoImagePosition = CGPointMake(8, 8);
|
||||
@@ -146,6 +149,33 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
|
||||
dispatch_async(queue, ^{
|
||||
_snapshotCallback = std::make_unique<mbgl::Actor<mbgl::MapSnapshotter::Callback>>(*mbgl::Scheduler::GetCurrent(), [=](std::exception_ptr mbglError, mbgl::PremultipliedImage image, mbgl::MapSnapshotter::Attributions attributions, mbgl::MapSnapshotter::PointForFn pointForFn) {
|
||||
_loading = false;
|
||||
|
||||
NSMutableArray *infos = [NSMutableArray array];
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
CGFloat fontSize = [UIFont smallSystemFontSize];
|
||||
UIColor *attributeFontColor = [UIColor blackColor];
|
||||
#else
|
||||
CGFloat fontSize = [NSFont systemFontSizeForControlSize:NSMiniControlSize];
|
||||
NSColor *attributeFontColor = [NSColor blackColor];
|
||||
#endif
|
||||
for (auto attribution = attributions.begin(); attribution != attributions.end(); ++attribution) {
|
||||
NSString *attributionHTMLString = @(attribution->c_str());
|
||||
NSArray *tileSetInfos = [MGLAttributionInfo attributionInfosFromHTMLString:attributionHTMLString
|
||||
fontSize:fontSize
|
||||
linkColor:attributeFontColor];
|
||||
[infos growArrayByAddingAttributionInfosFromArray:tileSetInfos];
|
||||
}
|
||||
|
||||
CGSize attributionBackgroundSize = CGSizeMake(10, 0);
|
||||
for (MGLAttributionInfo *info in infos) {
|
||||
if (info.isFeedbackLink) {
|
||||
continue;
|
||||
}
|
||||
attributionBackgroundSize.width += [info.title size].width + 10;
|
||||
attributionBackgroundSize.height = MAX([info.title size].height, attributionBackgroundSize.height);
|
||||
}
|
||||
|
||||
if (mbglError) {
|
||||
NSString *description = @(mbgl::util::toString(mbglError).c_str());
|
||||
NSDictionary *userInfo = @{NSLocalizedDescriptionKey: description};
|
||||
@@ -170,10 +200,39 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
|
||||
#if TARGET_OS_IPHONE
|
||||
UIImage *logoImage = [UIImage imageNamed:@"mapbox" inBundle:[NSBundle mgl_frameworkBundle] compatibleWithTraitCollection:nil];
|
||||
|
||||
CGRect logoImageRect = CGRectMake(MGLLogoImagePosition.x, mglImage.size.height - (MGLLogoImagePosition.y + logoImage.size.height), logoImage.size.width, logoImage.size.height);
|
||||
CGRect attributionBackgroundFrame = CGRectMake(mglImage.size.width - 10 - attributionBackgroundSize.width,
|
||||
logoImageRect.origin.y + (logoImageRect.size.height / 2) - (attributionBackgroundSize.height / 2) + 1,
|
||||
attributionBackgroundSize.width,
|
||||
attributionBackgroundSize.height);
|
||||
CGPoint attributionTextPosition = CGPointMake(attributionBackgroundFrame.origin.x + 10,
|
||||
attributionBackgroundFrame.origin.y - 1);
|
||||
|
||||
CGRect cropRect = CGRectMake(attributionBackgroundFrame.origin.x * mglImage.scale,
|
||||
attributionBackgroundFrame.origin.y * mglImage.scale,
|
||||
attributionBackgroundSize.width * mglImage.scale,
|
||||
attributionBackgroundSize.height * mglImage.scale);
|
||||
|
||||
|
||||
UIGraphicsBeginImageContextWithOptions(mglImage.size, NO, self.options.scale);
|
||||
|
||||
[mglImage drawInRect:CGRectMake(0, 0, mglImage.size.width, mglImage.size.height)];
|
||||
[logoImage drawInRect:CGRectMake(MGLLogoImagePosition.x, mglImage.size.height - (MGLLogoImagePosition.y + logoImage.size.height), logoImage.size.width,logoImage.size.height)];
|
||||
|
||||
[logoImage drawInRect:logoImageRect];
|
||||
|
||||
UIImage *currentImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
CGImageRef attributionImageRef = CGImageCreateWithImageInRect([currentImage CGImage], cropRect);
|
||||
UIImage *attributionImage = [UIImage imageWithCGImage:attributionImageRef];
|
||||
CGImageRelease(attributionImageRef);
|
||||
|
||||
CIImage *ciAttributionImage = [[CIImage alloc] initWithCGImage:attributionImage.CGImage];
|
||||
|
||||
UIImage *blurredAttributionBackground = [self blurredAttributionBackground:ciAttributionImage];
|
||||
|
||||
[blurredAttributionBackground drawInRect:attributionBackgroundFrame];
|
||||
|
||||
[self drawAttributionText:infos origin:attributionTextPosition];
|
||||
|
||||
UIImage *compositedImage = UIGraphicsGetImageFromCurrentImageContext();
|
||||
|
||||
UIGraphicsEndImageContext();
|
||||
@@ -183,6 +242,15 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
|
||||
|
||||
NSSize targetSize = NSMakeSize(self.options.size.width, self.options.size.height);
|
||||
NSRect targetFrame = NSMakeRect(0, 0, targetSize.width, targetSize.height);
|
||||
CGRect logoImageRect = CGRectMake(MGLLogoImagePosition.x, MGLLogoImagePosition.y, logoImage.size.width, logoImage.size.height);
|
||||
CGRect attributionBackgroundFrame = CGRectMake(targetFrame.size.width - 10 - attributionBackgroundSize.width,
|
||||
MGLLogoImagePosition.y + 1,
|
||||
attributionBackgroundSize.width,
|
||||
attributionBackgroundSize.height);
|
||||
CGPoint attributionTextPosition = CGPointMake(attributionBackgroundFrame.origin.x + 10,
|
||||
logoImageRect.origin.y + (logoImageRect.size.height / 2) - (attributionBackgroundSize.height / 2));
|
||||
|
||||
|
||||
NSImage *compositedImage = nil;
|
||||
NSImageRep *sourceImageRep = [sourceImage bestRepresentationForRect:targetFrame
|
||||
context:nil
|
||||
@@ -190,10 +258,24 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
|
||||
compositedImage = [[NSImage alloc] initWithSize:targetSize];
|
||||
|
||||
[compositedImage lockFocus];
|
||||
|
||||
[sourceImageRep drawInRect: targetFrame];
|
||||
[logoImage drawInRect:CGRectMake(MGLLogoImagePosition.x, MGLLogoImagePosition.y, logoImage.size.width,logoImage.size.height)];
|
||||
|
||||
[logoImage drawInRect:logoImageRect];
|
||||
|
||||
NSBitmapImageRep *attributionBackground = [[NSBitmapImageRep alloc] initWithFocusedViewRect:attributionBackgroundFrame];
|
||||
|
||||
CIImage *attributionBackgroundImage = [[CIImage alloc] initWithCGImage:[attributionBackground CGImage]];
|
||||
|
||||
NSImage *blurredAttributionBackground = [self blurredAttributionBackground:attributionBackgroundImage];
|
||||
|
||||
[blurredAttributionBackground drawInRect:attributionBackgroundFrame];
|
||||
|
||||
[self drawAttributionText:infos origin:attributionTextPosition];
|
||||
|
||||
[compositedImage unlockFocus];
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
// Dispatch result to origin queue
|
||||
@@ -208,6 +290,47 @@ const CGFloat MGLSnapshotterMinimumPixelSize = 64;
|
||||
});
|
||||
}
|
||||
|
||||
- (void)drawAttributionText:(NSArray *)attributionInfo origin:(CGPoint)origin
|
||||
{
|
||||
for (MGLAttributionInfo *info in attributionInfo) {
|
||||
if (info.isFeedbackLink) {
|
||||
continue;
|
||||
}
|
||||
[info.title drawAtPoint:origin];
|
||||
|
||||
origin.x += [info.title size].width + 10;
|
||||
}
|
||||
}
|
||||
|
||||
- (MGLImage *)blurredAttributionBackground:(CIImage *)backgroundImage
|
||||
{
|
||||
CGAffineTransform transform = CGAffineTransformIdentity;
|
||||
CIFilter *clamp = [CIFilter filterWithName:@"CIAffineClamp"];
|
||||
[clamp setValue:backgroundImage forKey:kCIInputImageKey];
|
||||
[clamp setValue:[NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)] forKey:@"inputTransform"];
|
||||
|
||||
CIFilter *attributionBlurFilter = [CIFilter filterWithName:@"CIGaussianBlur"];
|
||||
[attributionBlurFilter setValue:[clamp outputImage] forKey:kCIInputImageKey];
|
||||
[attributionBlurFilter setValue:@10 forKey:kCIInputRadiusKey];
|
||||
|
||||
CIFilter *attributionColorFilter = [CIFilter filterWithName:@"CIColorControls"];
|
||||
[attributionColorFilter setValue:[attributionBlurFilter outputImage] forKey:kCIInputImageKey];
|
||||
[attributionColorFilter setValue:@(0.1) forKey:kCIInputBrightnessKey];
|
||||
|
||||
CIImage *blurredImage = attributionColorFilter.outputImage;
|
||||
|
||||
CIContext *ctx = [CIContext contextWithOptions:nil];
|
||||
CGImageRef cgimg = [ctx createCGImage:blurredImage fromRect:[backgroundImage extent]];
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
return [UIImage imageWithCGImage:cgimg];
|
||||
#else
|
||||
|
||||
return [[NSImage alloc] initWithCGImage:cgimg size:[backgroundImage extent].size];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)cancel
|
||||
{
|
||||
_snapshotCallback.reset();
|
||||
|
||||
@@ -85,7 +85,8 @@ extern MGL_EXPORT const MGLShapeSourceOption MGLShapeSourceOptionSimplificationT
|
||||
or they may be defined by local or external
|
||||
<a href="http://geojson.org/">GeoJSON</a> code. A shape source is added to an
|
||||
`MGLStyle` object along with an `MGLVectorStyleLayer` object. The vector style
|
||||
layer defines the appearance of any content supplied by the shape source.
|
||||
layer defines the appearance of any content supplied by the shape source. You
|
||||
can update a shape source by setting its `shape` or `URL` property.
|
||||
|
||||
Each
|
||||
<a href="https://www.mapbox.com/mapbox-gl-style-spec/#sources-geojson"><code>geojson</code></a>
|
||||
|
||||
@@ -638,7 +638,7 @@ static NSURL *MGLStyleURL_trafficNight;
|
||||
self.URL ? [NSString stringWithFormat:@"\"%@\"", self.URL] : self.URL];
|
||||
}
|
||||
|
||||
#pragma mark Style language preferences
|
||||
#pragma mark Mapbox Streets source introspection
|
||||
|
||||
- (void)setLocalizesLabels:(BOOL)localizesLabels
|
||||
{
|
||||
@@ -749,4 +749,29 @@ static NSURL *MGLStyleURL_trafficNight;
|
||||
}
|
||||
}
|
||||
|
||||
- (NS_SET_OF(MGLVectorSource *) *)mapboxStreetsSources {
|
||||
return [self.sources objectsPassingTest:^BOOL (__kindof MGLVectorSource * _Nonnull source, BOOL * _Nonnull stop) {
|
||||
return [source isKindOfClass:[MGLVectorSource class]] && source.mapboxStreets;
|
||||
}];
|
||||
}
|
||||
|
||||
- (NS_ARRAY_OF(MGLStyleLayer *) *)placeStyleLayers {
|
||||
NSSet *streetsSourceIdentifiers = [self.mapboxStreetsSources valueForKey:@"identifier"];
|
||||
|
||||
NSSet *placeSourceLayerIdentifiers = [NSSet setWithObjects:@"marine_label", @"country_label", @"state_label", @"place_label", @"water_label", @"poi_label", @"rail_station_label", @"mountain_peak_label", nil];
|
||||
NSPredicate *isPlacePredicate = [NSPredicate predicateWithBlock:^BOOL (MGLVectorStyleLayer * _Nullable layer, NSDictionary<NSString *, id> * _Nullable bindings) {
|
||||
return [layer isKindOfClass:[MGLVectorStyleLayer class]] && [streetsSourceIdentifiers containsObject:layer.sourceIdentifier] && [placeSourceLayerIdentifiers containsObject:layer.sourceLayerIdentifier];
|
||||
}];
|
||||
return [self.layers filteredArrayUsingPredicate:isPlacePredicate];
|
||||
}
|
||||
|
||||
- (NS_ARRAY_OF(MGLStyleLayer *) *)roadStyleLayers {
|
||||
NSSet *streetsSourceIdentifiers = [self.mapboxStreetsSources valueForKey:@"identifier"];
|
||||
|
||||
NSPredicate *isPlacePredicate = [NSPredicate predicateWithBlock:^BOOL (MGLVectorStyleLayer * _Nullable layer, NSDictionary<NSString *, id> * _Nullable bindings) {
|
||||
return [layer isKindOfClass:[MGLVectorStyleLayer class]] && [streetsSourceIdentifiers containsObject:layer.sourceIdentifier] && [layer.sourceLayerIdentifier isEqualToString:@"road_label"];
|
||||
}];
|
||||
return [self.layers filteredArrayUsingPredicate:isPlacePredicate];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace mbgl {
|
||||
@class MGLAttributionInfo;
|
||||
@class MGLMapView;
|
||||
@class MGLOpenGLStyleLayer;
|
||||
@class MGLVectorSource;
|
||||
@class MGLVectorStyleLayer;
|
||||
|
||||
@interface MGLStyle (Private)
|
||||
|
||||
@@ -30,4 +32,11 @@ namespace mbgl {
|
||||
|
||||
@end
|
||||
|
||||
@interface MGLStyle (MGLStreetsAdditions)
|
||||
|
||||
@property (nonatomic, readonly, copy) NS_ARRAY_OF(MGLVectorStyleLayer *) *placeStyleLayers;
|
||||
@property (nonatomic, readonly, copy) NS_ARRAY_OF(MGLVectorStyleLayer *) *roadStyleLayers;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
@@ -4,6 +4,12 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
|
||||
|
||||
## master
|
||||
|
||||
### Annotations and user interaction
|
||||
|
||||
* Increased the default maximum zoom level from 20 to 22. ([#9835](https://github.com/mapbox/mapbox-gl-native/pull/9835))
|
||||
|
||||
## 3.7.0
|
||||
|
||||
### Networking and storage
|
||||
|
||||
* Added a new `MGLMapSnapshotter` class for capturing rendered map images from an `MGLMapView`’s camera. ([#9891](https://github.com/mapbox/mapbox-gl-native/pull/9891))
|
||||
@@ -23,19 +29,29 @@ Mapbox welcomes participation and contributions from everyone. Please read [CONT
|
||||
* Fixed an issue that could cause antialiasing between polygons on the same layer to fail if the fill layers used data-driven styling for the fill color. ([#9699](https://github.com/mapbox/mapbox-gl-native/pull/9699))
|
||||
* The previously deprecated support for style classes has been removed. For interface compatibility, the API methods remain, but they are now non-functional.
|
||||
|
||||
### Annotations and user interaction
|
||||
### Annotations
|
||||
|
||||
* Fixed several bugs and performance issues related to the use of annotations backed by `MGLAnnotationImage`. The limits on the number and size of images and glyphs has been effectively eliminated and should now depend on hardware constraints. These fixes also apply to images used to represent icons in `MGLSymbolStyleLayer`. ([#9213](https://github.com/mapbox/mapbox-gl-native/pull/9213))
|
||||
* Increased the default maximum zoom level from 20 to 22. ([#9835](https://github.com/mapbox/mapbox-gl-native/pull/9835))
|
||||
* Added an `overlays` property to `MGLMapView`. ([#8617](https://github.com/mapbox/mapbox-gl-native/pull/8617))
|
||||
* Selecting an annotation no longer sets the user tracking mode to `MGLUserTrackingModeNone`. ([#10094](https://github.com/mapbox/mapbox-gl-native/pull/10094))
|
||||
* Added `-[MGLMapView cameraThatFitsShape:direction:edgePadding:]` to get a camera with zoom level and center coordinate computed to fit a shape. ([#10107](https://github.com/mapbox/mapbox-gl-native/pull/10107))
|
||||
* Added support selection of shape and polyline annotations.([#9984](https://github.com/mapbox/mapbox-gl-native/pull/9984))
|
||||
* Fixed an issue where view annotations could be slightly misaligned. View annotation placement is now rounded to the nearest pixel. ([#10219](https://github.com/mapbox/mapbox-gl-native/pull/10219))
|
||||
* Fixed an issue where a shape annotation callout was not displayed if the centroid was not visible. ([#10255](https://github.com/mapbox/mapbox-gl-native/pull/10255))
|
||||
|
||||
### User interaction
|
||||
|
||||
* Users of VoiceOver can now swipe left and right to navigate among visible places, points of interest, and roads. ([#9950](https://github.com/mapbox/mapbox-gl-native/pull/9950))
|
||||
* Increased the default maximum zoom level from 20 to 22. ([#9835](https://github.com/mapbox/mapbox-gl-native/pull/9835))
|
||||
|
||||
### Other changes
|
||||
|
||||
* Added a Bulgarian localization. ([#10309](https://github.com/mapbox/mapbox-gl-native/pull/10309))
|
||||
* Fixed an issue that could cause line label rendering glitches when the line geometry is projected to a point behind the plane of the camera. ([#9865](https://github.com/mapbox/mapbox-gl-native/pull/9865))
|
||||
* Fixed an issue that could cause a crash when using `-[MGLMapView flyToCamera:completionHandler:]` and related methods with zoom levels at or near the maximum value. ([#9381](https://github.com/mapbox/mapbox-gl-native/pull/9381))
|
||||
* Added `-[MGLMapView showAttribution:]` to allow custom attribution buttons to show the default attribution interface. ([#10085](https://github.com/mapbox/mapbox-gl-native/pull/10085))
|
||||
* Fixed a conflict between multiple copies of SMCalloutView in a project. ([#10183](https://github.com/mapbox/mapbox-gl-native/pull/10183))
|
||||
* Fixed a crash when enabling the scale bar in iOS 8. ([#10241](https://github.com/mapbox/mapbox-gl-native/pull/10241))
|
||||
|
||||
## 3.6.4 - September 25, 2017
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |m|
|
||||
|
||||
version = '3.7.0-alpha.1'
|
||||
version = '3.7.0-beta.4'
|
||||
|
||||
m.name = 'Mapbox-iOS-SDK-nightly-dynamic'
|
||||
m.version = "#{version}-nightly"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |m|
|
||||
|
||||
version = '3.7.0-alpha.1'
|
||||
version = '3.7.0-beta.4'
|
||||
|
||||
m.name = 'Mapbox-iOS-SDK-symbols'
|
||||
m.version = "#{version}-symbols"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
Pod::Spec.new do |m|
|
||||
|
||||
version = '3.7.0-alpha.1'
|
||||
version = '3.7.0-beta.4'
|
||||
|
||||
m.name = 'Mapbox-iOS-SDK'
|
||||
m.version = version
|
||||
|
||||
@@ -165,7 +165,9 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
|
||||
self.mapView.scaleBar.hidden = NO;
|
||||
self.mapView.showsUserHeadingIndicator = YES;
|
||||
self.hudLabel.hidden = YES;
|
||||
self.hudLabel.titleLabel.font = [UIFont monospacedDigitSystemFontOfSize:10 weight:UIFontWeightRegular];
|
||||
if ([UIFont respondsToSelector:@selector(monospacedDigitSystemFontOfSize:weight:)]) {
|
||||
self.hudLabel.titleLabel.font = [UIFont monospacedDigitSystemFontOfSize:10 weight:UIFontWeightRegular];
|
||||
}
|
||||
|
||||
if ([MGLAccountManager accessToken].length)
|
||||
{
|
||||
@@ -827,6 +829,7 @@ typedef NS_ENUM(NSInteger, MBXSettingsMiscellaneousRows) {
|
||||
}
|
||||
|
||||
MGLPolygon *polygon = [MGLPolygon polygonWithCoordinates:polygonCoordinates count:[stateCoordinatePairs count]];
|
||||
polygon.title = feature[@"properties"][@"NAME"];
|
||||
|
||||
[self.mapView addAnnotation:polygon];
|
||||
|
||||
|
||||
0
platform/ios/app/bg.lproj/Localizable.strings
Normal file
0
platform/ios/app/bg.lproj/Localizable.strings
Normal file
@@ -4,6 +4,8 @@ default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
|
||||
trigger_map:
|
||||
- pattern: nightly-release
|
||||
workflow: nightly-release
|
||||
- pattern: release-from-tag
|
||||
workflow: release-from-tag
|
||||
- pattern: "*"
|
||||
is_pull_request_allowed: true
|
||||
workflow: primary
|
||||
@@ -11,48 +13,9 @@ workflows:
|
||||
primary:
|
||||
steps:
|
||||
- script:
|
||||
title: Install Dependencies
|
||||
title: Skip Workflow
|
||||
inputs:
|
||||
- content: |-
|
||||
#!/bin/bash
|
||||
set -eu -o pipefail
|
||||
brew install cmake
|
||||
- is_debug: 'yes'
|
||||
- script:
|
||||
title: Generate Workspace
|
||||
inputs:
|
||||
- content: |-
|
||||
#!/bin/bash
|
||||
set -eu -o pipefail
|
||||
export BUILDTYPE=Debug
|
||||
make iproj
|
||||
- is_debug: 'yes'
|
||||
- xcode-test:
|
||||
title: Run SDK Unit Tests
|
||||
inputs:
|
||||
- project_path: platform/ios/ios.xcworkspace
|
||||
- scheme: CI
|
||||
- deploy-to-bitrise-io:
|
||||
title: Deploy to Bitrise.io
|
||||
inputs:
|
||||
- notify_user_groups: none
|
||||
- slack:
|
||||
title: Post to Slack
|
||||
inputs:
|
||||
- webhook_url: "$SLACK_HOOK_URL"
|
||||
- channel: "#gl-bots"
|
||||
- from_username: 'Bitrise iOS'
|
||||
- from_username_on_error: 'Bitrise iOS'
|
||||
- message: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}>
|
||||
for <https://github.com/mapbox/mapbox-gl-native/compare/${BITRISE_GIT_BRANCH}|mapbox/mapbox-gl-native@${BITRISE_GIT_BRANCH}>
|
||||
by ${GIT_CLONE_COMMIT_COMMITER_NAME}
|
||||
passed'
|
||||
- message_on_error: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}>
|
||||
for <https://github.com/mapbox/mapbox-gl-native/compare/${BITRISE_GIT_BRANCH}|mapbox/mapbox-gl-native@${BITRISE_GIT_BRANCH}>
|
||||
by ${GIT_CLONE_COMMIT_COMMITER_NAME}
|
||||
failed'
|
||||
- icon_url: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-icon-128.png
|
||||
- icon_url_on_error: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-error-icon-128.png
|
||||
- content: echo "This workflow is obsolete — see CircleCi."
|
||||
nightly-release:
|
||||
steps:
|
||||
- script:
|
||||
@@ -62,9 +25,13 @@ workflows:
|
||||
#!/bin/bash
|
||||
set -eu -o pipefail
|
||||
brew install cmake
|
||||
sudo easy_install pip
|
||||
sudo pip install awscli
|
||||
- is_debug: 'yes'
|
||||
- script:
|
||||
title: Configure AWS-CLI
|
||||
inputs:
|
||||
- content: |-
|
||||
#!/bin/bash
|
||||
pip install awscli
|
||||
- script:
|
||||
title: Build package
|
||||
inputs:
|
||||
@@ -83,8 +50,8 @@ workflows:
|
||||
inputs:
|
||||
- webhook_url: "$SLACK_HOOK_URL"
|
||||
- channel: "#gl-bots"
|
||||
- from_username: 'Bitrise iOS Nightly \U0001F31D'
|
||||
- from_username_on_error: 'Bitrise iOS Nightly \U0001F31D'
|
||||
- from_username: 'Bitrise iOS Nightly 💤'
|
||||
- from_username_on_error: 'Bitrise iOS Nightly 💤'
|
||||
- message: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}>
|
||||
for <https://github.com/mapbox/mapbox-gl-native/compare/${BITRISE_GIT_BRANCH}@%7B1day%7D...${BITRISE_GIT_BRANCH}|mapbox/mapbox-gl-native@${BITRISE_GIT_BRANCH}>
|
||||
completed successfully.'
|
||||
@@ -93,3 +60,39 @@ workflows:
|
||||
failed.'
|
||||
- icon_url: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-icon-128.png
|
||||
- icon_url_on_error: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-error-icon-128.png
|
||||
release-from-tag:
|
||||
steps:
|
||||
- script:
|
||||
title: Install Dependencies
|
||||
inputs:
|
||||
- content: |-
|
||||
#!/bin/bash
|
||||
set -eu -o pipefail
|
||||
brew install cmake
|
||||
sudo easy_install pip
|
||||
sudo pip install awscli
|
||||
- is_debug: 'yes'
|
||||
- script:
|
||||
title: Build package
|
||||
inputs:
|
||||
- content: |-
|
||||
#!/bin/bash
|
||||
set -eu -o pipefail
|
||||
export VERSION_TAG=${BITRISE_GIT_TAG}
|
||||
platform/ios/scripts/deploy-packages.sh
|
||||
- is_debug: 'yes'
|
||||
- slack:
|
||||
title: Post to Slack
|
||||
inputs:
|
||||
- webhook_url: "$SLACK_HOOK_URL"
|
||||
- channel: "#gl-bots"
|
||||
- from_username: 'Bitrise iOS Deploy'
|
||||
- from_username_on_error: 'Bitrise iOS Deploy'
|
||||
- message: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}>
|
||||
for <https://github.com/mapbox/mapbox-gl-native/releases/tag/${BITRISE_GIT_TAG}|`${BITRISE_GIT_TAG}`>
|
||||
completed successfully.'
|
||||
- message_on_error: '<${BITRISE_BUILD_URL}|Build #${BITRISE_BUILD_NUMBER}>
|
||||
for <https://github.com/mapbox/mapbox-gl-native/releases/tag/${BITRISE_GIT_TAG}|`${BITRISE_GIT_TAG}`>
|
||||
failed.'
|
||||
- icon_url: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-icon-128.png
|
||||
- icon_url_on_error: https://bitrise-public-content-production.s3.amazonaws.com/slack/bitrise-slack-error-icon-128.png
|
||||
|
||||
@@ -51,7 +51,7 @@ To use annotation views, implement `MGLMapViewDelegate` `-mapView:viewForAnnotat
|
||||
* No limit on style or image size
|
||||
* Full support for animations
|
||||
* Relative control over z-ordering using the `zPosition` property on `CALayer`
|
||||
* [Familiar API for MapKit users](https://www.mapbox.com/help/switch-mapkit/#annotations-pins)
|
||||
* Familiar API for MapKit users
|
||||
|
||||
**Cons**
|
||||
|
||||
@@ -63,7 +63,7 @@ To use annotation views, implement `MGLMapViewDelegate` `-mapView:viewForAnnotat
|
||||
|
||||
For absolute full control of how points are displayed on a map, consider [runtime styling](runtime-styling.html).
|
||||
|
||||
You can use `MGLPointFeature` or any of the other [style feature subclasses](Style%20Features.html) to add points and shapes to an `MGLShapeSource`.
|
||||
You can use `MGLPointFeature` or any other [style primitives](Style%20Primitives.html) to add points and shapes to an `MGLShapeSource`.
|
||||
|
||||
From there, you can create one or many `MGLSymbolStyleLayer` or `MGLCircleStyleLayer` layers to filter and style points for display on the map ([example](https://www.mapbox.com/ios-sdk/examples/runtime-multiple-annotations)).
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
"TELEMETRY_GROUP_TITLE" = "Настройки за поверителност";
|
||||
"TELEMETRY_SWITCH_TITLE" = "Mapbox Телеметрия";
|
||||
"TELEMETRY_GROUP_FOOTER" = "Тази настройка позволява на приложението да споделя анонимни локации и данни за използване с Mapbox.";
|
||||
@@ -292,10 +292,15 @@
|
||||
DA35A2CB1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2C81CCAAAD200E826B2 /* NSValue+MGLAdditions.m */; };
|
||||
DA35A2CC1CCAAAD200E826B2 /* NSValue+MGLAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = DA35A2C81CCAAAD200E826B2 /* NSValue+MGLAdditions.m */; };
|
||||
DA35D0881E1A6309007DED41 /* one-liner.json in Resources */ = {isa = PBXBuildFile; fileRef = DA35D0871E1A6309007DED41 /* one-liner.json */; };
|
||||
DA5DB12A1FABF1EE001C2326 /* MGLMapAccessibilityElementTests.m in Sources */ = {isa = PBXBuildFile; fileRef = DA5DB1291FABF1EE001C2326 /* MGLMapAccessibilityElementTests.m */; };
|
||||
DA6408DB1DA4E7D300908C90 /* MGLVectorStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA6408D91DA4E7D300908C90 /* MGLVectorStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
DA6408DC1DA4E7D300908C90 /* MGLVectorStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA6408D91DA4E7D300908C90 /* MGLVectorStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
DA6408DD1DA4E7D300908C90 /* MGLVectorStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.m */; };
|
||||
DA6408DE1DA4E7D300908C90 /* MGLVectorStyleLayer.m in Sources */ = {isa = PBXBuildFile; fileRef = DA6408DA1DA4E7D300908C90 /* MGLVectorStyleLayer.m */; };
|
||||
DA704CC21F65A475004B3F28 /* MGLMapAccessibilityElement.h in Headers */ = {isa = PBXBuildFile; fileRef = DA704CC01F65A475004B3F28 /* MGLMapAccessibilityElement.h */; };
|
||||
DA704CC31F65A475004B3F28 /* MGLMapAccessibilityElement.h in Headers */ = {isa = PBXBuildFile; fileRef = DA704CC01F65A475004B3F28 /* MGLMapAccessibilityElement.h */; };
|
||||
DA704CC41F65A475004B3F28 /* MGLMapAccessibilityElement.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA704CC11F65A475004B3F28 /* MGLMapAccessibilityElement.mm */; };
|
||||
DA704CC51F65A475004B3F28 /* MGLMapAccessibilityElement.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA704CC11F65A475004B3F28 /* MGLMapAccessibilityElement.mm */; };
|
||||
DA72620B1DEEE3480043BB89 /* MGLOpenGLStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA7262091DEEE3480043BB89 /* MGLOpenGLStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
DA72620C1DEEE3480043BB89 /* MGLOpenGLStyleLayer.h in Headers */ = {isa = PBXBuildFile; fileRef = DA7262091DEEE3480043BB89 /* MGLOpenGLStyleLayer.h */; settings = {ATTRIBUTES = (Public, ); }; };
|
||||
DA72620D1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm in Sources */ = {isa = PBXBuildFile; fileRef = DA72620A1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm */; };
|
||||
@@ -774,6 +779,14 @@
|
||||
DA2E885D1CC0382C00F24E7B /* MGLOfflinePackTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflinePackTests.m; path = ../../darwin/test/MGLOfflinePackTests.m; sourceTree = "<group>"; };
|
||||
DA2E885E1CC0382C00F24E7B /* MGLOfflineRegionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLOfflineRegionTests.m; path = ../../darwin/test/MGLOfflineRegionTests.m; sourceTree = "<group>"; };
|
||||
DA2E88601CC0382C00F24E7B /* MGLStyleTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = MGLStyleTests.mm; path = ../../darwin/test/MGLStyleTests.mm; sourceTree = "<group>"; };
|
||||
DA33895F1FA3EAB7001EA329 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Foundation.strings"; sourceTree = "<group>"; };
|
||||
DA3389651FA3EE1B001EA329 /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
DA3389661FA3EE28001EA329 /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Foundation.strings; sourceTree = "<group>"; };
|
||||
DA3389671FA3EE2F001EA329 /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = bg; path = bg.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
|
||||
DA3389681FA3EE48001EA329 /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
DA3389691FA3EE50001EA329 /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = bg; path = bg.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
DA33896A1FA3EE58001EA329 /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Root.strings; sourceTree = "<group>"; };
|
||||
DA33896B1FA3EF4A001EA329 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = hu; path = hu.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
|
||||
DA35A29D1CC9E94C00E826B2 /* MGLCoordinateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLCoordinateFormatter.h; sourceTree = "<group>"; };
|
||||
DA35A2A01CC9E95F00E826B2 /* MGLCoordinateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MGLCoordinateFormatter.m; sourceTree = "<group>"; };
|
||||
DA35A2A91CCA058D00E826B2 /* MGLCoordinateFormatterTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = MGLCoordinateFormatterTests.m; path = ../../darwin/test/MGLCoordinateFormatterTests.m; sourceTree = "<group>"; };
|
||||
@@ -794,6 +807,7 @@
|
||||
DA57D4AC1EBA922A00793288 /* vi */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = vi; path = vi.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
DA5C09BA1EFC48550056B178 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
DA5C09BB1EFC486C0056B178 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
DA5DB1291FABF1EE001C2326 /* MGLMapAccessibilityElementTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MGLMapAccessibilityElementTests.m; sourceTree = "<group>"; };
|
||||
DA6023F11E4CE94300DBFF23 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Foundation.strings; sourceTree = "<group>"; };
|
||||
DA6023F21E4CE94800DBFF23 /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = sv; path = sv.lproj/Foundation.stringsdict; sourceTree = "<group>"; };
|
||||
DA618B111E68823600CB7F44 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = ru; path = ru.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
@@ -812,6 +826,8 @@
|
||||
DA704CBB1F637311004B3F28 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Foundation.strings; sourceTree = "<group>"; };
|
||||
DA704CBC1F637405004B3F28 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = uk; path = uk.lproj/Localizable.stringsdict; sourceTree = "<group>"; };
|
||||
DA704CBD1F63746E004B3F28 /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = "zh-Hant"; path = "zh-Hant.lproj/Localizable.stringsdict"; sourceTree = "<group>"; };
|
||||
DA704CC01F65A475004B3F28 /* MGLMapAccessibilityElement.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLMapAccessibilityElement.h; sourceTree = "<group>"; };
|
||||
DA704CC11F65A475004B3F28 /* MGLMapAccessibilityElement.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLMapAccessibilityElement.mm; sourceTree = "<group>"; };
|
||||
DA704CC71F6663A3004B3F28 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/Foundation.strings; sourceTree = "<group>"; };
|
||||
DA7262091DEEE3480043BB89 /* MGLOpenGLStyleLayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MGLOpenGLStyleLayer.h; sourceTree = "<group>"; };
|
||||
DA72620A1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MGLOpenGLStyleLayer.mm; sourceTree = "<group>"; };
|
||||
@@ -1111,6 +1127,8 @@
|
||||
35599DB81D46AD7F0048254D /* Categories */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1FDD9D6D1F26936400252B09 /* MGLVectorSource+MGLAdditions.h */,
|
||||
1FDD9D6E1F26936400252B09 /* MGLVectorSource+MGLAdditions.m */,
|
||||
350098DA1D484E60004B2AF0 /* NSValue+MGLStyleAttributeAdditions.h */,
|
||||
350098DB1D484E60004B2AF0 /* NSValue+MGLStyleAttributeAdditions.mm */,
|
||||
);
|
||||
@@ -1338,6 +1356,7 @@
|
||||
3598544C1E1D38AA00B29F84 /* MGLDistanceFormatterTests.m */,
|
||||
DA0CD58F1CF56F6A00A5F5A5 /* MGLFeatureTests.mm */,
|
||||
DA2E885C1CC0382C00F24E7B /* MGLGeometryTests.mm */,
|
||||
DA5DB1291FABF1EE001C2326 /* MGLMapAccessibilityElementTests.m */,
|
||||
35E208A61D24210F00EC9A46 /* MGLNSDataAdditionsTests.m */,
|
||||
1F95931C1E6DE2E900D5B294 /* MGLNSDateAdditionsTests.mm */,
|
||||
DAE7DEC11E245455007505A6 /* MGLNSStringAdditionsTests.m */,
|
||||
@@ -1415,6 +1434,8 @@
|
||||
35CE617F1D4165C2004F2359 /* Categories */,
|
||||
DAD165841CF4D06B001FF4B9 /* Annotations */,
|
||||
DAD165851CF4D08B001FF4B9 /* Telemetry */,
|
||||
DA704CC01F65A475004B3F28 /* MGLMapAccessibilityElement.h */,
|
||||
DA704CC11F65A475004B3F28 /* MGLMapAccessibilityElement.mm */,
|
||||
DA8848361CBAFB8500AB86E3 /* MGLMapView.h */,
|
||||
DA17BE2F1CC4BAC300402C41 /* MGLMapView_Private.h */,
|
||||
DA8848371CBAFB8500AB86E3 /* MGLMapView+IBAdditions.h */,
|
||||
@@ -1612,8 +1633,6 @@
|
||||
DAD165831CF4CFED001FF4B9 /* Categories */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
1FDD9D6D1F26936400252B09 /* MGLVectorSource+MGLAdditions.h */,
|
||||
1FDD9D6E1F26936400252B09 /* MGLVectorSource+MGLAdditions.m */,
|
||||
7E016D821D9E890300A29A21 /* MGLPolygon+MGLAdditions.h */,
|
||||
7E016D831D9E890300A29A21 /* MGLPolygon+MGLAdditions.m */,
|
||||
7E016D7C1D9E86BE00A29A21 /* MGLPolyline+MGLAdditions.h */,
|
||||
@@ -1754,6 +1773,7 @@
|
||||
DA35A2C91CCAAAD200E826B2 /* NSValue+MGLAdditions.h in Headers */,
|
||||
3510FFEA1D6D9C7A00F413B2 /* NSComparisonPredicate+MGLAdditions.h in Headers */,
|
||||
DA6408DB1DA4E7D300908C90 /* MGLVectorStyleLayer.h in Headers */,
|
||||
DA704CC21F65A475004B3F28 /* MGLMapAccessibilityElement.h in Headers */,
|
||||
DD0902AB1DB192A800C5BDCE /* MGLNetworkConfiguration.h in Headers */,
|
||||
DA8848571CBAFB9800AB86E3 /* MGLMapboxEvents.h in Headers */,
|
||||
35D3A1E61E9BE7EB002B38EE /* MGLScaleBar.h in Headers */,
|
||||
@@ -1889,6 +1909,7 @@
|
||||
558DE7A11E5615E400C7916D /* MGLFoundation_Private.h in Headers */,
|
||||
3538AA1E1D542239008EC33D /* MGLForegroundStyleLayer.h in Headers */,
|
||||
30E578181DAA85520050F07E /* UIImage+MGLAdditions.h in Headers */,
|
||||
DA704CC31F65A475004B3F28 /* MGLMapAccessibilityElement.h in Headers */,
|
||||
40F887711D7A1E59008ECB67 /* MGLShapeSource_Private.h in Headers */,
|
||||
DABFB8631CBE99E500D62B32 /* MGLOfflineRegion.h in Headers */,
|
||||
DA35A2B21CCA141D00E826B2 /* MGLCompassDirectionFormatter.h in Headers */,
|
||||
@@ -2109,6 +2130,7 @@
|
||||
fi,
|
||||
nl,
|
||||
hu,
|
||||
bg,
|
||||
);
|
||||
mainGroup = DA1DC9411CB6C1C2006E619F;
|
||||
productRefGroup = DA1DC94B1CB6C1C2006E619F /* Products */;
|
||||
@@ -2267,6 +2289,7 @@
|
||||
DA2E88621CC0382C00F24E7B /* MGLOfflinePackTests.m in Sources */,
|
||||
55E2AD131E5B125400E8C587 /* MGLOfflineStorageTests.mm in Sources */,
|
||||
920A3E5D1E6F995200C16EFC /* MGLSourceQueryTests.m in Sources */,
|
||||
DA5DB12A1FABF1EE001C2326 /* MGLMapAccessibilityElementTests.m in Sources */,
|
||||
FAE1CDCB1E9D79CB00C40B5B /* MGLFillExtrusionStyleLayerTests.mm in Sources */,
|
||||
DA35A2AA1CCA058D00E826B2 /* MGLCoordinateFormatterTests.m in Sources */,
|
||||
357579831D502AE6000B822E /* MGLRasterStyleLayerTests.mm in Sources */,
|
||||
@@ -2355,6 +2378,7 @@
|
||||
DA88482A1CBAFA6200AB86E3 /* MGLTilePyramidOfflineRegion.mm in Sources */,
|
||||
4049C29F1DB6CD6C00B3F799 /* MGLPointCollection.mm in Sources */,
|
||||
35136D3F1D42273000C20EFD /* MGLLineStyleLayer.mm in Sources */,
|
||||
DA704CC41F65A475004B3F28 /* MGLMapAccessibilityElement.mm in Sources */,
|
||||
DA72620D1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm in Sources */,
|
||||
DA88481A1CBAFA6200AB86E3 /* MGLAccountManager.m in Sources */,
|
||||
3510FFFB1D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.mm in Sources */,
|
||||
@@ -2442,6 +2466,7 @@
|
||||
DAA4E4211CBB730400178DFB /* MGLOfflineStorage.mm in Sources */,
|
||||
4049C2A01DB6CD6C00B3F799 /* MGLPointCollection.mm in Sources */,
|
||||
35136D401D42273000C20EFD /* MGLLineStyleLayer.mm in Sources */,
|
||||
DA704CC51F65A475004B3F28 /* MGLMapAccessibilityElement.mm in Sources */,
|
||||
DA72620E1DEEE3480043BB89 /* MGLOpenGLStyleLayer.mm in Sources */,
|
||||
DAA4E42F1CBB730400178DFB /* MGLCompactCalloutView.m in Sources */,
|
||||
3510FFFC1D6DCC4700F413B2 /* NSCompoundPredicate+MGLAdditions.mm in Sources */,
|
||||
@@ -2520,6 +2545,7 @@
|
||||
DA618B2B1E68932D00CB7F44 /* fi */,
|
||||
DAE8CCAD1E6E8C70009B5CB0 /* nl */,
|
||||
DA5C09BA1EFC48550056B178 /* hu */,
|
||||
DA3389651FA3EE1B001EA329 /* bg */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
@@ -2544,6 +2570,7 @@
|
||||
DA618B2C1E68933600CB7F44 /* fi */,
|
||||
DAE8CCAE1E6E8C76009B5CB0 /* nl */,
|
||||
DACCD9C81F1F473700BB09A1 /* hu */,
|
||||
DA33896A1FA3EE58001EA329 /* bg */,
|
||||
);
|
||||
name = Root.strings;
|
||||
sourceTree = "<group>";
|
||||
@@ -2566,6 +2593,7 @@
|
||||
DA1AC01B1E5B8774006DF1D6 /* lt */,
|
||||
DA618B1B1E68884E00CB7F44 /* ca */,
|
||||
DA5C09BB1EFC486C0056B178 /* hu */,
|
||||
DA3389681FA3EE48001EA329 /* bg */,
|
||||
);
|
||||
name = Localizable.strings;
|
||||
sourceTree = "<group>";
|
||||
@@ -2585,6 +2613,8 @@
|
||||
DAE9E0F11EB7BF1B001E8E8B /* es */,
|
||||
DA704CBB1F637311004B3F28 /* ru */,
|
||||
DA704CC71F6663A3004B3F28 /* uk */,
|
||||
DA33895F1FA3EAB7001EA329 /* pt-BR */,
|
||||
DA3389661FA3EE28001EA329 /* bg */,
|
||||
);
|
||||
name = Foundation.strings;
|
||||
sourceTree = "<group>";
|
||||
@@ -2604,6 +2634,8 @@
|
||||
DA618B1D1E6888F500CB7F44 /* ca */,
|
||||
DA618B261E68920D00CB7F44 /* lt */,
|
||||
DACFE7981F66EA2100630DA8 /* vi */,
|
||||
DA3389671FA3EE2F001EA329 /* bg */,
|
||||
DA33896B1FA3EF4A001EA329 /* hu */,
|
||||
);
|
||||
name = Foundation.stringsdict;
|
||||
sourceTree = "<group>";
|
||||
@@ -2631,6 +2663,7 @@
|
||||
DA57D4AC1EBA922A00793288 /* vi */,
|
||||
DA704CBC1F637405004B3F28 /* uk */,
|
||||
DA704CBD1F63746E004B3F28 /* zh-Hant */,
|
||||
DA3389691FA3EE50001EA329 /* bg */,
|
||||
);
|
||||
name = Localizable.stringsdict;
|
||||
sourceTree = "<group>";
|
||||
|
||||
@@ -34,6 +34,9 @@
|
||||
/* Accessibility label */
|
||||
"INFO_A11Y_LABEL" = "About this map";
|
||||
|
||||
/* List separator */
|
||||
"LIST_SEPARATOR" = ", ";
|
||||
|
||||
/* User-friendly error description */
|
||||
"LOAD_MAP_FAILED_DESC" = "The map failed to load because an unknown error occurred.";
|
||||
|
||||
@@ -46,12 +49,30 @@
|
||||
/* Accessibility label */
|
||||
"MAP_A11Y_LABEL" = "Map";
|
||||
|
||||
/* Map accessibility value */
|
||||
"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld annotation(s) visible";
|
||||
/* Map accessibility value; {number of visible annotations} */
|
||||
"MAP_A11Y_VALUE_ANNOTATIONS" = "%ld annotation(s) visible.";
|
||||
|
||||
/* Map accessibility value; {list of visible places} */
|
||||
"MAP_A11Y_VALUE_PLACES" = "Places visible: %@.";
|
||||
|
||||
/* Map accessibility value; {number of visible roads} */
|
||||
"MAP_A11Y_VALUE_ROADS" = "%ld road(s) visible.";
|
||||
|
||||
/* Map accessibility value; {zoom level} */
|
||||
"MAP_A11Y_VALUE_ZOOM" = "Zoom %dx.";
|
||||
|
||||
/* User-friendly error description */
|
||||
"PARSE_STYLE_FAILED_DESC" = "The map failed to load because the style is corrupted.";
|
||||
|
||||
/* Accessibility value indicating that a road is a divided road (dual carriageway) */
|
||||
"ROAD_DIVIDED_A11Y_VALUE" = "Divided road";
|
||||
|
||||
/* Accessibility value indicating that a road is a one-way road */
|
||||
"ROAD_ONEWAY_A11Y_VALUE" = "One way";
|
||||
|
||||
/* String format for accessibility value for road feature; {route number} */
|
||||
"ROAD_REF_A11Y_FMT" = "Route %@";
|
||||
|
||||
/* Action sheet title */
|
||||
"SDK_NAME" = "Mapbox iOS SDK";
|
||||
|
||||
|
||||
93
platform/ios/resources/bg.lproj/Localizable.strings
Normal file
93
platform/ios/resources/bg.lproj/Localizable.strings
Normal file
@@ -0,0 +1,93 @@
|
||||
/* Accessibility hint */
|
||||
"ANNOTATION_A11Y_HINT" = "Показва повече инфо";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"API_CLIENT_400_DESC" = "Неуспешна сесия за данни. Оригинална заявка: %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"API_CLIENT_400_REASON" = "Статус кодът беше %ld";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"CANCEL" = "Отказ";
|
||||
|
||||
/* Accessibility hint for closing the selected annotation’s callout view and returning to the map */
|
||||
"CLOSE_CALLOUT_A11Y_HINT" = "Връща към картата";
|
||||
|
||||
/* Accessibility hint */
|
||||
"COMPASS_A11Y_HINT" = "Завърта картата в посока север";
|
||||
|
||||
/* Accessibility label */
|
||||
"COMPASS_A11Y_LABEL" = "Компас";
|
||||
|
||||
/* Compass abbreviation for north */
|
||||
"COMPASS_NORTH" = "С";
|
||||
|
||||
/* Instructions in Interface Builder designable; {key}, {plist file name} */
|
||||
"DESIGNABLE" = "За да се показва Mapbox карта тук, добави %1$@ към твоя токен за достъп в %2$@\n\nЗа подробни инструкции, виж:";
|
||||
|
||||
/* Setup documentation URL display string; keep as short as possible */
|
||||
"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
|
||||
|
||||
/* Accessibility hint */
|
||||
"INFO_A11Y_HINT" = "Показва кредитите, форма за връзка и още";
|
||||
|
||||
/* Accessibility label */
|
||||
"INFO_A11Y_LABEL" = "За тази карта";
|
||||
|
||||
/* User-friendly error description */
|
||||
"LOAD_MAP_FAILED_DESC" = "Картата не се зареди поради неизвестна грешка.";
|
||||
|
||||
/* User-friendly error description */
|
||||
"LOAD_STYLE_FAILED_DESC" = "Картата не се зареди поради незареждане на стила.";
|
||||
|
||||
/* Accessibility label */
|
||||
"LOGO_A11Y_LABEL" = "Mapbox";
|
||||
|
||||
/* Accessibility label */
|
||||
"MAP_A11Y_LABEL" = "Карта";
|
||||
|
||||
/* Map accessibility value */
|
||||
"MAP_A11Y_VALUE" = "Мащаб %1$dх\n@2$ld видима(и) анотация(и)";
|
||||
|
||||
/* User-friendly error description */
|
||||
"PARSE_STYLE_FAILED_DESC" = "Картата не се зареди поради повреден стил.";
|
||||
|
||||
/* Action sheet title */
|
||||
"SDK_NAME" = "Mapbox iOS SDK";
|
||||
|
||||
/* Developer-only SDK update notification; {latest version, in format x.x.x} */
|
||||
"SDK_UPDATE_AVAILABLE" = "Сега е налична Mapbox iOS SDK версия %@:";
|
||||
|
||||
/* User-friendly error description */
|
||||
"STYLE_NOT_FOUND_DESC" = "Картата не се зареди поради неоткрит или несъвместим стил.";
|
||||
|
||||
/* Telemetry prompt message */
|
||||
"TELEMETRY_DISABLED_MSG" = "Можеш да помогнеш OpenStreetMap и Mapbox да станат по-добри, като предоставиш анонимни данни за потребление.";
|
||||
|
||||
/* Telemetry prompt button */
|
||||
"TELEMETRY_DISABLED_OFF" = "Не участвам";
|
||||
|
||||
/* Telemetry prompt button */
|
||||
"TELEMETRY_DISABLED_ON" = "Участвам";
|
||||
|
||||
/* Telemetry prompt message */
|
||||
"TELEMETRY_ENABLED_MSG" = "Помагаш OpenStreetMap и Mapbox да станат по-добри, като предоставяш анонимни данни за потребление.";
|
||||
|
||||
/* Telemetry prompt button */
|
||||
"TELEMETRY_ENABLED_OFF" = "Спирам участие";
|
||||
|
||||
/* Telemetry prompt button */
|
||||
"TELEMETRY_ENABLED_ON" = "Продължавам да участвам";
|
||||
|
||||
/* Telemetry prompt button */
|
||||
"TELEMETRY_MORE" = "Искам още инфо";
|
||||
|
||||
/* Action in attribution sheet */
|
||||
"TELEMETRY_NAME" = "Mapbox Телеметрия";
|
||||
|
||||
/* Telemetry prompt title */
|
||||
"TELEMETRY_TITLE" = "Направи Mapbox картите по-добри";
|
||||
|
||||
/* Default user location annotation title */
|
||||
"USER_DOT_TITLE" = "Сега си тук";
|
||||
|
||||
34
platform/ios/resources/bg.lproj/Localizable.stringsdict
Normal file
34
platform/ios/resources/bg.lproj/Localizable.stringsdict
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>MAP_A11Y_VALUE</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@level@
|
||||
%#@count@</string>
|
||||
<key>level</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Мащаб %dx</string>
|
||||
<key>other</key>
|
||||
<string>Мащаб %dx</string>
|
||||
</dict>
|
||||
<key>count</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>one</key>
|
||||
<string>%d видима анотация</string>
|
||||
<key>other</key>
|
||||
<string>%d видими анотации</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -2,22 +2,10 @@
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>MAP_A11Y_VALUE</key>
|
||||
<key>MAP_A11Y_VALUE_ANNOTATIONS</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@level@
|
||||
%#@count@</string>
|
||||
<key>level</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Zoom %dx</string>
|
||||
<key>other</key>
|
||||
<string>Zoom %dx</string>
|
||||
</dict>
|
||||
<string>%#@count@</string>
|
||||
<key>count</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
@@ -30,5 +18,37 @@
|
||||
<string>%d annotations visible</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>MAP_A11Y_VALUE_ROADS</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@count@</string>
|
||||
<key>count</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>ld</string>
|
||||
<key>one</key>
|
||||
<string>%d road visible</string>
|
||||
<key>other</key>
|
||||
<string>%d roads visible</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>MAP_A11Y_VALUE_ZOOM</key>
|
||||
<dict>
|
||||
<key>NSStringLocalizedFormatKey</key>
|
||||
<string>%#@level@</string>
|
||||
<key>level</key>
|
||||
<dict>
|
||||
<key>NSStringFormatSpecTypeKey</key>
|
||||
<string>NSStringPluralRuleType</string>
|
||||
<key>NSStringFormatValueTypeKey</key>
|
||||
<string>d</string>
|
||||
<key>one</key>
|
||||
<string>Zoom %dx</string>
|
||||
<key>other</key>
|
||||
<string>Zoom %dx</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"ANNOTATION_A11Y_HINT" = "Mostrar mais informações";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"API_CLIENT_400_DESC" = "The session data task failed. Original request was: %@";
|
||||
"API_CLIENT_400_DESC" = "Tarefa de dados da sessão falhou. Requisição original: %@";
|
||||
|
||||
/* No comment provided by engineer. */
|
||||
"API_CLIENT_400_REASON" = "O código de status foi %ld";
|
||||
@@ -10,6 +10,9 @@
|
||||
/* No comment provided by engineer. */
|
||||
"CANCEL" = "Cancelar";
|
||||
|
||||
/* Accessibility hint for closing the selected annotation’s callout view and returning to the map */
|
||||
"CLOSE_CALLOUT_A11Y_HINT" = "Retornar ao mapa";
|
||||
|
||||
/* Accessibility hint */
|
||||
"COMPASS_A11Y_HINT" = "Rotaciona o mapa com face ao norte";
|
||||
|
||||
@@ -20,7 +23,7 @@
|
||||
"COMPASS_NORTH" = "N";
|
||||
|
||||
/* Instructions in Interface Builder designable; {key}, {plist file name} */
|
||||
"DESIGNABLE" = "To display a Mapbox-hosted map here, set %1$@ to your access token in %2$@\n\nFor detailed instructions, see:";
|
||||
"DESIGNABLE" = "Para exibir um mapa hospedado no Mapbox aqui, insira %1$@ para seu token de acesso %2$@\n\nPara maiores detalhes, veja:";
|
||||
|
||||
/* Setup documentation URL display string; keep as short as possible */
|
||||
"FIRST_STEPS_URL" = "mapbox.com/help/first-steps-ios-sdk";
|
||||
@@ -31,6 +34,12 @@
|
||||
/* Accessibility label */
|
||||
"INFO_A11Y_LABEL" = "Sobre este mapa";
|
||||
|
||||
/* User-friendly error description */
|
||||
"LOAD_MAP_FAILED_DESC" = "Falha ao carregar mapa devido a um erro desconhecido";
|
||||
|
||||
/* User-friendly error description */
|
||||
"LOAD_STYLE_FAILED_DESC" = "Falha ao carregar mapa porque o estilo não pode ser carregado";
|
||||
|
||||
/* Accessibility label */
|
||||
"LOGO_A11Y_LABEL" = "Mapbox";
|
||||
|
||||
@@ -40,11 +49,20 @@
|
||||
/* Map accessibility value */
|
||||
"MAP_A11Y_VALUE" = "Zoom %1$dx\n%2$ld anotações visíveis";
|
||||
|
||||
/* User-friendly error description */
|
||||
"PARSE_STYLE_FAILED_DESC" = "Falha ao carregar mapa porque o estilo está corrompido.";
|
||||
|
||||
/* Action sheet title */
|
||||
"SDK_NAME" = "Mapbox iOS SDK";
|
||||
|
||||
/* Developer-only SDK update notification; {latest version, in format x.x.x} */
|
||||
"SDK_UPDATE_AVAILABLE" = "SDK Mapbox para iOS versão %@ está disponível:";
|
||||
|
||||
/* User-friendly error description */
|
||||
"STYLE_NOT_FOUND_DESC" = "Falha ao carregar mapa porque o estilo não pode ser encontrado ou é incompatível.";
|
||||
|
||||
/* Telemetry prompt message */
|
||||
"TELEMETRY_DISABLED_MSG" = "You can help make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.";
|
||||
"TELEMETRY_DISABLED_MSG" = "Você pode ajudar a tornar o OpenStreetMap e Mapbox ainda melhor contribuindo anonimamente com seus dados de uso.";
|
||||
|
||||
/* Telemetry prompt button */
|
||||
"TELEMETRY_DISABLED_OFF" = "Não Participar";
|
||||
@@ -53,7 +71,7 @@
|
||||
"TELEMETRY_DISABLED_ON" = "Participar";
|
||||
|
||||
/* Telemetry prompt message */
|
||||
"TELEMETRY_ENABLED_MSG" = "You are helping to make OpenStreetMap and Mapbox maps better by contributing anonymous usage data.";
|
||||
"TELEMETRY_ENABLED_MSG" = "Você está ajudando a tornar o OpenStreetMap e Mapbox ainda melhor contribuindo anonimamente com seus dados de uso.";
|
||||
|
||||
/* Telemetry prompt button */
|
||||
"TELEMETRY_ENABLED_OFF" = "Parar de Participar";
|
||||
|
||||
@@ -58,17 +58,17 @@ BINARY_DIRECTORY=${BINARY_DIRECTORY:-build/ios/deploy}
|
||||
GITHUB_RELEASE=${GITHUB_RELEASE:-true}
|
||||
PUBLISH_PRE_FLAG=''
|
||||
|
||||
if [[ -z `which github-release` ]]; then
|
||||
step "Installing github-release…"
|
||||
brew install github-release
|
||||
if [ -z `which github-release` ]; then
|
||||
echo "Unable to install github-release. See: https://github.com/aktau/github-release"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ ${GITHUB_RELEASE} = "true" ]]; then
|
||||
GITHUB_RELEASE=true # Assign bool, not just a string
|
||||
|
||||
if [[ -z `which github-release` ]]; then
|
||||
step "Installing github-release…"
|
||||
brew install github-release
|
||||
if [ -z `which github-release` ]; then
|
||||
echo "Unable to install github-release. See: https://github.com/aktau/github-release"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -z ${VERSION_TAG} ]]; then
|
||||
@@ -83,7 +83,7 @@ if [[ $( echo ${VERSION_TAG} | grep --invert-match ios-v ) ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ $( curl --head https://api.github.com/repos/${GITHUB_USER}/${GITHUB_REPO}/releases/tags/${VERSION_TAG} | head -n 1 | grep -c "404 Not Found") == 0 ]]; then
|
||||
if github-release info --tag ${VERSION_TAG} | grep --quiet "draft: ✗"; then
|
||||
echo "Error: ${VERSION_TAG} has already been published on GitHub"
|
||||
echo "See: https://github.com/${GITHUB_USER}/${GITHUB_REPO}/releases/tag/${VERSION_TAG}"
|
||||
exit 1
|
||||
|
||||
@@ -6,7 +6,7 @@ set -u
|
||||
|
||||
if [ -z `which jazzy` ]; then
|
||||
echo "Installing jazzy…"
|
||||
gem install jazzy
|
||||
gem install jazzy --no-rdoc --no-ri
|
||||
if [ -z `which jazzy` ]; then
|
||||
echo "Unable to install jazzy. See https://github.com/mapbox/mapbox-gl-native/blob/master/platform/ios/INSTALL.md"
|
||||
exit 1
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
callout view displays the represented annotation’s title, subtitle, and
|
||||
accessory views in a compact, two-line layout.
|
||||
*/
|
||||
@interface MGLCompactCalloutView : SMCalloutView <MGLCalloutView>
|
||||
@interface MGLCompactCalloutView : MGLSMCalloutView <MGLCalloutView>
|
||||
|
||||
+ (instancetype)platformCalloutView;
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ const CGFloat MGLUserLocationAnnotationDotSize = 22.0;
|
||||
const CGFloat MGLUserLocationAnnotationHaloSize = 115.0;
|
||||
|
||||
const CGFloat MGLUserLocationAnnotationPuckSize = 45.0;
|
||||
const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuckSize * 0.6;
|
||||
const CGFloat MGLUserLocationAnnotationArrowSize = MGLUserLocationAnnotationPuckSize * 0.5;
|
||||
|
||||
const CGFloat MGLUserLocationHeadingUpdateThreshold = 0.01;
|
||||
|
||||
@@ -175,12 +175,16 @@ const CGFloat MGLUserLocationHeadingUpdateThreshold = 0.01;
|
||||
_puckArrow = [CAShapeLayer layer];
|
||||
_puckArrow.path = [[self puckArrow] CGPath];
|
||||
_puckArrow.fillColor = [self.mapView.tintColor CGColor];
|
||||
_puckArrow.bounds = CGRectMake(0, 0, MGLUserLocationAnnotationArrowSize, MGLUserLocationAnnotationArrowSize);
|
||||
_puckArrow.position = CGPointMake(super.bounds.size.width / 2.0, super.bounds.size.height / 2.0);
|
||||
_puckArrow.bounds = CGRectMake(0, 0, round(MGLUserLocationAnnotationArrowSize), round(MGLUserLocationAnnotationArrowSize));
|
||||
_puckArrow.position = CGPointMake(CGRectGetMidX(super.bounds), CGRectGetMidY(super.bounds));
|
||||
_puckArrow.shouldRasterize = YES;
|
||||
_puckArrow.rasterizationScale = [UIScreen mainScreen].scale;
|
||||
_puckArrow.drawsAsynchronously = YES;
|
||||
|
||||
_puckArrow.lineJoin = @"round";
|
||||
_puckArrow.lineWidth = 1.f;
|
||||
_puckArrow.strokeColor = _puckArrow.fillColor;
|
||||
|
||||
[self.layer addSublayer:_puckArrow];
|
||||
}
|
||||
if (self.userLocation.location.course >= 0)
|
||||
@@ -302,7 +306,7 @@ const CGFloat MGLUserLocationHeadingUpdateThreshold = 0.01;
|
||||
[CATransaction setDisableActions:shouldDisableActions];
|
||||
|
||||
_accuracyRingLayer.bounds = CGRectMake(0, 0, accuracyRingSize, accuracyRingSize);
|
||||
_accuracyRingLayer.cornerRadius = accuracyRingSize / 2;
|
||||
_accuracyRingLayer.cornerRadius = accuracyRingSize / 2.0;
|
||||
|
||||
// match the halo to the accuracy ring
|
||||
_haloLayer.bounds = _accuracyRingLayer.bounds;
|
||||
@@ -431,9 +435,11 @@ const CGFloat MGLUserLocationHeadingUpdateThreshold = 0.01;
|
||||
|
||||
- (CALayer *)circleLayerWithSize:(CGFloat)layerSize
|
||||
{
|
||||
layerSize = round(layerSize);
|
||||
|
||||
CALayer *circleLayer = [CALayer layer];
|
||||
circleLayer.bounds = CGRectMake(0, 0, layerSize, layerSize);
|
||||
circleLayer.position = CGPointMake(super.bounds.size.width / 2.0, super.bounds.size.height / 2.0);
|
||||
circleLayer.position = CGPointMake(CGRectGetMidX(super.bounds), CGRectGetMidY(super.bounds));
|
||||
circleLayer.cornerRadius = layerSize / 2.0;
|
||||
circleLayer.shouldRasterize = YES;
|
||||
circleLayer.rasterizationScale = [UIScreen mainScreen].scale;
|
||||
@@ -456,7 +462,7 @@ const CGFloat MGLUserLocationHeadingUpdateThreshold = 0.01;
|
||||
- (CGFloat)calculateAccuracyRingSize
|
||||
{
|
||||
// diameter in screen points
|
||||
return self.userLocation.location.horizontalAccuracy / [self.mapView metersPerPointAtLatitude:self.userLocation.coordinate.latitude] * 2.0;
|
||||
return round(self.userLocation.location.horizontalAccuracy / [self.mapView metersPerPointAtLatitude:self.userLocation.coordinate.latitude] * 2.0);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
54
platform/ios/src/MGLMapAccessibilityElement.h
Normal file
54
platform/ios/src/MGLMapAccessibilityElement.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
#import "MGLFoundation.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol MGLFeature;
|
||||
|
||||
/// Unique identifier representing a single annotation in mbgl.
|
||||
typedef uint32_t MGLAnnotationTag;
|
||||
|
||||
/** An accessibility element representing something that appears on the map. */
|
||||
MGL_EXPORT
|
||||
@interface MGLMapAccessibilityElement : UIAccessibilityElement
|
||||
|
||||
@end
|
||||
|
||||
/** An accessibility element representing a map annotation. */
|
||||
@interface MGLAnnotationAccessibilityElement : MGLMapAccessibilityElement
|
||||
|
||||
/** The tag of the annotation represented by this element. */
|
||||
@property (nonatomic) MGLAnnotationTag tag;
|
||||
|
||||
- (instancetype)initWithAccessibilityContainer:(id)container tag:(MGLAnnotationTag)identifier NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
/** An accessibility element representing a map feature. */
|
||||
MGL_EXPORT
|
||||
@interface MGLFeatureAccessibilityElement : MGLMapAccessibilityElement
|
||||
|
||||
/** The feature represented by this element. */
|
||||
@property (nonatomic, strong) id <MGLFeature> feature;
|
||||
|
||||
- (instancetype)initWithAccessibilityContainer:(id)container feature:(id <MGLFeature>)feature NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
@end
|
||||
|
||||
/** An accessibility element representing a place feature. */
|
||||
MGL_EXPORT
|
||||
@interface MGLPlaceFeatureAccessibilityElement : MGLFeatureAccessibilityElement
|
||||
@end
|
||||
|
||||
/** An accessibility element representing a road feature. */
|
||||
MGL_EXPORT
|
||||
@interface MGLRoadFeatureAccessibilityElement : MGLFeatureAccessibilityElement
|
||||
@end
|
||||
|
||||
/** An accessibility element representing the MGLMapView at large. */
|
||||
MGL_EXPORT
|
||||
@interface MGLMapViewProxyAccessibilityElement : UIAccessibilityElement
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
199
platform/ios/src/MGLMapAccessibilityElement.mm
Normal file
199
platform/ios/src/MGLMapAccessibilityElement.mm
Normal file
@@ -0,0 +1,199 @@
|
||||
#import "MGLMapAccessibilityElement.h"
|
||||
#import "MGLDistanceFormatter.h"
|
||||
#import "MGLCompassDirectionFormatter.h"
|
||||
#import "MGLFeature.h"
|
||||
#import "MGLVectorSource+MGLAdditions.h"
|
||||
|
||||
#import "NSBundle+MGLAdditions.h"
|
||||
#import "MGLGeometry_Private.h"
|
||||
|
||||
@implementation MGLMapAccessibilityElement
|
||||
|
||||
- (UIAccessibilityTraits)accessibilityTraits {
|
||||
return super.accessibilityTraits | UIAccessibilityTraitAdjustable;
|
||||
}
|
||||
|
||||
- (void)accessibilityIncrement {
|
||||
[self.accessibilityContainer accessibilityIncrement];
|
||||
}
|
||||
|
||||
- (void)accessibilityDecrement {
|
||||
[self.accessibilityContainer accessibilityDecrement];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MGLAnnotationAccessibilityElement
|
||||
|
||||
- (instancetype)initWithAccessibilityContainer:(id)container tag:(MGLAnnotationTag)tag {
|
||||
if (self = [super initWithAccessibilityContainer:container]) {
|
||||
_tag = tag;
|
||||
self.accessibilityHint = NSLocalizedStringWithDefaultValue(@"ANNOTATION_A11Y_HINT", nil, nil, @"Shows more info", @"Accessibility hint");
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIAccessibilityTraits)accessibilityTraits {
|
||||
return super.accessibilityTraits | UIAccessibilityTraitButton;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MGLFeatureAccessibilityElement
|
||||
|
||||
- (instancetype)initWithAccessibilityContainer:(id)container feature:(id<MGLFeature>)feature {
|
||||
if (self = [super initWithAccessibilityContainer:container]) {
|
||||
_feature = feature;
|
||||
|
||||
NSString *languageCode = [MGLVectorSource preferredMapboxStreetsLanguage];
|
||||
NSString *nameAttribute = [NSString stringWithFormat:@"name_%@", languageCode];
|
||||
NSString *name = [feature attributeForKey:nameAttribute];
|
||||
|
||||
// If a feature hasn’t been translated into the preferred language, it
|
||||
// may be in the local language, which may be written in another script.
|
||||
// Romanize it.
|
||||
NSLocale *locale = [NSLocale localeWithLocaleIdentifier:languageCode];
|
||||
NSOrthography *orthography;
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 110000
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunguarded-availability-new"
|
||||
if ([NSOrthography respondsToSelector:@selector(defaultOrthographyForLanguage:)]) {
|
||||
orthography = [NSOrthography defaultOrthographyForLanguage:locale.localeIdentifier];
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
if ([orthography.dominantScript isEqualToString:@"Latn"]) {
|
||||
name = [name stringByApplyingTransform:NSStringTransformToLatin reverse:NO];
|
||||
}
|
||||
|
||||
self.accessibilityLabel = name;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (UIAccessibilityTraits)accessibilityTraits {
|
||||
return super.accessibilityTraits | UIAccessibilityTraitStaticText;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MGLPlaceFeatureAccessibilityElement
|
||||
|
||||
- (instancetype)initWithAccessibilityContainer:(id)container feature:(id<MGLFeature>)feature {
|
||||
if (self = [super initWithAccessibilityContainer:container feature:feature]) {
|
||||
NSDictionary *attributes = feature.attributes;
|
||||
NSMutableArray *facts = [NSMutableArray array];
|
||||
|
||||
// Announce the kind of place or POI.
|
||||
if (attributes[@"type"]) {
|
||||
// FIXME: Unfortunately, these types aren’t a closed set that can be
|
||||
// localized, since they’re based on OpenStreetMap tags.
|
||||
NSString *type = [attributes[@"type"] stringByReplacingOccurrencesOfString:@"_"
|
||||
withString:@" "];
|
||||
[facts addObject:type];
|
||||
}
|
||||
// Announce the kind of airport, rail station, or mountain based on its
|
||||
// Maki image name.
|
||||
else if (attributes[@"maki"]) {
|
||||
// TODO: Localize Maki image names.
|
||||
[facts addObject:attributes[@"maki"]];
|
||||
}
|
||||
|
||||
// Announce the peak’s elevation in the preferred units.
|
||||
if (attributes[@"elevation_m"] ?: attributes[@"elevation_ft"]) {
|
||||
NSLengthFormatter *formatter = [[NSLengthFormatter alloc] init];
|
||||
formatter.unitStyle = NSFormattingUnitStyleLong;
|
||||
|
||||
NSNumber *elevationValue;
|
||||
NSLengthFormatterUnit unit;
|
||||
BOOL usesMetricSystem = ![[formatter.numberFormatter.locale objectForKey:NSLocaleMeasurementSystem]
|
||||
isEqualToString:@"U.S."];
|
||||
if (usesMetricSystem) {
|
||||
elevationValue = attributes[@"elevation_m"];
|
||||
unit = NSLengthFormatterUnitMeter;
|
||||
} else {
|
||||
elevationValue = attributes[@"elevation_ft"];
|
||||
unit = NSLengthFormatterUnitFoot;
|
||||
}
|
||||
[facts addObject:[formatter stringFromValue:elevationValue.doubleValue unit:unit]];
|
||||
}
|
||||
|
||||
if (facts.count) {
|
||||
NSString *separator = NSLocalizedStringWithDefaultValue(@"LIST_SEPARATOR", nil, nil, @", ", @"List separator");
|
||||
self.accessibilityValue = [facts componentsJoinedByString:separator];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MGLRoadFeatureAccessibilityElement
|
||||
|
||||
- (instancetype)initWithAccessibilityContainer:(id)container feature:(id<MGLFeature>)feature {
|
||||
if (self = [super initWithAccessibilityContainer:container feature:feature]) {
|
||||
NSDictionary *attributes = feature.attributes;
|
||||
NSMutableArray *facts = [NSMutableArray array];
|
||||
|
||||
// Announce the route number.
|
||||
if (attributes[@"ref"]) {
|
||||
// TODO: Decorate the route number with the network name based on the shield attribute.
|
||||
NSString *ref = [NSString stringWithFormat:NSLocalizedStringWithDefaultValue(@"ROAD_REF_A11Y_FMT", nil, nil, @"Route %@", @"String format for accessibility value for road feature; {route number}"), attributes[@"ref"]];
|
||||
[facts addObject:ref];
|
||||
}
|
||||
|
||||
// Announce whether the road is a one-way road.
|
||||
if ([attributes[@"oneway"] isEqualToString:@"true"]) {
|
||||
[facts addObject:NSLocalizedStringWithDefaultValue(@"ROAD_ONEWAY_A11Y_VALUE", nil, nil, @"One way", @"Accessibility value indicating that a road is a one-way road")];
|
||||
}
|
||||
|
||||
// Announce whether the road is a divided road.
|
||||
MGLPolyline *polyline;
|
||||
if ([feature isKindOfClass:[MGLMultiPolylineFeature class]]) {
|
||||
[facts addObject:NSLocalizedStringWithDefaultValue(@"ROAD_DIVIDED_A11Y_VALUE", nil, nil, @"Divided road", @"Accessibility value indicating that a road is a divided road (dual carriageway)")];
|
||||
polyline = [(MGLMultiPolylineFeature *)feature polylines].firstObject;
|
||||
}
|
||||
|
||||
// Announce the road’s general direction.
|
||||
if ([feature isKindOfClass:[MGLPolylineFeature class]]) {
|
||||
polyline = (MGLPolylineFeature *)feature;
|
||||
}
|
||||
if (polyline) {
|
||||
NSUInteger pointCount = polyline.pointCount;
|
||||
if (pointCount) {
|
||||
CLLocationCoordinate2D *coordinates = polyline.coordinates;
|
||||
CLLocationDirection startDirection = MGLDirectionBetweenCoordinates(coordinates[pointCount - 1], coordinates[0]);
|
||||
CLLocationDirection endDirection = MGLDirectionBetweenCoordinates(coordinates[0], coordinates[pointCount - 1]);
|
||||
|
||||
MGLCompassDirectionFormatter *formatter = [[MGLCompassDirectionFormatter alloc] init];
|
||||
formatter.unitStyle = NSFormattingUnitStyleLong;
|
||||
|
||||
NSString *startDirectionString = [formatter stringFromDirection:startDirection];
|
||||
NSString *endDirectionString = [formatter stringFromDirection:endDirection];
|
||||
NSString *directionString = [NSString stringWithFormat:NSLocalizedStringWithDefaultValue(@"ROAD_DIRECTION_A11Y_FMT", nil, nil, @"%@ to %@", @"String format for accessibility value for road feature; {starting compass direction}, {ending compass direction}"), startDirectionString, endDirectionString];
|
||||
[facts addObject:directionString];
|
||||
}
|
||||
}
|
||||
|
||||
if (facts.count) {
|
||||
NSString *separator = NSLocalizedStringWithDefaultValue(@"LIST_SEPARATOR", nil, nil, @", ", @"List separator");
|
||||
self.accessibilityValue = [facts componentsJoinedByString:separator];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation MGLMapViewProxyAccessibilityElement
|
||||
|
||||
- (instancetype)initWithAccessibilityContainer:(id)container {
|
||||
if (self = [super initWithAccessibilityContainer:container]) {
|
||||
self.accessibilityTraits = UIAccessibilityTraitButton;
|
||||
self.accessibilityLabel = [self.accessibilityContainer accessibilityLabel];
|
||||
self.accessibilityHint = NSLocalizedStringWithDefaultValue(@"CLOSE_CALLOUT_A11Y_HINT", nil, nil, @"Returns to the map", @"Accessibility hint for closing the selected annotation’s callout view and returning to the map");
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
File diff suppressed because it is too large
Load Diff
@@ -175,10 +175,15 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
|
||||
return [self usesMetricSystem] ? self.metersPerPoint : self.metersPerPoint * MGLFeetPerMeter;
|
||||
}
|
||||
|
||||
#pragma mark - Convenient methods
|
||||
#pragma mark - Convenience methods
|
||||
|
||||
- (BOOL)usesRightToLeftLayout {
|
||||
return [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.superview.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft;
|
||||
// semanticContentAttribute is iOS 9+
|
||||
if ([self.superview respondsToSelector:@selector(semanticContentAttribute)]) {
|
||||
return [UIView userInterfaceLayoutDirectionForSemanticContentAttribute:self.superview.semanticContentAttribute] == UIUserInterfaceLayoutDirectionRightToLeft;
|
||||
} else {
|
||||
return UIApplication.sharedApplication.userInterfaceLayoutDirection == UIUserInterfaceLayoutDirectionRightToLeft;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)usesMetricSystem {
|
||||
@@ -241,7 +246,7 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
|
||||
|
||||
CGFloat alpha = maximumDistance > allowedDistance ? .0f : 1.0f;
|
||||
|
||||
if(self.alpha != alpha) {
|
||||
if (self.alpha != alpha) {
|
||||
[UIView animateWithDuration:.2f delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
|
||||
self.alpha = alpha;
|
||||
} completion:nil];
|
||||
@@ -331,7 +336,7 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
|
||||
}
|
||||
|
||||
- (void)layoutBars {
|
||||
CGFloat barWidth = (CGRectGetWidth(self.bounds) - self.borderWidth * 2.0f) / self.bars.count;
|
||||
CGFloat barWidth = round((CGRectGetWidth(self.bounds) - self.borderWidth * 2.0f) / self.bars.count);
|
||||
|
||||
NSUInteger i = 0;
|
||||
for (UIView *bar in self.bars) {
|
||||
@@ -354,11 +359,11 @@ static const CGFloat MGLFeetPerMeter = 3.28084;
|
||||
}
|
||||
|
||||
- (void)layoutLabels {
|
||||
CGFloat barWidth = self.bounds.size.width / self.bars.count;
|
||||
CGFloat barWidth = round(self.bounds.size.width / self.bars.count);
|
||||
BOOL RTL = [self usesRightToLeftLayout];
|
||||
NSUInteger i = RTL ? self.bars.count : 0;
|
||||
for (MGLScaleBarLabel *label in self.labels) {
|
||||
CGFloat xPosition = barWidth * i - CGRectGetMidX(label.bounds) + self.borderWidth;
|
||||
CGFloat xPosition = round(barWidth * i - CGRectGetMidX(label.bounds) + self.borderWidth);
|
||||
label.frame = CGRectMake(xPosition, 0,
|
||||
CGRectGetWidth(label.bounds),
|
||||
CGRectGetHeight(label.bounds));
|
||||
|
||||
@@ -34,7 +34,8 @@ MGL_EXPORT
|
||||
The heading of the user location. (read-only)
|
||||
|
||||
This property is `nil` if the user location tracking mode is not
|
||||
`MGLUserTrackingModeFollowWithHeading`.
|
||||
`MGLUserTrackingModeFollowWithHeading` or if
|
||||
`MGLMapView.showsUserHeadingIndicator` is disabled.
|
||||
*/
|
||||
@property (nonatomic, readonly, nullable) CLHeading *heading;
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user