Merge branch 'master' into node
18
.clang-format
Normal file
@@ -0,0 +1,18 @@
|
||||
Standard: Cpp11
|
||||
IndentWidth: 4
|
||||
AccessModifierOffset: -4
|
||||
UseTab: Never
|
||||
BinPackParameters: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
NamespaceIndentation: None
|
||||
PointerBindsToType: true
|
||||
SpacesInParentheses: false
|
||||
BreakBeforeBraces: Attach
|
||||
ColumnLimit: 100
|
||||
Cpp11BracedListStyle: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
35
.gitignore
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
.DS_Store
|
||||
*.xcodeproj
|
||||
*.o
|
||||
*.actual.png
|
||||
*.diff.png
|
||||
*.pyc
|
||||
/android/debug
|
||||
/android/sdk
|
||||
/android/**/.classpath
|
||||
/android/**/.project
|
||||
/android/**/.settings/
|
||||
/mason_packages
|
||||
/config/*.gypi
|
||||
/build
|
||||
/macosx/build
|
||||
/linux/build
|
||||
/ios/build
|
||||
/ios/app/build
|
||||
/test/build
|
||||
/gyp/build
|
||||
/gyp/java
|
||||
/test/node_modules
|
||||
/test/fixtures/*/*_actual.*
|
||||
/test/fixtures/api/1.png
|
||||
/test/fixtures/api/2.png
|
||||
/test/fixtures/database/*.db
|
||||
/include/mbgl/shader/shaders.hpp
|
||||
/src/shader/shaders_gl.cpp
|
||||
/src/shader/shaders_gles2.cpp
|
||||
/bin/style.bin.js
|
||||
*~
|
||||
|
||||
/ios/benchmark/assets/tiles/mapbox.mapbox-streets-v6/
|
||||
/ios/benchmark/assets/tiles/mapbox.mapbox-terrain-v2/
|
||||
/ios/benchmark/assets/glyphs/DIN Offc Pro*/
|
||||
23
.gitmodules
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
[submodule "test/suite"]
|
||||
path = test/suite
|
||||
url = https://github.com/mapbox/mapbox-gl-test-suite.git
|
||||
|
||||
[submodule ".mason"]
|
||||
path = .mason
|
||||
url = https://github.com/mapbox/mason.git
|
||||
|
||||
[submodule "styles"]
|
||||
path = styles
|
||||
url = https://github.com/mapbox/mapbox-gl-styles.git
|
||||
|
||||
[submodule "test/ios/KIF"]
|
||||
path = test/ios/KIF
|
||||
url = https://github.com/kif-framework/KIF.git
|
||||
|
||||
[submodule "platform/ios/vendor/SMCalloutView"]
|
||||
path = platform/ios/vendor/SMCalloutView
|
||||
url = https://github.com/nfarina/calloutview.git
|
||||
|
||||
[submodule "src/mbgl/util/geojsonvt"]
|
||||
path = src/mbgl/util/geojsonvt
|
||||
url = https://github.com/mapbox/geojson-vt-cpp
|
||||
1
.mason
Submodule
100
.travis.yml
Normal file
@@ -0,0 +1,100 @@
|
||||
language: android
|
||||
|
||||
sudo: false
|
||||
|
||||
matrix:
|
||||
exclude:
|
||||
- os: linux
|
||||
include:
|
||||
- os: linux
|
||||
env: FLAVOR=linux CXX=g++-4.9 BUILDTYPE=Release
|
||||
addons:
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test' ]
|
||||
packages: [ 'gdb', 'g++-4.9', 'gcc-4.9', 'libllvm3.4', 'xutils-dev', 'libxxf86vm-dev', 'x11proto-xf86vidmode-dev', 'mesa-utils' ]
|
||||
- os: linux
|
||||
env: FLAVOR=linux CXX=clang++-3.5 BUILDTYPE=Debug
|
||||
addons:
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5' ]
|
||||
packages: [ 'gdb', 'clang-3.5', 'libstdc++-4.9-dev', 'libstdc++6', 'libllvm3.4', 'xutils-dev', 'libxxf86vm-dev', 'x11proto-xf86vidmode-dev', 'mesa-utils' ]
|
||||
- os: linux
|
||||
env: FLAVOR=linux CXX=clang++-3.5 BUILDTYPE=Release
|
||||
addons:
|
||||
apt:
|
||||
sources: [ 'ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.5' ]
|
||||
packages: [ 'gdb', 'clang-3.5', 'libstdc++-4.9-dev', 'libstdc++6', 'libllvm3.4', 'xutils-dev', 'libxxf86vm-dev', 'x11proto-xf86vidmode-dev', 'mesa-utils' ]
|
||||
- os: osx
|
||||
osx_image: xcode6.4
|
||||
env: FLAVOR=osx BUILDTYPE=Debug
|
||||
- os: osx
|
||||
osx_image: xcode6.4
|
||||
env: FLAVOR=ios BUILDTYPE=Release
|
||||
- os: linux
|
||||
env: FLAVOR=android ANDROID_ABI=arm-v7 BUILDTYPE=Release
|
||||
android:
|
||||
components: [ 'build-tools-23', 'android-23', 'extra-android-m2repository' ]
|
||||
addons:
|
||||
apt:
|
||||
packages: [ 'lib32stdc++6' ]
|
||||
- os: linux
|
||||
env: FLAVOR=android ANDROID_ABI=arm-v7 BUILDTYPE=Debug
|
||||
android:
|
||||
components: [ 'build-tools-23', 'android-23', 'extra-android-m2repository' ]
|
||||
addons:
|
||||
apt:
|
||||
packages: [ 'lib32stdc++6' ]
|
||||
- os: linux
|
||||
env: FLAVOR=android ANDROID_ABI=arm-v8 BUILDTYPE=Release
|
||||
android:
|
||||
components: [ 'build-tools-23', 'android-23', 'extra-android-m2repository' ]
|
||||
addons:
|
||||
apt:
|
||||
packages: [ 'lib32stdc++6' ]
|
||||
- os: linux
|
||||
env: FLAVOR=android ANDROID_ABI=x86 BUILDTYPE=Release
|
||||
android:
|
||||
components: [ 'build-tools-23', 'android-23', 'extra-android-m2repository' ]
|
||||
addons:
|
||||
apt:
|
||||
packages: [ 'lib32stdc++6' ]
|
||||
|
||||
env:
|
||||
global:
|
||||
- TERM: dumb
|
||||
# AWS
|
||||
- secure: "MZHblLZXG/jWf2w0ZFlxCLDwx2qtGgRDODQyg1BR7JIuMz6AtWv8XR/sUczWLbiABCL0a/NzJF1g4v2pI7X69IntcjOdIABBgTh7++6+1TJ0Kp8viEltb55nQG3lHy/R6fOaI7Pj9tuCX0PCRtGA5C/fGnodLGEjy3RVOJ09ln0="
|
||||
- secure: "KaSQbhgjtV7ZCkesHmvrNsbQVjk5SPfGKB1VkWenRGYhLF45HpSRNwSxMQddZ566Pg7qIFgF1iWl/B0QW3B6AWL5WmzQ5AOJgwS876pNIc/UT7ubMPtgAtjpvw1bQvQP3B8MrB+3OE5c6tD+a3LhR9krV//dOsfErR5Yy+3Mbkc="
|
||||
# Access Token
|
||||
- secure: "RiBIBfVhhaMjU5ksuwJO3shdvG9FpinBjdSv4co9jg9171SR8edNriedHjVKSIeBhSGNmZmX+twS3dJS/By6tl/LKh9sTynA+ZAYYljkE7jn881B/gMrlYvdAA6og5KvkhV1/0iJWlhuZrMTkhpDR200iLgg3EWBhWjltzmDW/I="
|
||||
# Testmunk
|
||||
- secure: "CHBiUM60TolDbQnn+4IRA/tvOKwKs3g9EDvv8YHSJMg3FuHmjKQkprBasvxf3hnTXg4WLZEubmeDcyJ6RRzPP5mMSr/hksYl0pSjj/6TUecE5fHPVVeN7txVqkpOBf9i45Y+iBUQMjBb1NnDK3pHXxpnAs1Q/pe7vReErj4GF1U="
|
||||
# iOS code signing
|
||||
- secure: "I6Iu75X1E+js5tzijtKi1EGtIuBcA4/25nDYe0svV4HAtujY71ZJZ4eB6355CKhFXpLXrF3i7eKVX3v+zWS0QROPEWacgsqsvNg+Ba9cnznW/faUSOYekCfhzWd/6reYDM7KzKAQwSUHLk9JIWK/kkmi4r+vVJK7h+tjPllK5YA="
|
||||
- IOS_APP_NAME="Mapbox GL"
|
||||
- 'IOS_DEVELOPER_NAME="iPhone Distribution: Mapbox, Inc."'
|
||||
- IOS_PROFILE_NAME="ios-in-house"
|
||||
- secure: "nQqSM8rd7OHtV4MqmNqVnkrVHqxKqQsaWRYk4/nPdhbeVWtTtkk0df711LrF1TUtbEPEewHxYUvTZ/UXmwJNeoKdzTHavI8hnatRkgjyxGERPn1il1Otelht9I+LQQHf+plrpRjVWBrNIW0Zox1B3cqn6d3NglpbXrEQ2EjYGNA="
|
||||
- KIF_SCREENSHOTS="${TRAVIS_BUILD_DIR}/screenshots"
|
||||
|
||||
before_install:
|
||||
- source ./scripts/travis_helper.sh
|
||||
|
||||
install:
|
||||
- ./scripts/${FLAVOR}/install.sh
|
||||
|
||||
script:
|
||||
- ./scripts/${FLAVOR}/run.sh
|
||||
|
||||
after_failure:
|
||||
- "[ -f ./scripts/${FLAVOR}/after_failure.sh ] && ./scripts/${FLAVOR}/after_failure.sh"
|
||||
|
||||
after_script:
|
||||
- "[ -f ./scripts/${FLAVOR}/after_script.sh ] && ./scripts/${FLAVOR}/after_script.sh"
|
||||
|
||||
notifications:
|
||||
slack:
|
||||
secure: HHQYr7sF8M1SzoWSqgKVYtwAgGdLLCyTMsQjFhEEQNYO92ZwURE5s03qWTGH5k8+4Yqn26yrXt3NztLC4JIOpcGervN2mSZyq4dZgFTcWEd61igw0qwSenlwvFfbE1ASK/KYCzfyn9MIfHN+ovwLoRxXZkPwinKDvl3DXjBaFNg=
|
||||
|
||||
git:
|
||||
submodules: false
|
||||
162
.ycm_extra_conf.py
Normal file
@@ -0,0 +1,162 @@
|
||||
# Version of .ycm_extra_conf.py sample file adapted
|
||||
# for the Mapbox GL Native project.
|
||||
#
|
||||
# This file is NOT licensed under the GPLv3, which is the license for the rest
|
||||
# of YouCompleteMe.
|
||||
#
|
||||
# Here's the license text for this file:
|
||||
#
|
||||
# This is free and unencumbered software released into the public domain.
|
||||
#
|
||||
# Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
# distribute this software, either in source code form or as a compiled
|
||||
# binary, for any purpose, commercial or non-commercial, and by any
|
||||
# means.
|
||||
#
|
||||
# In jurisdictions that recognize copyright laws, the author or authors
|
||||
# of this software dedicate any and all copyright interest in the
|
||||
# software to the public domain. We make this dedication for the benefit
|
||||
# of the public at large and to the detriment of our heirs and
|
||||
# successors. We intend this dedication to be an overt act of
|
||||
# relinquishment in perpetuity of all present and future rights to this
|
||||
# software under copyright law.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
# OTHER DEALINGS IN THE SOFTWARE.
|
||||
#
|
||||
# For more information, please refer to <http://unlicense.org/>
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import ycm_core
|
||||
|
||||
|
||||
def DirectoryOfThisScript():
|
||||
return os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
default_flags = [
|
||||
'-std=c++14',
|
||||
'-I%s' % (os.path.join(DirectoryOfThisScript(), 'src')),
|
||||
'-I%s' % (os.path.join(DirectoryOfThisScript(), 'include')),
|
||||
]
|
||||
|
||||
|
||||
def MakeRelativePathsInFlagsAbsolute(flags, working_directory):
|
||||
if not working_directory:
|
||||
return list(flags)
|
||||
|
||||
new_flags = []
|
||||
make_next_absolute = False
|
||||
path_flags = ['-isystem', '-I', '-iquote', '--sysroot=']
|
||||
|
||||
for flag in flags:
|
||||
new_flag = flag
|
||||
|
||||
if make_next_absolute:
|
||||
make_next_absolute = False
|
||||
if not flag.startswith('/'):
|
||||
new_flag = os.path.join(working_directory, flag)
|
||||
|
||||
for path_flag in path_flags:
|
||||
if flag == path_flag:
|
||||
make_next_absolute = True
|
||||
break
|
||||
|
||||
if flag.startswith(path_flag):
|
||||
path = flag[len(path_flag):]
|
||||
new_flag = path_flag + os.path.join(working_directory, path)
|
||||
break
|
||||
|
||||
if new_flag:
|
||||
new_flags.append(new_flag)
|
||||
|
||||
return new_flags
|
||||
|
||||
|
||||
def FlagsForFileDefault():
|
||||
return {
|
||||
'flags': default_flags,
|
||||
'do_cache': False,
|
||||
}
|
||||
|
||||
|
||||
def FlagsForFileLinux(filename):
|
||||
working_directory = os.path.join('build', 'linux')
|
||||
|
||||
if not os.path.exists(os.path.join(DirectoryOfThisScript(), working_directory)):
|
||||
return FlagsForFileDefault()
|
||||
|
||||
relative_source_path = filename.replace(DirectoryOfThisScript() + '/', '')
|
||||
relative_obj_path = os.path.splitext(relative_source_path)[0] + '.o'
|
||||
|
||||
make_cmd = 'make -pn |grep %s: |grep GYP_CXXFLAGS |cut -d\' \' -f4-' % relative_obj_path
|
||||
|
||||
p = subprocess.Popen([make_cmd], shell=True, stdout=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
|
||||
if p.returncode:
|
||||
return FlagsForFileDefault()
|
||||
|
||||
flags = stdout.split(' ')
|
||||
flags_relative = MakeRelativePathsInFlagsAbsolute(flags, os.path.join(DirectoryOfThisScript(), working_directory))
|
||||
flags_final = [flag for flag in flags_relative if flag.startswith("-")]
|
||||
|
||||
return {
|
||||
'flags': flags_final,
|
||||
'do_cache': True,
|
||||
}
|
||||
|
||||
|
||||
def FlagsForFileDarwin(filename):
|
||||
working_directory = os.path.join('build', 'osx')
|
||||
|
||||
if not os.path.exists(os.path.join(DirectoryOfThisScript(), working_directory)):
|
||||
return FlagsForFileDefault()
|
||||
|
||||
relative_source_path = filename.replace(DirectoryOfThisScript() + '/', '')
|
||||
relative_obj_path = os.path.splitext(relative_source_path)[0] + '.o'
|
||||
|
||||
make_cmd = 'make -pn |grep "%s :=" |grep "NDEBUG" |tail -n 1 | cut -d\' \' -f4-' % relative_obj_path
|
||||
|
||||
p = subprocess.Popen([make_cmd], shell=True, stdout=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
|
||||
if p.returncode:
|
||||
return FlagsForFileDefault()
|
||||
|
||||
flags = stdout.split(' ')
|
||||
flags_relative = MakeRelativePathsInFlagsAbsolute(flags, os.path.join(DirectoryOfThisScript(), working_directory))
|
||||
flags_final = [flag for flag in flags_relative if flag.startswith("-")]
|
||||
|
||||
# Append OSX sysroot SDK path
|
||||
xcrun_cmd = 'xcrun --show-sdk-path'
|
||||
|
||||
p = subprocess.Popen([xcrun_cmd], shell=True, stdout=subprocess.PIPE)
|
||||
stdout, stderr = p.communicate()
|
||||
|
||||
if p.returncode:
|
||||
return FlagsForFileDefault()
|
||||
|
||||
flags_final.append('-isysroot ' + stdout)
|
||||
|
||||
return {
|
||||
'flags': flags_final,
|
||||
'do_cache': True,
|
||||
}
|
||||
|
||||
|
||||
def FlagsForFile(filename, **kwargs):
|
||||
if sys.platform.startswith('linux'):
|
||||
return FlagsForFileLinux(filename)
|
||||
|
||||
if sys.platform.startswith('darwin'):
|
||||
return FlagsForFileDarwin(filename)
|
||||
|
||||
return FlagsForFileDefault()
|
||||
72
CHANGELOG.md
Normal file
@@ -0,0 +1,72 @@
|
||||
# Changelog
|
||||
|
||||
## 0.5.1
|
||||
|
||||
### iOS
|
||||
|
||||
- Added support for CocoaPods 0.38.0. ([#1876](https://github.com/mapbox/mapbox-gl-native/pull/1876))
|
||||
|
||||
## 0.5.0
|
||||
|
||||
### Core
|
||||
|
||||
- Support for runtime marker imagery. ([#941](https://github.com/mapbox/mapbox-gl-native/pull/941))
|
||||
- Added `Map::fitBounds()` for region-based viewport setting. ([#1092](https://github.com/mapbox/mapbox-gl-native/issues/1092))
|
||||
- Added a raster satellite bundled style and improved raster rendering. ([#963](https://github.com/mapbox/mapbox-gl-native/issues/963))
|
||||
- Improved round line joins for semi-transparent lines. ([#1839](https://github.com/mapbox/mapbox-gl-native/pull/1839))
|
||||
- Improved map render lifecycle notifications. ([#1026](https://github.com/mapbox/mapbox-gl-native/issues/1026))
|
||||
- Fixed a bug that caused annotations not to show at zoom level zero. ([#1279](https://github.com/mapbox/mapbox-gl-native/issues/1279))
|
||||
- Fixed a bug with the ordering of shape layers. ([#1866](https://github.com/mapbox/mapbox-gl-native/pull/1866))
|
||||
- Other bug fixes and performance improvements.
|
||||
|
||||
### iOS
|
||||
|
||||
- **Breaking:** Headers now make use of lightweight generics, eliminating many unnecessary casts when working with annotations in Swift 2.0 in Xcode 7. ([#1711](https://github.com/mapbox/mapbox-gl-native/pull/1711))
|
||||
- **Breaking:** `-mapView:symbolNameForAnnotation:` has been removed from the `MGLMapViewDelegate` protocol. Implement `-mapView:imageForAnnotation:` instead, which accepts images at runtime. ([#941](https://github.com/mapbox/mapbox-gl-native/pull/941))
|
||||
- **Breaking:** `MGLMapView.direction` is now expressed in terms of degrees clockwise from true north, as indicated in the documentation, rather than counterclockwise. ([#1789](https://github.com/mapbox/mapbox-gl-native/pull/1789))
|
||||
- A Satellite style showing Mapbox Satellite imagery is now bundled with Mapbox GL. ([#1845](https://github.com/mapbox/mapbox-gl-native/pull/1845))
|
||||
- Improved `UIView` tracking to the map. ([#1813](https://github.com/mapbox/mapbox-gl-native/pull/1813))
|
||||
- Delegate method `-[MGLMapViewDelegate mapView:didFailToLocateUserWithError:]` now works. ([#1608](https://github.com/mapbox/mapbox-gl-native/pull/1608))
|
||||
- It is now possible to fit the map’s viewport to a coordinate bounding box via `-[MGLMapView setVisibleCoordinateBounds:animated:]` or to a specific set of coordinates via `-[MGLMapView setVisibleCoordinates:count:edgePadding:animated:]`. ([#1783](https://github.com/mapbox/mapbox-gl-native/pull/1783), [#1795](https://github.com/mapbox/mapbox-gl-native/pull/1795))
|
||||
- The logo and ℹ️ no longer disappear or get distorted after embedding MGLMapView in a different view, and you can now access these subviews directly via properties on MGLMapView. ([#1779](https://github.com/mapbox/mapbox-gl-native/pull/1779), [#1815](https://github.com/mapbox/mapbox-gl-native/pull/1815))
|
||||
- Raster tiles now look sharper midway between two zoom levels. ([#1843](https://github.com/mapbox/mapbox-gl-native/pull/1843))
|
||||
- Resetting the map rotation to north no longer also resets the user location tracking mode. ([#1809](https://github.com/mapbox/mapbox-gl-native/pull/1809))
|
||||
- `-[MGLMapView convertPoint:toCoordinateFromView:]` now returns accurate coordinates on iPhone 6. ([#1827](https://github.com/mapbox/mapbox-gl-native/pull/1827))
|
||||
- Fixed an issue in which `-[MGLMapView direction]` would sometimes return 360 instead of 0. ([#1829](https://github.com/mapbox/mapbox-gl-native/pull/1829))
|
||||
- Build against iOS 8.4. ([#1868](https://github.com/mapbox/mapbox-gl-native/pull/1868))
|
||||
|
||||
## 0.4.0
|
||||
|
||||
### Core
|
||||
|
||||
- Support for polyline and polygon shape annotations. ([#1655](https://github.com/mapbox/mapbox-gl-native/issues/1655))
|
||||
- Improved placement and density of labels. ([#1666](https://github.com/mapbox/mapbox-gl-native/issues/1666), [blog](https://www.mapbox.com/blog/better-label-placement-mapbox-mobile/))
|
||||
- Improved z-ordering appearance of point markers. ([#988](https://github.com/mapbox/mapbox-gl-native/issues/988))
|
||||
- Fixed an issue in which certain features, such as roundabouts, were not rendered completely. ([#1725](https://github.com/mapbox/mapbox-gl-native/issues/1725))
|
||||
- Many bug fixes and performance and stability improvements.
|
||||
- Improved tests.
|
||||
|
||||
### iOS
|
||||
|
||||
- **Breaking:** `MGLMapView` no longer manages Mapbox access tokens directly; an access token cannot be passed in when initializing the map view. Instead, set `MGLMapboxAccessToken` to your access token in your app’s `Info.plist` file, or call `+[MGLAccountManager setAccessToken:]` before initializing the map view. If you were setting the access token inside an Interface Builder inspectable, also remove it from the User Defined Runtime Attributes section of the Identity inspector. ([#1553](https://github.com/mapbox/mapbox-gl-native/issues/1553))
|
||||
- **Breaking:** `MGLAccountManager`'s `-setMapboxMetricsEnabledSettingShownInApp:` has been removed. If you implement a Mapbox Metrics switch inside your app, instead of inside a Settings bundle, set `MGLMapboxMetricsEnabledSettingShownInApp` to `YES` in the `Info.plist` file. ([#1553](https://github.com/mapbox/mapbox-gl-native/issues/1553))
|
||||
- **Breaking:** `MGLMapView`'s `-mapID` has been renamed to `-styleID`. ([#1561](https://github.com/mapbox/mapbox-gl-native/issues/1561))
|
||||
- Headers have been audited for nullability, improving type safety in both Objective-C and Swift 1.2 when compiling with Xcode 6.3 or above. ([#1578](https://github.com/mapbox/mapbox-gl-native/issues/1578))
|
||||
- Fixed an issue in which the map would sometimes spin 180° while rotating the map with two fingers. ([#1453](https://github.com/mapbox/mapbox-gl-native/issues/1453))
|
||||
- Added a shortcut to the Mapbox Metrics switch in `MGLMapView`'s action sheet that is attached to the ℹ️ button. ([#1611](https://github.com/mapbox/mapbox-gl-native/issues/1611))
|
||||
- `MGLMapView` now supports Interface Builder designables. When you add an `MGLMapView` to a storyboard, it displays instructions for getting set up directly on the storyboard canvas. ([#1573](https://github.com/mapbox/mapbox-gl-native/issues/1573))
|
||||
- The default title for the user location annotation is now “You Are Here”. You can customize the title by setting `mapView.userAnnotation.title`. ([#1559](https://github.com/mapbox/mapbox-gl-native/issues/1559))
|
||||
- Internal use of the Reachability library has been cleaned up so that your app can include its own copy of Reachability. ([#1718](https://github.com/mapbox/mapbox-gl-native/issues/1718))
|
||||
- Now distribute a binary stripped of debugging symbols by default with an optional, secondary symbols build. ([#1650](https://github.com/mapbox/mapbox-gl-native/issues/1650))
|
||||
|
||||
## 0.3.1
|
||||
|
||||
- Temporarily removed `IBDesignable` support on iOS.
|
||||
|
||||
## 0.3.0
|
||||
|
||||
- Initial iOS beta release.
|
||||
|
||||
Known issues:
|
||||
|
||||
- None.
|
||||
11
CONTRIBUTING.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Contributing
|
||||
|
||||
If you have a usage question for a product built on Mapbox GL (such as Mapbox Mobile toolkits like our SDKs), please visit https://www.mapbox.com/help/.
|
||||
|
||||
If you want to contribute code:
|
||||
|
||||
1. Please familiarize yourself with the [install process](INSTALL.md).
|
||||
|
||||
1. Ensure that the [existing issues](https://github.com/mapbox/mapbox-gl-native/issues?utf8=✓&q=) don't already cover your question or contribution.
|
||||
|
||||
1. Pull requests gladly accepted.
|
||||
347
INSTALL.md
Normal file
@@ -0,0 +1,347 @@
|
||||
# Install
|
||||
|
||||
This document describes the process for setting up Mapbox GL for development _on the framework itself_.
|
||||
|
||||
# Depends
|
||||
|
||||
- Modern C++ compiler that supports `-std=c++14` (clang++ 3.5 or later or g++-4.9 or later)
|
||||
- [Boost headers](http://boost.org/)
|
||||
- [`zlib`](http://www.zlib.net/)
|
||||
- [`libpng`](http://www.libpng.org/pub/png/libpng.html)
|
||||
- [`libuv 0.10+`](https://github.com/joyent/libuv)
|
||||
- [`glfw 3.1+`](http://www.glfw.org/)
|
||||
- [`libcurl`](http://curl.haxx.se/libcurl/) (depends on OpenSSL; Linux only)
|
||||
- Apple Command Line Tools (for build on OS X; available at [Apple Developer](https://developer.apple.com/downloads))
|
||||
- `pkg-config` (for build only)
|
||||
- [Homebrew](http://brew.sh) (for building on OS X)
|
||||
- [xcpretty](https://github.com/supermarin/xcpretty) (for building on OS X)
|
||||
- [Cask](http://caskroom.io/) (for building Android on OS X)
|
||||
- Python 2.x (for build only)
|
||||
|
||||
# Build instructions
|
||||
|
||||
We try to link to as many system-provided libraries as possible. When these are unavailable or too outdated, we run a thin build-script layer called [Mason](https://github.com/mapbox/mason) to automate builds, and load precompiled binary packages when possible.
|
||||
|
||||
Be sure to pull down all submodules first:
|
||||
|
||||
git submodule init
|
||||
git submodule update
|
||||
|
||||
## OS X
|
||||
|
||||
This process gives you either a native OS X windowed app or a Linux desktop app with a map view for development purposes, built on an OS X host system.
|
||||
|
||||
### Build
|
||||
|
||||
ImageMagick is required for tests. It's recommended to install it with [Homebrew](http://brew.sh/) via `brew install imagemagick`.
|
||||
|
||||
To create projects, you can run:
|
||||
|
||||
- `make xproj`: Creates an Xcode project with OS X-specific handlers for HTTP downloads and settings storage. It uses [GLFW](http://www.glfw.org) for window handling.
|
||||
- `make lproj`: Creates an Xcode project with platform-independent handlers for downloads and settings storage. This is what is also being built on Linux.
|
||||
- `make osx run-osx`: Builds and runs the OS X application on the command line with `xcodebuild`.
|
||||
- `make linux run-linux`: Builds and runs the Linux application with `make`.
|
||||
|
||||
Note that you can't have more than one project in Xcode open at a time since the static library project is shared across the OS X, Linux and iOS project.
|
||||
|
||||
### Test
|
||||
|
||||
- `make test-*` Builds and runs all tests. You can specify individual tests by replacing * with their name.
|
||||
|
||||
### Usage
|
||||
|
||||
- Press `S` to cycle through bundled styles
|
||||
- Press `X` to reset the transform
|
||||
- Press `N` to reset north
|
||||
- Press `Tab` to toggle debug information
|
||||
- Press `C` to toggle symbol collision debug boxes
|
||||
- Press `Esc` to quit
|
||||
- Press `1` through `6` to add increasing numbers of point annotations for testing
|
||||
|
||||
### Target
|
||||
|
||||
OS X 10.9+
|
||||
|
||||
|
||||
## iOS (Test App)
|
||||
|
||||
This process gives you a native iOS app for simulator or device which compiles the source to GL within it for fastest turnaround time during development. Normal, production use of the library is via a precompiled binary linked into the app target.
|
||||
|
||||
Developing for iOS implies an OS X host system.
|
||||
|
||||
### Build
|
||||
|
||||
If you want to build from source and/or contribute to development of the project, run `make iproj`, which will create and open an Xcode project which can build the entire library from source as well as an Objective-C test app. If you don't have an Apple Developer account, change the destination from "My Mac" to a simulator such as "iPhone 6" before you run and build the app.
|
||||
|
||||
### Test
|
||||
|
||||
You can run `make itest` to run the included integration tests. Requires `gem install xcpretty`. If you want to run the tests in Xcode instead, first `make ipackage` to create a local static library version, then open `test/ios/ios-tests.xcodeproj`, and lastly `Command + U` on the `Mapbox GL Tests` application target.
|
||||
|
||||
### Usage
|
||||
|
||||
- Pan to move
|
||||
- Pinch to zoom
|
||||
- Use two fingers to rotate
|
||||
- Double-tap to zoom in one level
|
||||
- Two-finger single-tap to zoom out one level
|
||||
- Double-tap, long-pressing the second, then pan up and down to "quick zoom" (iPhone only, meant for one-handed use)
|
||||
- Use the debug menu to add test annotations, reset position, and toggle debug info.
|
||||
|
||||
## iOS (Your App)
|
||||
|
||||
**If you want a production version of this project, use [Mapbox Mobile](http://mapbox.com/mobile).**
|
||||
|
||||
This section is for people contributing to Mapbox GL directly in the context of their own app.
|
||||
|
||||
### Build
|
||||
|
||||
1. Install [appledoc](http://appledoc.gentlebytes.com/appledoc/) 2.2v963 for API docs generation (only this exact version works right now ([#2117](https://github.com/mapbox/mapbox-gl-native/issues/2117)).
|
||||
|
||||
```
|
||||
curl -L -o appledoc.zip https://github.com/tomaz/appledoc/releases/download/v2.2-963/appledoc.zip
|
||||
unzip appledoc.zip
|
||||
cp appledoc /usr/local/bin
|
||||
cp -Rf Templates/ ~/.appledoc
|
||||
```
|
||||
|
||||
1. Run `make ipackage`. The packaging script will produce the statically-linked `libMapbox.a`, `Mapbox.bundle` for resources, a `Headers` folder, and a `Docs` folder with HTML API documentation.
|
||||
|
||||
### Test
|
||||
|
||||
In the context of your own app, you can now either:
|
||||
|
||||
#### CocoaPods
|
||||
|
||||
Currently, until [#1437](https://github.com/mapbox/mapbox-gl-native/issues/1437) is completed, to install a _development version_ of Mapbox GL using CocoaPods you will need to build it from source manually per above.
|
||||
|
||||
1. Zip up the build product.
|
||||
|
||||
cd build/ios/pkg/static
|
||||
ZIP=mapbox-ios-sdk.zip
|
||||
rm -f ../${ZIP}
|
||||
zip -r ../${ZIP} *
|
||||
|
||||
1. Modify a custom `Mapbox-iOS-SDK.podspec` to download this zip file.
|
||||
|
||||
{...}
|
||||
|
||||
m.source = {
|
||||
:http => "http://{...}/mapbox-ios-sdk.zip",
|
||||
:flatten => true
|
||||
}
|
||||
|
||||
{...}
|
||||
|
||||
1. Update your app's `Podfile` to point to the `Mapbox-iOS-SDK.podspec`.
|
||||
|
||||
pod 'Mapbox-iOS-SDK', :podspec => 'http://{...}/Mapbox-iOS-SDK.podspec'
|
||||
|
||||
1. Run `pod update` to grab the newly-built library.
|
||||
|
||||
#### Binary
|
||||
|
||||
1. Built from source manually per above.
|
||||
|
||||
1. Copy the contents of `build/ios/pkg/static` into your project. It should happen automatically, but ensure that:
|
||||
|
||||
- `Headers` is in your *Header Search Paths* (`HEADER_SEARCH_PATHS`) build setting.
|
||||
- `Mapbox.bundle` is in your target's *Copy Bundle Resources* build phase.
|
||||
- `libMapbox.a` is in your target's *Link Binary With Libraries* build phase.
|
||||
|
||||
1. Add the following Cocoa framework dependencies to your target's *Link Binary With Libraries* build phase:
|
||||
|
||||
- `CoreTelephony.framework`
|
||||
- `GLKit.framework`
|
||||
- `ImageIO.framework`
|
||||
- `MobileCoreServices.framework`
|
||||
- `QuartzCore.framework`
|
||||
- `SystemConfiguration.framework`
|
||||
- `libc++.dylib`
|
||||
- `libsqlite3.dylib`
|
||||
- `libz.dylib`
|
||||
|
||||
1. Add `-ObjC` to your target's "Other Linker Flags" build setting (`OTHER_LDFLAGS`).
|
||||
|
||||
### Target
|
||||
|
||||
Devices: iPhone 4S and above (5, 5c, 5s, 6, 6 Plus), iPad 2 and above (3, 4, Mini, Air, Mini 2, Air 2), iPod touch 5th gen and above
|
||||
|
||||
iOS: 7.0+
|
||||
|
||||
|
||||
## Linux
|
||||
|
||||
We are using Ubuntu for development. While the software should work on other distributions as well, we are not providing explicit build instructions here.
|
||||
|
||||
This process gives you a Linux desktop app built on a Linux host system.
|
||||
|
||||
### Build
|
||||
|
||||
Install GCC 4.9+ if you are running Ubuntu 14.04 or older. Alternatively, you can also use [Clang 3.5+](http://llvm.org/apt/).
|
||||
|
||||
sudo add-apt-repository --yes ppa:ubuntu-toolchain-r/test
|
||||
sudo apt-get update
|
||||
sudo apt-get install gcc-4.9 g++-4.9
|
||||
export CXX=g++-4.9
|
||||
|
||||
Ensure you have git and other build essentials:
|
||||
|
||||
sudo apt-get install curl git build-essential zlib1g-dev automake \
|
||||
libtool xutils-dev make cmake pkg-config python-pip \
|
||||
libcurl4-openssl-dev libpng-dev libsqlite3-dev \
|
||||
libllvm3.4
|
||||
|
||||
Install glfw3 dependencies:
|
||||
|
||||
sudo apt-get install libxi-dev libglu1-mesa-dev x11proto-randr-dev \
|
||||
x11proto-xext-dev libxrandr-dev \
|
||||
x11proto-xf86vidmode-dev libxxf86vm-dev \
|
||||
libxcursor-dev libxinerama-dev
|
||||
|
||||
Then, you can then proceed to build the library:
|
||||
|
||||
git submodule update --init
|
||||
make linux
|
||||
|
||||
Set an access token as described below, and then run:
|
||||
|
||||
make run-linux
|
||||
|
||||
### Test
|
||||
|
||||
- `make test-*` Builds and runs all tests. You can specify individual tests by replacing * with their name.
|
||||
|
||||
### Usage
|
||||
|
||||
- Press `S` to cycle through bundled styles
|
||||
- Press `X` to reset the transform
|
||||
- Press `N` to reset north
|
||||
- Press `Tab` to toggle debug information
|
||||
- Press `C` to toggle symbol collision debug boxes
|
||||
- Press `Esc` to quit
|
||||
- Press `1` through `6` to add increasing numbers of point annotations for testing
|
||||
|
||||
### Target
|
||||
|
||||
Ubuntu
|
||||
|
||||
|
||||
## Android
|
||||
|
||||
### Build (Linux Host)
|
||||
|
||||
Install a few build dependencies:
|
||||
|
||||
apt-get install -y make git build-essential automake \
|
||||
libtool make cmake pkg-config lib32stdc++6 lib32z1
|
||||
|
||||
Install Oracle JDK 7 (requires license agreement) from http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html
|
||||
|
||||
export JAVA_HOME="/dir/to/jdk1.7.0_71"
|
||||
|
||||
Install the [Android NDK Revision 10e](https://developer.android.com/tools/sdk/ndk/index.html).
|
||||
|
||||
export ANDROID_NDK_PATH="/dir/to/android-ndk-r10e"
|
||||
|
||||
Install the Android SDK. We recommend doing this by way of [Android Studio](https://developer.android.com/sdk/installing/studio.html).
|
||||
|
||||
export ANDROID_HOME="/dir/to/android-sdk-linux"
|
||||
|
||||
Run:
|
||||
|
||||
make android
|
||||
|
||||
You can then open `android/java` in Android Studio via "Import Non-Android Studio Project".
|
||||
|
||||
### Build (OS X Host)
|
||||
|
||||
Install Oracle JDK 7+:
|
||||
|
||||
brew cask install java
|
||||
|
||||
Install the [Android NDK Revision 10e](https://developer.android.com/tools/sdk/ndk/index.html) for 64-bit OS X:
|
||||
|
||||
brew install android-ndk
|
||||
|
||||
This will also install the dependency `android-sdk`.
|
||||
|
||||
Install [Android Studio](https://developer.android.com/sdk/installing/studio.html):
|
||||
|
||||
brew cask install android-studio
|
||||
android
|
||||
|
||||
By default, the SDK will be installed to `/usr/local/opt/android-sdk`. If you open Android Studio at this point, you may get an error message telling you that it can't find a JVM, it's because you installed a custom Java VM from Oracle. Follow [these instructions](http://tools.android.com/recent/androidstudio1rc3_releasecandidate3released) to start Android Studio. You'll wind up setting these environment variables in your .bash_profile or similar:
|
||||
|
||||
echo "export ANDROID_HOME=`brew --prefix android-sdk`" >> .bash_profile
|
||||
echo "export ANDROID_NDK_PATH=`brew --cellar android-ndk`/r10e" >> .bash_profile
|
||||
# Replace <path to JDK> with something like /Library/Java/JavaVirtualMachines/jdk1.8.0_31.jdk
|
||||
echo "export JAVA_HOME=<path to JDK>" >> .bash_profile
|
||||
echo "export STUDIO_JDK=$JAVA_HOME" >> .bash_profile
|
||||
|
||||
Run:
|
||||
|
||||
make android
|
||||
open -a Android\ Studio
|
||||
|
||||
You can then open `android/java` in Android Studio via "Import Non-Android Studio Project".
|
||||
|
||||
### Setting up Android emulator
|
||||
|
||||
If you want to run the test app in the emulator, we recommend the x86 build because it will run a lot faster.
|
||||
|
||||
First ensure you have an `MAPBOX_ACCESS_TOKEN` environment variable set, as described below. Then, create an x86 build:
|
||||
|
||||
ANDROID_ABI=x86 make android
|
||||
|
||||
In Android Studio, create an x86 AVD (Android Virtual Device):
|
||||
|
||||
- Open AVD Manager via the Tools menu -> Android -> AVD Manager
|
||||
- Click "Create Virtual Device" at the bottom on AVD Manager window
|
||||
- Select one of the device profiles, for example the Nexus 4
|
||||
- Click "Next"
|
||||
- Select a Lollipop or Kitkat release with ABI of x86. If the line is greyed out click Download to download the OS files.
|
||||
- Click "Next"
|
||||
- Under "Emulated Performance" check "Host GPU" and uncheck "Store a snapshot for faster startup"
|
||||
- Click "Finish"
|
||||
- Close the AVD Manager
|
||||
|
||||
Now when you run or debug the Android project you will see a window "Choose Device". Select your new AVD from drop down under "Launch emulator". If you select "Use same device for future launches" Android Studio will remember the selection and not ask again.
|
||||
|
||||
### Running on a hardware device
|
||||
|
||||
First read the [Google documentation](http://developer.android.com/tools/device.html) to set up your device and your OS to connect to the device.
|
||||
|
||||
When you plug your device in and then run or debug the Android project you will see a window "Choose Device". Choose your device from the "Choose a running device" list.
|
||||
|
||||
If your device does not show up, you have not set it up properly. Double check the [Google documentation](http://developer.android.com/tools/device.html).
|
||||
|
||||
### Target
|
||||
|
||||
Devices running Android 4.0+ (API level 14+).
|
||||
|
||||
|
||||
# Troubleshooting
|
||||
|
||||
To trigger a complete rebuild, run `make clean` and then start over generating the Xcode projects or `Makefile` as described above.
|
||||
|
||||
If you are having trouble getting the dependencies right, you can blow away the `mason_packages` directory, or run `make distclean`. This means the `Makefile` and configure script will automatically install the dependencies again on the next try.
|
||||
|
||||
On OS X, you can also try clearing the Xcode cache with `make clear_xcode_cache`.
|
||||
|
||||
# Mapbox API access tokens
|
||||
|
||||
The demo applications use Mapbox vector tiles, which **require a Mapbox account and API access token**. Obtain an access token on the [Mapbox account page](https://www.mapbox.com/account/apps/).
|
||||
|
||||
For iOS and OS X use of the demo apps in Xcode, setup the access token by editing the scheme for the application target, then adding an environment variable with the name `MAPBOX_ACCESS_TOKEN`.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
For Linux, set the environment variable `MAPBOX_ACCESS_TOKEN` to your token.
|
||||
|
||||
For Android, gradle will take the value of `MAPBOX_ACCESS_TOKEN` and save it to `android/java/MapboxGLAndroidSDKTestApp/src/main/res/raw/token.txt` where the app will read it from.
|
||||
|
||||
# Style
|
||||
|
||||
Default styles in the JSON-based [styling format](https://github.com/mapbox/mapbox-gl-style-spec) are included at `./styles` as a submodule. See the [styles project](https://github.com/mapbox/mapbox-gl-styles) to report problems or to contribute to these styles.
|
||||
65
LICENSE.md
Normal file
@@ -0,0 +1,65 @@
|
||||
mapbox-gl-native copyright (c) 2014, Mapbox.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the
|
||||
distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
|
||||
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
===========================================================================
|
||||
|
||||
Mapbox GL uses portions of the Mapbox iOS SDK, which was derived from the
|
||||
Route-Me open source project, including the Alpstein fork of it.
|
||||
|
||||
The Route-Me license appears below.
|
||||
|
||||
Copyright (c) 2008-2013, Route-Me Contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
===========================================================================
|
||||
|
||||
Mapbox GL uses portions of SVPulsingAnnotationView.
|
||||
|
||||
Copyright (c) 2013, Sam Vermette <hello@samvermette.com>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
134
Makefile
Normal file
@@ -0,0 +1,134 @@
|
||||
export BUILDTYPE ?= Release
|
||||
export BUILD_TEST ?= 1
|
||||
export BUILD_RENDER ?= 1
|
||||
|
||||
# Determine build platform
|
||||
ifeq ($(shell uname -s), Darwin)
|
||||
export BUILD = osx
|
||||
export JOBS ?= $(shell sysctl -n hw.ncpu)
|
||||
export XCPRETTY := $(shell ./scripts/xcpretty.sh)
|
||||
else ifeq ($(shell uname -s), Linux)
|
||||
export BUILD = linux
|
||||
export JOBS ?= $(shell grep --count processor /proc/cpuinfo)
|
||||
else
|
||||
$(error Cannot determine build platform)
|
||||
endif
|
||||
export BUILD_VERSION = $(shell uname -m)
|
||||
|
||||
RUN = +@$(MAKE) -f scripts/main.mk
|
||||
|
||||
default: ; @printf "You must specify a valid target\n"
|
||||
|
||||
#### OS X targets ##############################################################
|
||||
|
||||
ifeq ($(BUILD),osx)
|
||||
.PHONY: osx xosx run-osx run-xosx
|
||||
osx: ; $(RUN) HOST=osx HOST_VERSION=x86_64 Makefile/osxapp
|
||||
xosx: ; $(RUN) HOST=osx HOST_VERSION=x86_64 Xcode/osxapp
|
||||
run-osx: osx ; @"build/osx-x86_64/$(BUILDTYPE)/Mapbox GL.app/Contents/MacOS/Mapbox GL"
|
||||
run-xosx: xosx ; @"gyp/build/$(BUILDTYPE)/Mapbox GL.app/Contents/MacOS/Mapbox GL"
|
||||
|
||||
.PHONY: Xcode/osx Xcode/ios
|
||||
Xcode/ios: ; $(RUN) HOST=ios Xcode/__project__
|
||||
Xcode/osx: ; $(RUN) HOST=osx HOST_VERSION=x86_64 Xcode/__project__
|
||||
|
||||
.PHONY: xproj iproj
|
||||
xproj: Xcode/osx ; @open ./build/osx-x86_64/gyp/osx.xcodeproj
|
||||
iproj: Xcode/ios ; @open ./build/ios-all/gyp/ios.xcodeproj
|
||||
|
||||
.PHONY: ios ibench isim
|
||||
ios ibench isim: export XCODEBUILD_ARGS += PROVISIONING_PROFILE="$$(PROVISIONING_PROFILE)"
|
||||
|
||||
ios: export XCODEBUILD_ARGS += -sdk iphoneos ARCHS="arm64 armv7 armv7s"
|
||||
ios: ; $(RUN) HOST=ios Xcode/iosapp
|
||||
|
||||
isim: export XCODEBUILD_ARGS += -sdk iphonesimulator ARCHS="x86_64 i386"
|
||||
isim: ; $(RUN) HOST=ios Xcode/iosapp
|
||||
|
||||
ibench: export XCODEBUILD_ARGS += -sdk iphoneos ARCHS="arm64"
|
||||
ibench: ; $(RUN) HOST=ios Xcode/ios-bench
|
||||
|
||||
.PHONY: ipackage ipackage-strip ipackage-sim itest
|
||||
ipackage: Xcode/ios ; @JOBS=$(JOBS) ./scripts/ios/package.sh
|
||||
ipackage-strip: Xcode/ios ; @JOBS=$(JOBS) ./scripts/ios/package.sh strip
|
||||
ipackage-sim: Xcode/ios ; @JOBS=$(JOBS) ./scripts/ios/package.sh sim
|
||||
itest: ipackage-sim ; ./scripts/ios/test.sh
|
||||
endif
|
||||
|
||||
#### All platforms targets #####################################################
|
||||
|
||||
.PHONY: linux run-linux run-valgrind-linux
|
||||
linux: ; $(RUN) Makefile/linuxapp
|
||||
run-linux: linux ; (cd build/linux-x86_64/$(BUILDTYPE) && ./mapbox-gl)
|
||||
run-valgrind-linux: linux
|
||||
(cd build/linux-x86_64/$(BUILDTYPE) && valgrind --leak-check=full --suppressions=../../../scripts/valgrind.sup ./mapbox-gl)
|
||||
|
||||
.PHONY: android android-lib
|
||||
# Builds a particular android architecture.
|
||||
android-lib-%: ; $(RUN) HOST=android HOST_VERSION=$* Makefile/androidapp
|
||||
|
||||
# Builds the default Android library
|
||||
android-lib: ; $(RUN) HOST=android Makefile/androidapp
|
||||
|
||||
# Builds the selected/default Android library
|
||||
android: android-lib
|
||||
cd android/java && ./gradlew --parallel --max-workers=$(JOBS) assemble$(BUILDTYPE)
|
||||
|
||||
# Builds all android architectures.
|
||||
android-all: android-lib-arm-v5 android-lib-arm-v7 android-lib-arm-v8
|
||||
android-all: android-lib-x86 android-lib-x86-64
|
||||
android-all: android-lib-mips android-lib-mips-64
|
||||
cd android/java && ./gradlew --parallel-threads=$(JOBS) assemble$(BUILDTYPE)
|
||||
|
||||
.PHONY: test
|
||||
test: ; $(RUN) Makefile/test
|
||||
test-%: ; $(RUN) test-$*
|
||||
ifeq ($(BUILD),osx)
|
||||
xtest: ; $(RUN) HOST=osx HOST_VERSION=x86_64 Xcode/test
|
||||
endif
|
||||
|
||||
.PHONY: render xrender
|
||||
render: ; $(RUN) Makefile/mbgl-render
|
||||
ifeq ($(BUILD),osx)
|
||||
xrender: ; $(RUN) HOST=osx HOST_VERSION=x86_64 Xcode/mbgl-render
|
||||
endif
|
||||
|
||||
|
||||
##### Maintenace operations ####################################################
|
||||
|
||||
.PHONY: clear_xcode_cache
|
||||
clear_xcode_cache:
|
||||
ifeq ($(BUILD), osx)
|
||||
@CUSTOM_DD=`defaults read com.apple.dt.Xcode IDECustomDerivedDataLocation 2>/dev/null`; \
|
||||
if [ $$CUSTOM_DD ]; then \
|
||||
echo clearing files in $$CUSTOM_DD older than one day; \
|
||||
find $$CUSTOM_DD/mapboxgl-app-* -mtime +1 | xargs rm -rf; \
|
||||
fi; \
|
||||
if [ -d ~/Library/Developer/Xcode/DerivedData/ ] && [ ! $$CUSTOM_DD ]; then \
|
||||
echo 'clearing files in ~/Library/Developer/Xcode/DerivedData/mapboxgl-app-* older than one day'; \
|
||||
find ~/Library/Developer/Xcode/DerivedData/mapboxgl-app-* -mtime +1 | xargs rm -rf; \
|
||||
fi
|
||||
endif
|
||||
|
||||
.PHONY: clear_sqlite_cache
|
||||
clear_sqlite_cache:
|
||||
ifeq ($(BUILD), osx)
|
||||
rm -f ~/Library/Application\ Support/Mapbox\ GL/cache.db
|
||||
else
|
||||
rm -f /tmp/mbgl-cache.db
|
||||
endif
|
||||
|
||||
clean: clear_sqlite_cache clear_xcode_cache
|
||||
-find ./deps/gyp -name "*.pyc" -exec rm {} \;
|
||||
-rm -rf ./build/
|
||||
-rm -rf ./macosx/build
|
||||
-rm -rf ./linux/build
|
||||
-rm -rf ./ios/build
|
||||
-rm -rf ./test/build
|
||||
-rm -rf ./config/*.gypi
|
||||
-rm -rf ./android/java/build ./android/java/MapboxGLAndroidSDKTestApp/build ./android/java/MapboxGLAndroidSDKTestApp/build
|
||||
-rm -rf ./android/java/MapboxGLAndroidSDK/src/main/jniLibs ./android/java/MapboxGLAndroidSDK/src/main/assets
|
||||
-rm -f ./android/test/features.zip
|
||||
|
||||
distclean: clean
|
||||
-rm -rf ./mason_packages
|
||||
18
README.md
Normal file
@@ -0,0 +1,18 @@
|
||||
# Mapbox GL (Native)
|
||||
|
||||
[](https://travis-ci.org/mapbox/mapbox-gl-native/builds)
|
||||
|
||||
An OpenGL ES-based renderer for [Mapbox Vector Tiles](https://www.mapbox.com/blog/vector-tiles), consisting of a C++ library for OS X and Linux and SDK bindings for iOS and Android.
|
||||
|
||||
**This repository is for development on Mapbox GL itself.**
|
||||
|
||||
If you want to use products _based on_ Mapbox GL, check out:
|
||||
|
||||
- [Mapbox Mobile](http://mapbox.com/mobile) — iOS and Android native development libraries for vector maps in apps
|
||||
- [`node-mapbox-gl-native`](https://github.com/mapbox/node-mapbox-gl-native) — Node.js library for vector map rendering
|
||||
- [`react-native-mapbox-gl`](https://github.com/mapbox/react-native-mapbox-gl`) — React Native library for vector maps in apps
|
||||
- [`qmapboxgl`](https://github.com/tmpsantos/qmapboxgl) — Qt library for vector map rendering
|
||||
|
||||
--
|
||||
|
||||
See [`INSTALL.md`](./INSTALL.md) for development setup and install instructions, including dependencies.
|
||||
13
android/LICENSE_GESTURES.md
Normal file
@@ -0,0 +1,13 @@
|
||||
Android Gesture Detectors Framework Licence
|
||||
===================================
|
||||
|
||||
Copyright (c) 2012, Almer Thie
|
||||
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
13
android/LICENSE_LOST.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
Copyright (c) 2014 Mapzen
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
1863
android/cpp/jni.cpp
Normal file
728
android/cpp/native_map_view.cpp
Normal file
@@ -0,0 +1,728 @@
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <tuple>
|
||||
|
||||
#include <sys/system_properties.h>
|
||||
|
||||
#include <GLES2/gl2.h>
|
||||
|
||||
#include <mbgl/android/native_map_view.hpp>
|
||||
#include <mbgl/android/jni.hpp>
|
||||
#include <mbgl/platform/platform.hpp>
|
||||
#include <mbgl/platform/event.hpp>
|
||||
#include <mbgl/platform/log.hpp>
|
||||
#include <mbgl/platform/gl.hpp>
|
||||
#include <mbgl/util/constants.hpp>
|
||||
|
||||
namespace mbgl {
|
||||
namespace android {
|
||||
|
||||
void log_egl_string(EGLDisplay display, EGLint name, const char *label) {
|
||||
const char *str = eglQueryString(display, name);
|
||||
if (str == nullptr) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglQueryString(%d) returned error %d", name,
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglQueryString() failed");
|
||||
} else {
|
||||
char buf[513];
|
||||
for (int len = std::strlen(str), pos = 0; len > 0; len -= 512, pos += 512) {
|
||||
strncpy(buf, str + pos, 512);
|
||||
buf[512] = 0;
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "EGL %s: %s", label, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void log_gl_string(GLenum name, const char *label) {
|
||||
const GLubyte *str = glGetString(name);
|
||||
if (str == nullptr) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "glGetString(%d) returned error %d", name,
|
||||
glGetError());
|
||||
throw new std::runtime_error("glGetString() failed");
|
||||
} else {
|
||||
char buf[513];
|
||||
for (int len = std::strlen(reinterpret_cast<const char *>(str)), pos = 0; len > 0;
|
||||
len -= 512, pos += 512) {
|
||||
strncpy(buf, reinterpret_cast<const char *>(str) + pos, 512);
|
||||
buf[512] = 0;
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "GL %s: %s", label, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NativeMapView::NativeMapView(JNIEnv *env, jobject obj_, float pixelRatio_, int availableProcessors_, size_t totalMemory_)
|
||||
: mbgl::View(*this),
|
||||
pixelRatio(pixelRatio_),
|
||||
availableProcessors(availableProcessors_),
|
||||
totalMemory(totalMemory_),
|
||||
fileCache(mbgl::android::cachePath + "/mbgl-cache.db"),
|
||||
fileSource(&fileCache),
|
||||
map(*this, fileSource, MapMode::Continuous) {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::NativeMapView");
|
||||
|
||||
map.pause();
|
||||
|
||||
assert(env != nullptr);
|
||||
assert(obj_ != nullptr);
|
||||
|
||||
if (env->GetJavaVM(&vm) < 0) {
|
||||
env->ExceptionDescribe();
|
||||
return;
|
||||
}
|
||||
|
||||
obj = env->NewGlobalRef(obj_);
|
||||
if (obj == nullptr) {
|
||||
env->ExceptionDescribe();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NativeMapView::~NativeMapView() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::~NativeMapView");
|
||||
terminateContext();
|
||||
destroySurface();
|
||||
terminateDisplay();
|
||||
|
||||
assert(vm != nullptr);
|
||||
assert(obj != nullptr);
|
||||
|
||||
jint ret;
|
||||
JNIEnv *env = nullptr;
|
||||
ret = vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6);
|
||||
if (ret == JNI_OK) {
|
||||
env->DeleteGlobalRef(obj);
|
||||
} else {
|
||||
mbgl::Log::Error(mbgl::Event::JNI, "GetEnv() failed with %i", ret);
|
||||
throw new std::runtime_error("GetEnv() failed");
|
||||
}
|
||||
obj = nullptr;
|
||||
vm = nullptr;
|
||||
}
|
||||
|
||||
float NativeMapView::getPixelRatio() const {
|
||||
return pixelRatio;
|
||||
}
|
||||
|
||||
std::array<uint16_t, 2> NativeMapView::getSize() const {
|
||||
return {{ static_cast<uint16_t>(width), static_cast<uint16_t>(height) }};
|
||||
}
|
||||
|
||||
std::array<uint16_t, 2> NativeMapView::getFramebufferSize() const {
|
||||
return {{ static_cast<uint16_t>(fbWidth), static_cast<uint16_t>(fbHeight) }};
|
||||
}
|
||||
|
||||
void NativeMapView::activate() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::activate");
|
||||
if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE) && (context != EGL_NO_CONTEXT)) {
|
||||
if (!eglMakeCurrent(display, surface, surface, context)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglMakeCurrent() failed");
|
||||
}
|
||||
} else {
|
||||
mbgl::Log::Info(mbgl::Event::Android, "Not activating as we are not ready");
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMapView::deactivate() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::deactivate");
|
||||
if (display != EGL_NO_DISPLAY) {
|
||||
if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent(EGL_NO_CONTEXT) returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglMakeCurrent() failed");
|
||||
}
|
||||
} else {
|
||||
mbgl::Log::Info(mbgl::Event::Android, "Not deactivating as we are not ready");
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMapView::invalidate() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::invalidate()");
|
||||
|
||||
clean.clear();
|
||||
|
||||
assert(vm != nullptr);
|
||||
assert(obj != nullptr);
|
||||
|
||||
JNIEnv *env = nullptr;
|
||||
bool detach = attach_jni_thread(vm, &env, "NativeMapView::invalidate()");
|
||||
|
||||
env->CallVoidMethod(obj, onInvalidateId);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
}
|
||||
|
||||
detach_jni_thread(vm, &env, detach);
|
||||
}
|
||||
|
||||
void NativeMapView::swap() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::swap");
|
||||
|
||||
if ((display != EGL_NO_DISPLAY) && (surface != EGL_NO_SURFACE)) {
|
||||
if (!eglSwapBuffers(display, surface)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglSwapBuffers() returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglSwapBuffers() failed");
|
||||
}
|
||||
updateFps();
|
||||
} else {
|
||||
mbgl::Log::Info(mbgl::Event::Android, "Not swapping as we are not ready");
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMapView::notify() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::notify()");
|
||||
// noop
|
||||
}
|
||||
|
||||
mbgl::Map &NativeMapView::getMap() { return map; }
|
||||
|
||||
mbgl::DefaultFileSource &NativeMapView::getFileSource() { return fileSource; }
|
||||
|
||||
bool NativeMapView::inEmulator() {
|
||||
// Detect if we are in emulator
|
||||
char prop[PROP_VALUE_MAX];
|
||||
__system_property_get("ro.kernel.qemu", prop);
|
||||
return strtol(prop, nullptr, 0) == 1;
|
||||
}
|
||||
|
||||
void NativeMapView::initializeDisplay() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::initializeDisplay");
|
||||
|
||||
assert(display == EGL_NO_DISPLAY);
|
||||
assert(config == nullptr);
|
||||
assert(format < 0);
|
||||
|
||||
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
if (display == EGL_NO_DISPLAY) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglGetDisplay() returned error %d", eglGetError());
|
||||
throw new std::runtime_error("eglGetDisplay() failed");
|
||||
}
|
||||
|
||||
EGLint major, minor;
|
||||
if (!eglInitialize(display, &major, &minor)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglInitialize() returned error %d", eglGetError());
|
||||
throw new std::runtime_error("eglInitialize() failed");
|
||||
}
|
||||
if ((major <= 1) && (minor < 3)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "EGL version is too low, need 1.3, got %d.%d", major,
|
||||
minor);
|
||||
throw new std::runtime_error("EGL version is too low");
|
||||
}
|
||||
|
||||
log_egl_string(display, EGL_VENDOR, "Vendor");
|
||||
log_egl_string(display, EGL_VERSION, "Version");
|
||||
log_egl_string(display, EGL_CLIENT_APIS, "Client APIs");
|
||||
log_egl_string(display, EGL_EXTENSIONS, "Client Extensions");
|
||||
|
||||
// Detect if we are in emulator
|
||||
if (inEmulator()) {
|
||||
mbgl::Log::Warning(mbgl::Event::Android, "In emulator! Enabling hacks :-(");
|
||||
}
|
||||
|
||||
// Get all configs at least RGB 565 with 16 depth and 8 stencil
|
||||
EGLint configAttribs[] = {
|
||||
EGL_CONFIG_CAVEAT, EGL_NONE, EGL_RENDERABLE_TYPE,
|
||||
EGL_OPENGL_ES2_BIT, EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
EGL_BUFFER_SIZE, 16, EGL_RED_SIZE,
|
||||
5, EGL_GREEN_SIZE, 6,
|
||||
EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE,
|
||||
16, EGL_STENCIL_SIZE, 8,
|
||||
(inEmulator() ? EGL_NONE : EGL_CONFORMANT), EGL_OPENGL_ES2_BIT, // Ugly hack
|
||||
(inEmulator() ? EGL_NONE : EGL_COLOR_BUFFER_TYPE), EGL_RGB_BUFFER, // Ugly hack
|
||||
EGL_NONE};
|
||||
EGLint numConfigs;
|
||||
if (!eglChooseConfig(display, configAttribs, nullptr, 0, &numConfigs)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglChooseConfig(NULL) returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglChooseConfig() failed");
|
||||
}
|
||||
if (numConfigs < 1) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglChooseConfig() returned no configs.");
|
||||
throw new std::runtime_error("eglChooseConfig() failed");
|
||||
}
|
||||
|
||||
const auto configs = std::make_unique<EGLConfig[]>(numConfigs);
|
||||
if (!eglChooseConfig(display, configAttribs, configs.get(), numConfigs, &numConfigs)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglChooseConfig() returned error %d", eglGetError());
|
||||
throw new std::runtime_error("eglChooseConfig() failed");
|
||||
}
|
||||
|
||||
config = chooseConfig(configs.get(), numConfigs);
|
||||
if (config == nullptr) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "No config chosen");
|
||||
throw new std::runtime_error("No config chosen");
|
||||
}
|
||||
|
||||
if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglGetConfigAttrib() returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglGetConfigAttrib() failed");
|
||||
}
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "Chosen window format is %d", format);
|
||||
}
|
||||
|
||||
void NativeMapView::terminateDisplay() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::terminateDisplay");
|
||||
|
||||
if (display != EGL_NO_DISPLAY) {
|
||||
// Destroy the surface first, if it still exists. This call needs a valid surface.
|
||||
if (surface != EGL_NO_SURFACE) {
|
||||
if (!eglDestroySurface(display, surface)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglDestroySurface() failed");
|
||||
}
|
||||
surface = EGL_NO_SURFACE;
|
||||
}
|
||||
|
||||
if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
|
||||
throw new std::runtime_error("eglMakeCurrent() failed");
|
||||
}
|
||||
|
||||
if (!eglTerminate(display)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglTerminate() returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglTerminate() failed");
|
||||
}
|
||||
}
|
||||
|
||||
display = EGL_NO_DISPLAY;
|
||||
config = nullptr;
|
||||
format = -1;
|
||||
}
|
||||
|
||||
void NativeMapView::initializeContext() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::initializeContext");
|
||||
|
||||
assert(display != EGL_NO_DISPLAY);
|
||||
assert(context == EGL_NO_CONTEXT);
|
||||
assert(config != nullptr);
|
||||
|
||||
const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
|
||||
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
|
||||
if (context == EGL_NO_CONTEXT) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateContext() returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglCreateContext() failed");
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMapView::terminateContext() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::terminateContext");
|
||||
if (display != EGL_NO_DISPLAY) {
|
||||
|
||||
if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
|
||||
throw new std::runtime_error("eglMakeCurrent() failed");
|
||||
}
|
||||
|
||||
if (context != EGL_NO_CONTEXT) {
|
||||
if (!eglDestroyContext(display, context)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroyContext() returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglDestroyContext() failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context = EGL_NO_CONTEXT;
|
||||
}
|
||||
|
||||
void NativeMapView::createSurface(ANativeWindow *window_) {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::createSurface");
|
||||
|
||||
assert(window == nullptr);
|
||||
assert(window_ != nullptr);
|
||||
window = window_;
|
||||
|
||||
assert(display != EGL_NO_DISPLAY);
|
||||
assert(surface == EGL_NO_SURFACE);
|
||||
assert(config != nullptr);
|
||||
assert(format >= 0);
|
||||
|
||||
ANativeWindow_setBuffersGeometry(window, 0, 0, format);
|
||||
|
||||
const EGLint surfaceAttribs[] = {EGL_NONE};
|
||||
surface = eglCreateWindowSurface(display, config, window, surfaceAttribs);
|
||||
if (surface == EGL_NO_SURFACE) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglCreateWindowSurface() returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglCreateWindowSurface() failed");
|
||||
}
|
||||
|
||||
if (!firstTime) {
|
||||
firstTime = true;
|
||||
|
||||
if (!eglMakeCurrent(display, surface, surface, context)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglMakeCurrent() returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglMakeCurrent() failed");
|
||||
}
|
||||
|
||||
log_gl_string(GL_VENDOR, "Vendor");
|
||||
log_gl_string(GL_RENDERER, "Renderer");
|
||||
log_gl_string(GL_VERSION, "Version");
|
||||
if (!inEmulator()) {
|
||||
log_gl_string(GL_SHADING_LANGUAGE_VERSION,
|
||||
"SL Version"); // In the emulator this returns NULL with error code 0?
|
||||
// https://code.google.com/p/android/issues/detail?id=78977
|
||||
}
|
||||
|
||||
log_gl_string(GL_EXTENSIONS, "Extensions");
|
||||
mbgl::gl::InitializeExtensions([] (const char * name) {
|
||||
return reinterpret_cast<mbgl::gl::glProc>(eglGetProcAddress(name));
|
||||
});
|
||||
|
||||
if (!eglMakeCurrent(display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglMakeCurrent(EGL_NO_CONTEXT) returned error %d", eglGetError());
|
||||
throw new std::runtime_error("eglMakeCurrent() failed");
|
||||
}
|
||||
}
|
||||
|
||||
resume();
|
||||
}
|
||||
|
||||
void NativeMapView::destroySurface() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::destroySurface");
|
||||
|
||||
pause();
|
||||
|
||||
if (surface != EGL_NO_SURFACE) {
|
||||
if (!eglDestroySurface(display, surface)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "eglDestroySurface() returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglDestroySurface() failed");
|
||||
}
|
||||
}
|
||||
|
||||
surface = EGL_NO_SURFACE;
|
||||
|
||||
if (window != nullptr) {
|
||||
ANativeWindow_release(window);
|
||||
window = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Speed
|
||||
/*
|
||||
typedef enum {
|
||||
Format16Bit = 0,
|
||||
Format32BitNoAlpha = 1,
|
||||
Format32BitAlpha = 2,
|
||||
Format24Bit = 3,
|
||||
Unknown = 4
|
||||
} BufferFormat;
|
||||
|
||||
typedef enum {
|
||||
Format16Depth8Stencil = 0,
|
||||
Format24Depth8Stencil = 1,
|
||||
} DepthStencilFormat;
|
||||
*/
|
||||
|
||||
// Quality
|
||||
typedef enum {
|
||||
Format16Bit = 3,
|
||||
Format32BitNoAlpha = 1,
|
||||
Format32BitAlpha = 2,
|
||||
Format24Bit = 0,
|
||||
Unknown = 4
|
||||
} BufferFormat;
|
||||
|
||||
typedef enum {
|
||||
Format16Depth8Stencil = 1,
|
||||
Format24Depth8Stencil = 0,
|
||||
} DepthStencilFormat;
|
||||
|
||||
// Tuple is <buffer_format, depth_stencil_format, is_not_conformant, is_caveat, config_num,
|
||||
// config_id>
|
||||
typedef std::tuple<BufferFormat, DepthStencilFormat, bool, bool, int, EGLConfig> ConfigProperties;
|
||||
|
||||
EGLConfig NativeMapView::chooseConfig(const EGLConfig configs[], EGLint numConfigs) {
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "Found %d configs", numConfigs);
|
||||
|
||||
// Create a list of configs that pass our filters
|
||||
std::list<ConfigProperties> configList;
|
||||
for (int i = 0; i < numConfigs; i++) {
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "Config %d:", i);
|
||||
|
||||
EGLint caveat, conformant, bits, red, green, blue, alpha, alphaMask, depth, stencil,
|
||||
sampleBuffers, samples;
|
||||
|
||||
if (!eglGetConfigAttrib(display, configs[i], EGL_CONFIG_CAVEAT, &caveat)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglGetConfigAttrib(EGL_CONFIG_CAVEAT) returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglGetConfigAttrib() failed");
|
||||
}
|
||||
|
||||
if (!eglGetConfigAttrib(display, configs[i], EGL_CONFORMANT, &conformant)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglGetConfigAttrib(EGL_CONFORMANT) returned error %d", eglGetError());
|
||||
throw new std::runtime_error("eglGetConfigAttrib() failed");
|
||||
}
|
||||
|
||||
if (!eglGetConfigAttrib(display, configs[i], EGL_BUFFER_SIZE, &bits)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglGetConfigAttrib(EGL_BUFFER_SIZE) returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglGetConfigAttrib() failed");
|
||||
}
|
||||
|
||||
if (!eglGetConfigAttrib(display, configs[i], EGL_RED_SIZE, &red)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglGetConfigAttrib(EGL_RED_SIZE) returned error %d", eglGetError());
|
||||
throw new std::runtime_error("eglGetConfigAttrib() failed");
|
||||
}
|
||||
|
||||
if (!eglGetConfigAttrib(display, configs[i], EGL_GREEN_SIZE, &green)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglGetConfigAttrib(EGL_GREEN_SIZE) returned error %d", eglGetError());
|
||||
throw new std::runtime_error("eglGetConfigAttrib() failed");
|
||||
}
|
||||
|
||||
if (!eglGetConfigAttrib(display, configs[i], EGL_BLUE_SIZE, &blue)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglGetConfigAttrib(EGL_BLUE_SIZE) returned error %d", eglGetError());
|
||||
throw new std::runtime_error("eglGetConfigAttrib() failed");
|
||||
}
|
||||
|
||||
if (!eglGetConfigAttrib(display, configs[i], EGL_ALPHA_SIZE, &alpha)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglGetConfigAttrib(EGL_ALPHA_SIZE) returned error %d", eglGetError());
|
||||
throw new std::runtime_error("eglGetConfigAttrib() failed");
|
||||
}
|
||||
|
||||
if (!eglGetConfigAttrib(display, configs[i], EGL_ALPHA_MASK_SIZE, &alphaMask)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglGetConfigAttrib(EGL_ALPHA_MASK_SIZE) returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglGetConfigAttrib() failed");
|
||||
}
|
||||
|
||||
if (!eglGetConfigAttrib(display, configs[i], EGL_DEPTH_SIZE, &depth)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglGetConfigAttrib(EGL_DEPTH_SIZE) returned error %d", eglGetError());
|
||||
throw new std::runtime_error("eglGetConfigAttrib() failed");
|
||||
}
|
||||
|
||||
if (!eglGetConfigAttrib(display, configs[i], EGL_STENCIL_SIZE, &stencil)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglGetConfigAttrib(EGL_STENCIL_SIZE) returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglGetConfigAttrib() failed");
|
||||
}
|
||||
|
||||
if (!eglGetConfigAttrib(display, configs[i], EGL_SAMPLE_BUFFERS, &sampleBuffers)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglGetConfigAttrib(EGL_SAMPLE_BUFFERS) returned error %d",
|
||||
eglGetError());
|
||||
throw new std::runtime_error("eglGetConfigAttrib() failed");
|
||||
}
|
||||
|
||||
if (!eglGetConfigAttrib(display, configs[i], EGL_SAMPLES, &samples)) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL,
|
||||
"eglGetConfigAttrib(EGL_SAMPLES) returned error %d", eglGetError());
|
||||
throw new std::runtime_error("eglGetConfigAttrib() failed");
|
||||
}
|
||||
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "...Caveat: %d", caveat);
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "...Conformant: %d", conformant);
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "...Color: %d", bits);
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "...Red: %d", red);
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "...Green: %d", green);
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "...Blue: %d", blue);
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "...Alpha: %d", alpha);
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "...Alpha mask: %d", alphaMask);
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "...Depth: %d", depth);
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "...Stencil: %d", stencil);
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "...Sample buffers: %d", sampleBuffers);
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "...Samples: %d", samples);
|
||||
|
||||
bool configOk = true;
|
||||
configOk &= (depth == 24) || (depth == 16);
|
||||
configOk &= stencil == 8;
|
||||
configOk &= sampleBuffers == 0;
|
||||
configOk &= samples == 0;
|
||||
|
||||
// Filter our configs first for depth, stencil and anti-aliasing
|
||||
if (configOk) {
|
||||
// Work out the config's buffer format
|
||||
BufferFormat bufferFormat;
|
||||
if ((bits == 16) && (red == 5) && (green == 6) && (blue == 5) && (alpha == 0)) {
|
||||
bufferFormat = Format16Bit;
|
||||
} else if ((bits == 32) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 0)) {
|
||||
bufferFormat = Format32BitNoAlpha;
|
||||
} else if ((bits == 32) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 8)) {
|
||||
bufferFormat = Format32BitAlpha;
|
||||
} else if ((bits == 24) && (red == 8) && (green == 8) && (blue == 8) && (alpha == 0)) {
|
||||
bufferFormat = Format24Bit;
|
||||
} else {
|
||||
bufferFormat = Unknown;
|
||||
}
|
||||
|
||||
// Work out the config's depth stencil format
|
||||
DepthStencilFormat depthStencilFormat;
|
||||
if ((depth == 16) && (stencil == 8)) {
|
||||
depthStencilFormat = Format16Depth8Stencil;
|
||||
} else {
|
||||
depthStencilFormat = Format24Depth8Stencil;
|
||||
}
|
||||
|
||||
bool isNotConformant = (conformant & EGL_OPENGL_ES2_BIT) != EGL_OPENGL_ES2_BIT;
|
||||
bool isCaveat = caveat != EGL_NONE;
|
||||
EGLConfig configId = configs[i];
|
||||
|
||||
// Ignore formats we don't recognise
|
||||
if (bufferFormat != Unknown) {
|
||||
configList.push_back(std::make_tuple(bufferFormat, depthStencilFormat,
|
||||
isNotConformant, isCaveat, i, configId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (configList.empty()) {
|
||||
mbgl::Log::Error(mbgl::Event::OpenGL, "Config list was empty.");
|
||||
}
|
||||
|
||||
// Sort the configs to find the best one
|
||||
configList.sort();
|
||||
bool isConformant = !std::get<2>(configList.front());
|
||||
bool isCaveat = std::get<3>(configList.front());
|
||||
int configNum = std::get<4>(configList.front());
|
||||
EGLConfig configId = std::get<5>(configList.front());
|
||||
|
||||
mbgl::Log::Info(mbgl::Event::OpenGL, "Chosen config is %d", configNum);
|
||||
|
||||
if (isCaveat) {
|
||||
mbgl::Log::Warning(mbgl::Event::OpenGL, "Chosen config has a caveat.");
|
||||
}
|
||||
if (!isConformant) {
|
||||
mbgl::Log::Warning(mbgl::Event::OpenGL, "Chosen config is not conformant.");
|
||||
}
|
||||
|
||||
return configId;
|
||||
}
|
||||
|
||||
void NativeMapView::pause() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::pause");
|
||||
|
||||
if ((display != EGL_NO_DISPLAY) && (context != EGL_NO_CONTEXT)) {
|
||||
map.pause();
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMapView::resume() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::resume");
|
||||
|
||||
assert(display != EGL_NO_DISPLAY);
|
||||
assert(context != EGL_NO_CONTEXT);
|
||||
|
||||
if (surface != EGL_NO_SURFACE) {
|
||||
map.resume();
|
||||
} else {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "Not resuming because we are not ready");
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMapView::notifyMapChange(mbgl::MapChange) {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::notifyMapChange()");
|
||||
|
||||
assert(vm != nullptr);
|
||||
assert(obj != nullptr);
|
||||
|
||||
JNIEnv *env = nullptr;
|
||||
bool detach = attach_jni_thread(vm, &env, "NativeMapView::notifyMapChange()");
|
||||
|
||||
env->CallVoidMethod(obj, onMapChangedId);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
}
|
||||
|
||||
detach_jni_thread(vm, &env, detach);
|
||||
}
|
||||
|
||||
void NativeMapView::enableFps(bool enable) {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::enableFps()");
|
||||
|
||||
fpsEnabled = enable;
|
||||
}
|
||||
|
||||
void NativeMapView::updateFps() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::updateFps()");
|
||||
|
||||
if (!fpsEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
static int frames = 0;
|
||||
static int64_t timeElapsed = 0LL;
|
||||
|
||||
frames++;
|
||||
struct timespec now;
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
int64_t currentTime = now.tv_sec * 1000000000LL + now.tv_nsec;
|
||||
|
||||
if (currentTime - timeElapsed >= 1) {
|
||||
fps = frames / ((currentTime - timeElapsed) / 1E9);
|
||||
mbgl::Log::Debug(mbgl::Event::Render, "FPS: %4.2f", fps);
|
||||
timeElapsed = currentTime;
|
||||
frames = 0;
|
||||
}
|
||||
|
||||
assert(vm != nullptr);
|
||||
assert(obj != nullptr);
|
||||
|
||||
JNIEnv *env = nullptr;
|
||||
bool detach = attach_jni_thread(vm, &env, "NativeMapView::updateFps()");
|
||||
|
||||
env->CallVoidMethod(obj, onFpsChangedId, fps);
|
||||
if (env->ExceptionCheck()) {
|
||||
env->ExceptionDescribe();
|
||||
}
|
||||
|
||||
detach_jni_thread(vm, &env, detach);
|
||||
}
|
||||
|
||||
void NativeMapView::onInvalidate() {
|
||||
mbgl::Log::Debug(mbgl::Event::Android, "NativeMapView::onInvalidate()");
|
||||
|
||||
const bool dirty = !clean.test_and_set();
|
||||
if (dirty) {
|
||||
float zoomFactor = map.getMaxZoom() - map.getMinZoom() + 1;
|
||||
float cpuFactor = availableProcessors;
|
||||
float memoryFactor = static_cast<float>(totalMemory) / 1000.0f / 1000.0f / 1000.0f;
|
||||
float sizeFactor = (static_cast<float>(map.getWidth()) / mbgl::util::tileSize) *
|
||||
(static_cast<float>(map.getHeight()) / mbgl::util::tileSize);
|
||||
|
||||
size_t cacheSize = zoomFactor * cpuFactor * memoryFactor * sizeFactor * 0.5f;
|
||||
|
||||
map.setSourceTileCacheSize(cacheSize);
|
||||
|
||||
map.renderSync();
|
||||
map.nudgeTransitions();
|
||||
}
|
||||
}
|
||||
|
||||
void NativeMapView::resizeView(int w, int h) {
|
||||
width = w;
|
||||
height = h;
|
||||
map.update(mbgl::Update::Dimensions);
|
||||
}
|
||||
|
||||
void NativeMapView::resizeFramebuffer(int w, int h) {
|
||||
fbWidth = w;
|
||||
fbHeight = h;
|
||||
map.update(mbgl::Update::Repaint);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
23
android/java/.gitignore
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
# Gradle files
|
||||
.gradle/
|
||||
|
||||
# IntelliJ files
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
# Build files
|
||||
build/
|
||||
*.so
|
||||
*.apk
|
||||
|
||||
# Lib assets
|
||||
MapboxGLAndroidSDK/src/main/assets/
|
||||
|
||||
# Local settings
|
||||
local.properties
|
||||
|
||||
# Token file
|
||||
MapboxGLAndroidSDKTestApp/src/main/res/raw/token.txt
|
||||
|
||||
# Twitter Fabric / Crashlytics
|
||||
fabric.properties
|
||||
256
android/java/MapboxGLAndroidSDK/build.gradle
Normal file
@@ -0,0 +1,256 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.3.0'
|
||||
classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'android-sdk-manager'
|
||||
apply plugin: 'com.android.library'
|
||||
apply plugin: 'checkstyle'
|
||||
apply plugin: 'maven'
|
||||
apply plugin: 'signing'
|
||||
|
||||
allprojects {
|
||||
group project.GROUP
|
||||
version project.VERSION_NAME
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile 'com.android.support:support-annotations:23.0.0'
|
||||
compile 'com.android.support:support-v4:23.0.0'
|
||||
compile 'com.android.support:design:23.0.0'
|
||||
compile 'com.squareup.okhttp:okhttp:2.4.0'
|
||||
compile 'com.mapzen.android:lost:1.0.1'
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion Integer.parseInt(project.ANDROID_BUILD_SDK_VERSION)
|
||||
buildToolsVersion project.ANDROID_BUILD_TOOLS_VERSION
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion Integer.parseInt(project.ANDROID_MIN_SDK)
|
||||
targetSdkVersion Integer.parseInt(project.ANDROID_BUILD_TARGET_SDK_VERSION)
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
checkAllWarnings true
|
||||
warningsAsErrors true
|
||||
disable 'InvalidPackage'
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
debug {
|
||||
jniDebuggable true
|
||||
}
|
||||
|
||||
release {
|
||||
minifyEnabled false
|
||||
jniDebuggable false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
all*.exclude group: 'commons-logging', module: 'commons-logging'
|
||||
all*.exclude group: 'commons-collections', module: 'commons-collections'
|
||||
}
|
||||
|
||||
|
||||
android.libraryVariants.all { variant ->
|
||||
def name = variant.name
|
||||
task "javadoc$name"(type: Javadoc) {
|
||||
description = "Generates javadoc for build $name"
|
||||
failOnError = false
|
||||
destinationDir = new File(destinationDir, variant.baseName)
|
||||
source = files(variant.javaCompile.source)
|
||||
classpath = files(variant.javaCompile.classpath.files) + files(android.bootClasspath)
|
||||
options.links("http://docs.oracle.com/javase/7/docs/api/")
|
||||
options.links("http://d.android.com/reference/")
|
||||
exclude '**/R.html', '**/R.*.html'
|
||||
}
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
configFile project.file('../checks.xml')
|
||||
showViolations true
|
||||
}
|
||||
|
||||
/*
|
||||
task cleanJNIBuilds {
|
||||
def jniLibsDir = new File("MapboxGLAndroidSDK/src/main/jniLibs")
|
||||
delete jniLibsDir.absolutePath
|
||||
}
|
||||
*/
|
||||
|
||||
android.libraryVariants.all { variant ->
|
||||
def name = variant.buildType.name
|
||||
def checkstyle = project.tasks.create "checkstyle${name.capitalize()}", Checkstyle
|
||||
checkstyle.dependsOn variant.javaCompile
|
||||
checkstyle.source variant.javaCompile.source
|
||||
checkstyle.classpath = project.fileTree(variant.javaCompile.destinationDir)
|
||||
checkstyle.exclude('**/BuildConfig.java')
|
||||
checkstyle.exclude('**/R.java')
|
||||
checkstyle.exclude('**/com/almeros/android/multitouch/**')
|
||||
project.tasks.getByName("check").dependsOn checkstyle
|
||||
}
|
||||
|
||||
// From https://raw.github.com/mcxiaoke/gradle-mvn-push/master/jar.gradle
|
||||
android.libraryVariants.all { variant ->
|
||||
def jarTask = project.tasks.create(name: "jar${variant.name.capitalize()}", type: Jar) {
|
||||
from variant.javaCompile.destinationDir
|
||||
exclude "**/R.class"
|
||||
exclude "**/BuildConfig.class"
|
||||
}
|
||||
jarTask.dependsOn variant.javaCompile
|
||||
artifacts.add('archives', jarTask);
|
||||
}
|
||||
|
||||
// From https://raw.github.com/mcxiaoke/gradle-mvn-push/master/gradle-mvn-push.gradle
|
||||
def isReleaseBuild() {
|
||||
return VERSION_NAME.contains("SNAPSHOT") == false
|
||||
}
|
||||
|
||||
def getReleaseRepositoryUrl() {
|
||||
return hasProperty('RELEASE_REPOSITORY_URL') ? RELEASE_REPOSITORY_URL :
|
||||
"https://oss.sonatype.org/service/local/staging/deploy/maven2/"
|
||||
}
|
||||
|
||||
def getSnapshotRepositoryUrl() {
|
||||
return hasProperty('SNAPSHOT_REPOSITORY_URL') ? SNAPSHOT_REPOSITORY_URL :
|
||||
"https://oss.sonatype.org/content/repositories/snapshots/"
|
||||
}
|
||||
|
||||
def getRepositoryUsername() {
|
||||
return hasProperty('USERNAME') ? USERNAME :
|
||||
(hasProperty('NEXUS_USERNAME') ? NEXUS_USERNAME : "")
|
||||
}
|
||||
|
||||
def getRepositoryPassword() {
|
||||
return hasProperty('PASSWORD') ? PASSWORD :
|
||||
(hasProperty('NEXUS_PASSWORD') ? NEXUS_PASSWORD : "")
|
||||
}
|
||||
|
||||
|
||||
task apklib(type: Zip) {
|
||||
appendix = extension = 'apklib'
|
||||
|
||||
from 'AndroidManifest.xml'
|
||||
into('res') {
|
||||
from 'res'
|
||||
}
|
||||
into('src') {
|
||||
from 'src'
|
||||
}
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives apklib
|
||||
}
|
||||
|
||||
afterEvaluate { project ->
|
||||
uploadArchives {
|
||||
repositories {
|
||||
mavenDeployer {
|
||||
beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
|
||||
|
||||
pom.groupId = GROUP
|
||||
pom.artifactId = POM_ARTIFACT_ID
|
||||
pom.version = VERSION_NAME
|
||||
|
||||
repository(url: getReleaseRepositoryUrl()) {
|
||||
authentication(userName: getRepositoryUsername(),
|
||||
password: getRepositoryPassword())
|
||||
}
|
||||
snapshotRepository(url: getSnapshotRepositoryUrl()) {
|
||||
authentication(userName: getRepositoryUsername(),
|
||||
password: getRepositoryPassword())
|
||||
}
|
||||
|
||||
/*
|
||||
// Leaving out as artifact was incorrectly named when found
|
||||
addFilter('aar') { artifact, file ->
|
||||
artifact.name == archivesBaseName
|
||||
}
|
||||
addFilter('apklib') { artifact, file ->
|
||||
artifact.name == archivesBaseName + '-apklib'
|
||||
}
|
||||
*/
|
||||
|
||||
pom.project {
|
||||
name POM_NAME
|
||||
packaging POM_PACKAGING
|
||||
description POM_DESCRIPTION
|
||||
url POM_URL
|
||||
|
||||
scm {
|
||||
url POM_SCM_URL
|
||||
connection POM_SCM_CONNECTION
|
||||
developerConnection POM_SCM_DEV_CONNECTION
|
||||
}
|
||||
|
||||
licenses {
|
||||
license {
|
||||
name POM_LICENCE_NAME
|
||||
url POM_LICENCE_URL
|
||||
distribution POM_LICENCE_DIST
|
||||
}
|
||||
}
|
||||
|
||||
developers {
|
||||
developer {
|
||||
id POM_DEVELOPER_ID
|
||||
name POM_DEVELOPER_NAME
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
signing {
|
||||
required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
|
||||
sign configurations.archives
|
||||
}
|
||||
|
||||
task androidJavadocs(type: Javadoc) {
|
||||
source = android.sourceSets.main.java.sourceFiles
|
||||
classpath = files(android.bootClasspath)
|
||||
}
|
||||
|
||||
task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
|
||||
classifier = 'javadoc'
|
||||
from androidJavadocs.destinationDir
|
||||
}
|
||||
|
||||
task androidSourcesJar(type: Jar) {
|
||||
classifier = 'sources'
|
||||
from android.sourceSets.main.java.sourceFiles
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives androidSourcesJar
|
||||
archives androidJavadocsJar
|
||||
}
|
||||
}
|
||||
2
android/java/MapboxGLAndroidSDK/deploy.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/usr/bin/env bash
|
||||
../gradlew -b build.gradle clean assembleRelease uploadArchives
|
||||
22
android/java/MapboxGLAndroidSDK/gradle.properties
Normal file
@@ -0,0 +1,22 @@
|
||||
GROUP=com.mapbox.mapboxgl
|
||||
VERSION_NAME=0.0.1-SNAPSHOT
|
||||
|
||||
POM_DESCRIPTION=Mapbox GL Android SDK
|
||||
POM_URL=https://github.com/mapbox/mapbox-gl-native
|
||||
POM_SCM_URL=https://github.com/mapbox/mapbox-gl-native
|
||||
POM_SCM_CONNECTION=scm:git@github.com:mapbox/mapbox-gl-native.git
|
||||
POM_SCM_DEV_CONNECTION=scm:git@github.com:mapbox/mapbox-gl-native.git
|
||||
POM_LICENCE_NAME=The Apache Software License, Version 2.0
|
||||
POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
|
||||
POM_LICENCE_DIST=repo
|
||||
POM_DEVELOPER_ID=mapbox
|
||||
POM_DEVELOPER_NAME=Mapbox
|
||||
|
||||
ANDROID_MIN_SDK=8
|
||||
ANDROID_BUILD_TARGET_SDK_VERSION=23
|
||||
ANDROID_BUILD_TOOLS_VERSION=23
|
||||
ANDROID_BUILD_SDK_VERSION=23
|
||||
|
||||
POM_NAME=Mapbox GL Android SDK
|
||||
POM_ARTIFACT_ID=mapbox-gl-android-sdk
|
||||
POM_PACKAGING=aar
|
||||
7
android/java/MapboxGLAndroidSDK/lint.xml
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<lint>
|
||||
<!-- Ignore errors caused by OkHTTP -->
|
||||
<issue id="InvalidPackage" severity="ignore">
|
||||
<ignore path="*/okio-1.2.0.jar" />
|
||||
</issue>
|
||||
</lint>
|
||||
@@ -0,0 +1,9 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.mapbox.mapboxgl.views">
|
||||
|
||||
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
|
||||
</manifest>
|
||||
@@ -0,0 +1,161 @@
|
||||
package com.almeros.android.multitouch.gesturedetectors;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie
|
||||
* (code.almeros.com)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
|
||||
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
public abstract class BaseGestureDetector {
|
||||
protected final Context mContext;
|
||||
protected boolean mGestureInProgress;
|
||||
|
||||
protected MotionEvent mPrevEvent;
|
||||
protected MotionEvent mCurrEvent;
|
||||
|
||||
protected float mCurrPressure;
|
||||
protected float mPrevPressure;
|
||||
protected long mTimeDelta;
|
||||
|
||||
/**
|
||||
* This value is the threshold ratio between the previous combined pressure
|
||||
* and the current combined pressure. When pressure decreases rapidly
|
||||
* between events the position values can often be imprecise, as it usually
|
||||
* indicates that the user is in the process of lifting a pointer off of the
|
||||
* device. This value was tuned experimentally.
|
||||
*/
|
||||
protected static final float PRESSURE_THRESHOLD = 0.67f;
|
||||
|
||||
public BaseGestureDetector(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* All gesture detectors need to be called through this method to be able to
|
||||
* detect gestures. This method delegates work to handler methods
|
||||
* (handleStartProgressEvent, handleInProgressEvent) implemented in
|
||||
* extending classes.
|
||||
*
|
||||
* @param event MotionEvent
|
||||
* @return {@code true} as handled
|
||||
*/
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
final int actionCode = event.getAction() & MotionEvent.ACTION_MASK;
|
||||
if (!mGestureInProgress) {
|
||||
handleStartProgressEvent(actionCode, event);
|
||||
} else {
|
||||
handleInProgressEvent(actionCode, event);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the current event occurred when NO gesture is in progress
|
||||
* yet. The handling in this implementation may set the gesture in progress
|
||||
* (via mGestureInProgress) or out of progress
|
||||
*
|
||||
* @param actionCode Action Code from MotionEvent
|
||||
* @param event MotionEvent
|
||||
*/
|
||||
protected abstract void handleStartProgressEvent(int actionCode,
|
||||
MotionEvent event);
|
||||
|
||||
/**
|
||||
* Called when the current event occurred when a gesture IS in progress. The
|
||||
* handling in this implementation may set the gesture out of progress (via
|
||||
* mGestureInProgress).
|
||||
*
|
||||
*
|
||||
* @param actionCode Action Code from MotionEvent
|
||||
* @param event MotionEvent
|
||||
*/
|
||||
protected abstract void handleInProgressEvent(int actionCode,
|
||||
MotionEvent event);
|
||||
|
||||
protected void updateStateByEvent(MotionEvent curr) {
|
||||
final MotionEvent prev = mPrevEvent;
|
||||
|
||||
// Reset mCurrEvent
|
||||
if (mCurrEvent != null) {
|
||||
mCurrEvent.recycle();
|
||||
mCurrEvent = null;
|
||||
}
|
||||
mCurrEvent = MotionEvent.obtain(curr);
|
||||
|
||||
// Delta time
|
||||
mTimeDelta = curr.getEventTime() - prev.getEventTime();
|
||||
|
||||
// Pressure
|
||||
mCurrPressure = curr.getPressure(curr.getActionIndex());
|
||||
mPrevPressure = prev.getPressure(prev.getActionIndex());
|
||||
}
|
||||
|
||||
protected void resetState() {
|
||||
if (mPrevEvent != null) {
|
||||
mPrevEvent.recycle();
|
||||
mPrevEvent = null;
|
||||
}
|
||||
if (mCurrEvent != null) {
|
||||
mCurrEvent.recycle();
|
||||
mCurrEvent = null;
|
||||
}
|
||||
mGestureInProgress = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if a gesture is currently in progress.
|
||||
*
|
||||
* @return {@code true} if a gesture is currently in progress, {@code false}
|
||||
* otherwise.
|
||||
*/
|
||||
public boolean isInProgress() {
|
||||
return mGestureInProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time difference in milliseconds between the previous accepted
|
||||
* GestureDetector event and the current GestureDetector event.
|
||||
*
|
||||
* @return Time difference since the last move event in milliseconds.
|
||||
*/
|
||||
public long getTimeDelta() {
|
||||
return mTimeDelta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the event time of the current GestureDetector event being
|
||||
* processed.
|
||||
*
|
||||
* @return Current GestureDetector event time in milliseconds.
|
||||
*/
|
||||
public long getEventTime() {
|
||||
return mCurrEvent.getEventTime();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
package com.almeros.android.multitouch.gesturedetectors;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie
|
||||
* (code.almeros.com)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
|
||||
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
public class MoveGestureDetector extends BaseGestureDetector {
|
||||
|
||||
/**
|
||||
* Listener which must be implemented which is used by MoveGestureDetector
|
||||
* to perform callbacks to any implementing class which is registered to a
|
||||
* MoveGestureDetector via the constructor.
|
||||
*
|
||||
* @see MoveGestureDetector.SimpleOnMoveGestureListener
|
||||
*/
|
||||
public interface OnMoveGestureListener {
|
||||
public boolean onMove(MoveGestureDetector detector);
|
||||
|
||||
public boolean onMoveBegin(MoveGestureDetector detector);
|
||||
|
||||
public void onMoveEnd(MoveGestureDetector detector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class which may be extended and where the methods may be
|
||||
* implemented. This way it is not necessary to implement all methods of
|
||||
* OnMoveGestureListener.
|
||||
*/
|
||||
public static class SimpleOnMoveGestureListener implements
|
||||
OnMoveGestureListener {
|
||||
public boolean onMove(MoveGestureDetector detector) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onMoveBegin(MoveGestureDetector detector) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onMoveEnd(MoveGestureDetector detector) {
|
||||
// Do nothing, overridden implementation may be used
|
||||
}
|
||||
}
|
||||
|
||||
private static final PointF FOCUS_DELTA_ZERO = new PointF();
|
||||
|
||||
private final OnMoveGestureListener mListener;
|
||||
|
||||
private PointF mFocusExternal = new PointF();
|
||||
private PointF mFocusDeltaExternal = new PointF();
|
||||
|
||||
public MoveGestureDetector(Context context, OnMoveGestureListener listener) {
|
||||
super(context);
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleStartProgressEvent(int actionCode, MotionEvent event) {
|
||||
switch (actionCode) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
resetState(); // In case we missed an UP/CANCEL event
|
||||
|
||||
mPrevEvent = MotionEvent.obtain(event);
|
||||
mTimeDelta = 0;
|
||||
|
||||
updateStateByEvent(event);
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
mGestureInProgress = mListener.onMoveBegin(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleInProgressEvent(int actionCode, MotionEvent event) {
|
||||
switch (actionCode) {
|
||||
case MotionEvent.ACTION_UP:
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
mListener.onMoveEnd(this);
|
||||
resetState();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
updateStateByEvent(event);
|
||||
|
||||
// Only accept the event if our relative pressure is within
|
||||
// a certain limit. This can help filter shaky data as a
|
||||
// finger is lifted.
|
||||
if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) {
|
||||
final boolean updatePrevious = mListener.onMove(this);
|
||||
if (updatePrevious) {
|
||||
mPrevEvent.recycle();
|
||||
mPrevEvent = MotionEvent.obtain(event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected void updateStateByEvent(MotionEvent curr) {
|
||||
super.updateStateByEvent(curr);
|
||||
|
||||
final MotionEvent prev = mPrevEvent;
|
||||
|
||||
// Focus intenal
|
||||
PointF mCurrFocusInternal = determineFocalPoint(curr);
|
||||
PointF mPrevFocusInternal = determineFocalPoint(prev);
|
||||
|
||||
// Focus external
|
||||
// - Prevent skipping of focus delta when a finger is added or removed
|
||||
boolean mSkipNextMoveEvent = prev.getPointerCount() != curr
|
||||
.getPointerCount();
|
||||
mFocusDeltaExternal = mSkipNextMoveEvent ? FOCUS_DELTA_ZERO
|
||||
: new PointF(mCurrFocusInternal.x - mPrevFocusInternal.x,
|
||||
mCurrFocusInternal.y - mPrevFocusInternal.y);
|
||||
|
||||
// - Don't directly use mFocusInternal (or skipping will occur). Add
|
||||
// unskipped delta values to mFocusExternal instead.
|
||||
mFocusExternal.x += mFocusDeltaExternal.x;
|
||||
mFocusExternal.y += mFocusDeltaExternal.y;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine (multi)finger focal point (a.k.a. center point between all
|
||||
* fingers)
|
||||
*
|
||||
* @param e
|
||||
* @return PointF focal point
|
||||
*/
|
||||
private PointF determineFocalPoint(MotionEvent e) {
|
||||
// Number of fingers on screen
|
||||
final int pCount = e.getPointerCount();
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
|
||||
for (int i = 0; i < pCount; i++) {
|
||||
x += e.getX(i);
|
||||
y += e.getY(i);
|
||||
}
|
||||
|
||||
return new PointF(x / pCount, y / pCount);
|
||||
}
|
||||
|
||||
public float getFocusX() {
|
||||
return mFocusExternal.x;
|
||||
}
|
||||
|
||||
public float getFocusY() {
|
||||
return mFocusExternal.y;
|
||||
}
|
||||
|
||||
public PointF getFocusDelta() {
|
||||
return mFocusDeltaExternal;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
package com.almeros.android.multitouch.gesturedetectors;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie
|
||||
* (code.almeros.com)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
|
||||
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
public class RotateGestureDetector extends TwoFingerGestureDetector {
|
||||
|
||||
/**
|
||||
* Listener which must be implemented which is used by RotateGestureDetector
|
||||
* to perform callbacks to any implementing class which is registered to a
|
||||
* RotateGestureDetector via the constructor.
|
||||
*
|
||||
* @see RotateGestureDetector.SimpleOnRotateGestureListener
|
||||
*/
|
||||
public interface OnRotateGestureListener {
|
||||
public boolean onRotate(RotateGestureDetector detector);
|
||||
|
||||
public boolean onRotateBegin(RotateGestureDetector detector);
|
||||
|
||||
public void onRotateEnd(RotateGestureDetector detector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class which may be extended and where the methods may be
|
||||
* implemented. This way it is not necessary to implement all methods of
|
||||
* OnRotateGestureListener.
|
||||
*/
|
||||
public static class SimpleOnRotateGestureListener implements
|
||||
OnRotateGestureListener {
|
||||
public boolean onRotate(RotateGestureDetector detector) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onRotateBegin(RotateGestureDetector detector) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onRotateEnd(RotateGestureDetector detector) {
|
||||
// Do nothing, overridden implementation may be used
|
||||
}
|
||||
}
|
||||
|
||||
private final OnRotateGestureListener mListener;
|
||||
private boolean mSloppyGesture;
|
||||
|
||||
public RotateGestureDetector(Context context,
|
||||
OnRotateGestureListener listener) {
|
||||
super(context);
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleStartProgressEvent(int actionCode, MotionEvent event) {
|
||||
switch (actionCode) {
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
// At least the second finger is on screen now
|
||||
|
||||
resetState(); // In case we missed an UP/CANCEL event
|
||||
mPrevEvent = MotionEvent.obtain(event);
|
||||
mTimeDelta = 0;
|
||||
|
||||
updateStateByEvent(event);
|
||||
|
||||
// See if we have a sloppy gesture
|
||||
mSloppyGesture = isSloppyGesture(event);
|
||||
if (!mSloppyGesture) {
|
||||
// No, start gesture now
|
||||
mGestureInProgress = mListener.onRotateBegin(this);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (!mSloppyGesture) {
|
||||
break;
|
||||
}
|
||||
|
||||
// See if we still have a sloppy gesture
|
||||
mSloppyGesture = isSloppyGesture(event);
|
||||
if (!mSloppyGesture) {
|
||||
// No, start normal gesture now
|
||||
mGestureInProgress = mListener.onRotateBegin(this);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (!mSloppyGesture) {
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleInProgressEvent(int actionCode, MotionEvent event) {
|
||||
switch (actionCode) {
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
// Gesture ended but
|
||||
updateStateByEvent(event);
|
||||
|
||||
if (!mSloppyGesture) {
|
||||
mListener.onRotateEnd(this);
|
||||
}
|
||||
|
||||
resetState();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (!mSloppyGesture) {
|
||||
mListener.onRotateEnd(this);
|
||||
}
|
||||
|
||||
resetState();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
updateStateByEvent(event);
|
||||
|
||||
// Only accept the event if our relative pressure is within
|
||||
// a certain limit. This can help filter shaky data as a
|
||||
// finger is lifted.
|
||||
if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) {
|
||||
final boolean updatePrevious = mListener.onRotate(this);
|
||||
if (updatePrevious) {
|
||||
mPrevEvent.recycle();
|
||||
mPrevEvent = MotionEvent.obtain(event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetState() {
|
||||
super.resetState();
|
||||
mSloppyGesture = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rotation difference from the previous rotate event to the
|
||||
* current event.
|
||||
*
|
||||
* @return The current rotation //difference in degrees.
|
||||
*/
|
||||
public float getRotationDegreesDelta() {
|
||||
double diffRadians = Math.atan2(mPrevFingerDiffY, mPrevFingerDiffX)
|
||||
- Math.atan2(mCurrFingerDiffY, mCurrFingerDiffX);
|
||||
return (float) (diffRadians * 180.0 / Math.PI);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,213 @@
|
||||
package com.almeros.android.multitouch.gesturedetectors;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
/**
|
||||
* @author Robert Nordan (robert.nordan@norkart.no)
|
||||
*
|
||||
* Copyright (c) 2013, Norkart AS
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
|
||||
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
public class ShoveGestureDetector extends TwoFingerGestureDetector {
|
||||
|
||||
/**
|
||||
* Listener which must be implemented which is used by ShoveGestureDetector
|
||||
* to perform callbacks to any implementing class which is registered to a
|
||||
* ShoveGestureDetector via the constructor.
|
||||
*
|
||||
* @see ShoveGestureDetector.SimpleOnShoveGestureListener
|
||||
*/
|
||||
public interface OnShoveGestureListener {
|
||||
public boolean onShove(ShoveGestureDetector detector);
|
||||
|
||||
public boolean onShoveBegin(ShoveGestureDetector detector);
|
||||
|
||||
public void onShoveEnd(ShoveGestureDetector detector);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class which may be extended and where the methods may be
|
||||
* implemented. This way it is not necessary to implement all methods of
|
||||
* OnShoveGestureListener.
|
||||
*/
|
||||
public static class SimpleOnShoveGestureListener implements
|
||||
OnShoveGestureListener {
|
||||
public boolean onShove(ShoveGestureDetector detector) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onShoveBegin(ShoveGestureDetector detector) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onShoveEnd(ShoveGestureDetector detector) {
|
||||
// Do nothing, overridden implementation may be used
|
||||
}
|
||||
}
|
||||
|
||||
private float mPrevAverageY;
|
||||
private float mCurrAverageY;
|
||||
|
||||
private final OnShoveGestureListener mListener;
|
||||
private boolean mSloppyGesture;
|
||||
|
||||
public ShoveGestureDetector(Context context, OnShoveGestureListener listener) {
|
||||
super(context);
|
||||
mListener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleStartProgressEvent(int actionCode, MotionEvent event) {
|
||||
switch (actionCode) {
|
||||
case MotionEvent.ACTION_POINTER_DOWN:
|
||||
// At least the second finger is on screen now
|
||||
|
||||
resetState(); // In case we missed an UP/CANCEL event
|
||||
mPrevEvent = MotionEvent.obtain(event);
|
||||
mTimeDelta = 0;
|
||||
|
||||
updateStateByEvent(event);
|
||||
|
||||
// See if we have a sloppy gesture
|
||||
mSloppyGesture = isSloppyGesture(event);
|
||||
if (!mSloppyGesture) {
|
||||
// No, start gesture now
|
||||
mGestureInProgress = mListener.onShoveBegin(this);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (!mSloppyGesture) {
|
||||
break;
|
||||
}
|
||||
|
||||
// See if we still have a sloppy gesture
|
||||
mSloppyGesture = isSloppyGesture(event);
|
||||
if (!mSloppyGesture) {
|
||||
// No, start normal gesture now
|
||||
mGestureInProgress = mListener.onShoveBegin(this);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
if (!mSloppyGesture) {
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleInProgressEvent(int actionCode, MotionEvent event) {
|
||||
switch (actionCode) {
|
||||
case MotionEvent.ACTION_POINTER_UP:
|
||||
// Gesture ended but
|
||||
updateStateByEvent(event);
|
||||
|
||||
if (!mSloppyGesture) {
|
||||
mListener.onShoveEnd(this);
|
||||
}
|
||||
|
||||
resetState();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
if (!mSloppyGesture) {
|
||||
mListener.onShoveEnd(this);
|
||||
}
|
||||
|
||||
resetState();
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
updateStateByEvent(event);
|
||||
|
||||
// Only accept the event if our relative pressure is within
|
||||
// a certain limit. This can help filter shaky data as a
|
||||
// finger is lifted. Also check that shove is meaningful.
|
||||
if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD
|
||||
&& Math.abs(getShovePixelsDelta()) > 0.5f) {
|
||||
final boolean updatePrevious = mListener.onShove(this);
|
||||
if (updatePrevious) {
|
||||
mPrevEvent.recycle();
|
||||
mPrevEvent = MotionEvent.obtain(event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void resetState() {
|
||||
super.resetState();
|
||||
mSloppyGesture = false;
|
||||
mPrevAverageY = 0.0f;
|
||||
mCurrAverageY = 0.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateStateByEvent(MotionEvent curr) {
|
||||
super.updateStateByEvent(curr);
|
||||
|
||||
final MotionEvent prev = mPrevEvent;
|
||||
float py0 = prev.getY(0);
|
||||
float py1 = prev.getY(1);
|
||||
mPrevAverageY = (py0 + py1) / 2.0f;
|
||||
|
||||
float cy0 = curr.getY(0);
|
||||
float cy1 = curr.getY(1);
|
||||
mCurrAverageY = (cy0 + cy1) / 2.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isSloppyGesture(MotionEvent event) {
|
||||
boolean sloppy = super.isSloppyGesture(event);
|
||||
if (sloppy)
|
||||
return true;
|
||||
|
||||
// If it's not traditionally sloppy, we check if the angle between
|
||||
// fingers
|
||||
// is acceptable.
|
||||
double angle = Math.abs(Math.atan2(mCurrFingerDiffY, mCurrFingerDiffX));
|
||||
// about 20 degrees, left or right
|
||||
return !((0.0f < angle && angle < 0.35f) || 2.79f < angle
|
||||
&& angle < Math.PI);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the distance in pixels from the previous shove event to the
|
||||
* current event.
|
||||
*
|
||||
* @return The current distance in pixels.
|
||||
*/
|
||||
public float getShovePixelsDelta() {
|
||||
return mCurrAverageY - mPrevAverageY;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
package com.almeros.android.multitouch.gesturedetectors;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.PointF;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.ViewConfiguration;
|
||||
|
||||
/**
|
||||
* @author Almer Thie (code.almeros.com) Copyright (c) 2013, Almer Thie
|
||||
* (code.almeros.com)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
|
||||
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
public abstract class TwoFingerGestureDetector extends BaseGestureDetector {
|
||||
|
||||
private final float mEdgeSlop;
|
||||
|
||||
protected float mPrevFingerDiffX;
|
||||
protected float mPrevFingerDiffY;
|
||||
protected float mCurrFingerDiffX;
|
||||
protected float mCurrFingerDiffY;
|
||||
|
||||
private float mCurrLen;
|
||||
private float mPrevLen;
|
||||
|
||||
private PointF mFocus;
|
||||
|
||||
public TwoFingerGestureDetector(Context context) {
|
||||
super(context);
|
||||
|
||||
ViewConfiguration config = ViewConfiguration.get(context);
|
||||
mEdgeSlop = config.getScaledEdgeSlop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected abstract void handleStartProgressEvent(int actionCode,
|
||||
MotionEvent event);
|
||||
|
||||
@Override
|
||||
protected abstract void handleInProgressEvent(int actionCode,
|
||||
MotionEvent event);
|
||||
|
||||
protected void updateStateByEvent(MotionEvent curr) {
|
||||
super.updateStateByEvent(curr);
|
||||
|
||||
final MotionEvent prev = mPrevEvent;
|
||||
|
||||
mCurrLen = -1;
|
||||
mPrevLen = -1;
|
||||
|
||||
// Previous
|
||||
final float px0 = prev.getX(0);
|
||||
final float py0 = prev.getY(0);
|
||||
final float px1 = prev.getX(1);
|
||||
final float py1 = prev.getY(1);
|
||||
final float pvx = px1 - px0;
|
||||
final float pvy = py1 - py0;
|
||||
mPrevFingerDiffX = pvx;
|
||||
mPrevFingerDiffY = pvy;
|
||||
|
||||
// Current
|
||||
final float cx0 = curr.getX(0);
|
||||
final float cy0 = curr.getY(0);
|
||||
final float cx1 = curr.getX(1);
|
||||
final float cy1 = curr.getY(1);
|
||||
final float cvx = cx1 - cx0;
|
||||
final float cvy = cy1 - cy0;
|
||||
mCurrFingerDiffX = cvx;
|
||||
mCurrFingerDiffY = cvy;
|
||||
mFocus = determineFocalPoint(curr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the current distance between the two pointers forming the gesture
|
||||
* in progress.
|
||||
*
|
||||
* @return Distance between pointers in pixels.
|
||||
*/
|
||||
public float getCurrentSpan() {
|
||||
if (mCurrLen == -1) {
|
||||
final float cvx = mCurrFingerDiffX;
|
||||
final float cvy = mCurrFingerDiffY;
|
||||
mCurrLen = (float) Math.sqrt(cvx * cvx + cvy * cvy);
|
||||
}
|
||||
return mCurrLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the previous distance between the two pointers forming the gesture
|
||||
* in progress.
|
||||
*
|
||||
* @return Previous distance between pointers in pixels.
|
||||
*/
|
||||
public float getPreviousSpan() {
|
||||
if (mPrevLen == -1) {
|
||||
final float pvx = mPrevFingerDiffX;
|
||||
final float pvy = mPrevFingerDiffY;
|
||||
mPrevLen = (float) Math.sqrt(pvx * pvx + pvy * pvy);
|
||||
}
|
||||
return mPrevLen;
|
||||
}
|
||||
|
||||
/**
|
||||
* MotionEvent has no getRawX(int) method; simulate it pending future API
|
||||
* approval.
|
||||
*
|
||||
* @param event Motion Event
|
||||
* @param pointerIndex Pointer Index
|
||||
* @return Raw x value or 0
|
||||
*/
|
||||
protected static float getRawX(MotionEvent event, int pointerIndex) {
|
||||
float offset = event.getX() - event.getRawX();
|
||||
if (pointerIndex < event.getPointerCount()) {
|
||||
return event.getX(pointerIndex) + offset;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* MotionEvent has no getRawY(int) method; simulate it pending future API
|
||||
* approval.
|
||||
*
|
||||
* @param event Motion Event
|
||||
* @param pointerIndex Pointer Index
|
||||
* @return Raw y value or 0
|
||||
*/
|
||||
protected static float getRawY(MotionEvent event, int pointerIndex) {
|
||||
float offset = event.getY() - event.getRawY();
|
||||
if (pointerIndex < event.getPointerCount()) {
|
||||
return event.getY(pointerIndex) + offset;
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if we have a sloppy gesture. Sloppy gestures can happen if the edge
|
||||
* of the user's hand is touching the screen, for example.
|
||||
*
|
||||
* @param event Motion Event
|
||||
* @return {@code true} if is sloppy gesture, {@code false} if not
|
||||
*/
|
||||
protected boolean isSloppyGesture(MotionEvent event) {
|
||||
// As orientation can change, query the metrics in touch down
|
||||
DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
|
||||
float mRightSlopEdge = metrics.widthPixels - mEdgeSlop;
|
||||
float mBottomSlopEdge = metrics.heightPixels - mEdgeSlop;
|
||||
|
||||
final float edgeSlop = mEdgeSlop;
|
||||
|
||||
final float x0 = event.getRawX();
|
||||
final float y0 = event.getRawY();
|
||||
final float x1 = getRawX(event, 1);
|
||||
final float y1 = getRawY(event, 1);
|
||||
|
||||
boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop || x0 > mRightSlopEdge
|
||||
|| y0 > mBottomSlopEdge;
|
||||
boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > mRightSlopEdge
|
||||
|| y1 > mBottomSlopEdge;
|
||||
|
||||
if (p0sloppy && p1sloppy) {
|
||||
return true;
|
||||
} else if (p0sloppy) {
|
||||
return true;
|
||||
} else if (p1sloppy) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine (multi)finger focal point (a.k.a. center point between all
|
||||
* fingers)
|
||||
*
|
||||
* @param e Motion Event
|
||||
* @return PointF focal point
|
||||
*/
|
||||
public static PointF determineFocalPoint(MotionEvent e) {
|
||||
// Number of fingers on screen
|
||||
final int pCount = e.getPointerCount();
|
||||
float x = 0.0f;
|
||||
float y = 0.0f;
|
||||
|
||||
for (int i = 0; i < pCount; i++) {
|
||||
x += e.getX(i);
|
||||
y += e.getY(i);
|
||||
}
|
||||
|
||||
return new PointF(x / pCount, y / pCount);
|
||||
}
|
||||
|
||||
public float getFocusX() {
|
||||
return mFocus.x;
|
||||
}
|
||||
|
||||
public float getFocusY() {
|
||||
return mFocus.y;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import com.mapbox.mapboxgl.views.MapView;
|
||||
|
||||
|
||||
public abstract class Annotation {
|
||||
|
||||
/**
|
||||
* The annotation id
|
||||
*
|
||||
* Internal C++ id is stored as unsigned int.
|
||||
*/
|
||||
protected long id = -1; // -1 unless added to a MapView
|
||||
private MapView mapView;
|
||||
|
||||
float alpha = 1.0f;
|
||||
boolean visible = true;
|
||||
|
||||
public Annotation() {}
|
||||
|
||||
public float getAlpha() {
|
||||
return alpha;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
public void remove() {
|
||||
if (mapView == null) return;
|
||||
mapView.removeAnnotation(this);
|
||||
}
|
||||
|
||||
public void setAlpha(float alpha) {
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public void setMapView(MapView mapView) {
|
||||
this.mapView = mapView;
|
||||
}
|
||||
|
||||
public void setVisible(boolean visible) {
|
||||
this.visible = visible;
|
||||
}
|
||||
|
||||
// TODO: Implement getZIndex of Google Maps Android API
|
||||
// public float getZIndex() {
|
||||
//
|
||||
// }
|
||||
|
||||
// TODO: Implement setZIndex of Google Maps Android API
|
||||
// public void setZIndex(float zIndex) {
|
||||
//
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
public abstract class AnnotationOptions {
|
||||
|
||||
protected Annotation annotation;
|
||||
|
||||
public AnnotationOptions() {}
|
||||
|
||||
public AnnotationOptions alpha(float alpha) {
|
||||
annotation.alpha = alpha;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
return annotation.alpha;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return annotation.visible;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
*
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1882
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1726
|
||||
*/
|
||||
public class Circle extends Annotation {
|
||||
|
||||
LatLng center;
|
||||
int fillColor = Color.BLACK;
|
||||
double radius;
|
||||
int strokeColor = Color.BLACK;
|
||||
float strokeWidth = 10; // Google Maps API defaults to 10
|
||||
|
||||
public LatLng getCenter() {
|
||||
return center;
|
||||
}
|
||||
|
||||
public int getFillColor() {
|
||||
return fillColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the circle's radius, in meters.
|
||||
*
|
||||
* @return radius in meters
|
||||
*/
|
||||
public double getRadius() {
|
||||
return radius;
|
||||
}
|
||||
|
||||
public int getStrokeColor() {
|
||||
return strokeColor;
|
||||
}
|
||||
|
||||
public float getStrokeWidth() {
|
||||
return strokeWidth;
|
||||
}
|
||||
|
||||
public void setCenter(LatLng center) {
|
||||
this.center = center;
|
||||
}
|
||||
|
||||
public void setFillColor(int color) {
|
||||
fillColor = color;
|
||||
}
|
||||
|
||||
public void setRadius(double radius) {
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public void setStrokeColor (int color) {
|
||||
strokeColor = color;
|
||||
}
|
||||
|
||||
public void setStrokeWidth (float width) {
|
||||
strokeWidth = width;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
*
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1882
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1726
|
||||
*/
|
||||
public class CircleOptions extends AnnotationOptions {
|
||||
|
||||
private Circle circle;
|
||||
|
||||
public CircleOptions() {
|
||||
circle = new Circle();
|
||||
}
|
||||
public CircleOptions center(LatLng center) {
|
||||
circle.center = center;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CircleOptions fillColor(int color) {
|
||||
circle.fillColor = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LatLng getCenter() {
|
||||
return circle.center;
|
||||
}
|
||||
|
||||
public int getFillColor() {
|
||||
return circle.fillColor;
|
||||
}
|
||||
|
||||
public double getRadius() {
|
||||
return circle.radius;
|
||||
}
|
||||
|
||||
public int getStrokeColor () {
|
||||
return circle.strokeColor;
|
||||
}
|
||||
|
||||
public float getStrokeWidth() {
|
||||
return circle.strokeWidth;
|
||||
}
|
||||
|
||||
public CircleOptions radius (double radius) {
|
||||
circle.radius = radius;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CircleOptions strokeColor(int color) {
|
||||
circle.strokeColor = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public CircleOptions strokeWidth (float width) {
|
||||
circle.strokeWidth = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
|
||||
public class Marker extends Annotation {
|
||||
|
||||
float anchorU;
|
||||
float anchorV;
|
||||
boolean draggable;
|
||||
boolean flat;
|
||||
float infoWindowAnchorU;
|
||||
float infoWindowAnchorV;
|
||||
LatLng position;
|
||||
float rotation;
|
||||
String snippet;
|
||||
String sprite = "default_marker";
|
||||
String title;
|
||||
|
||||
private boolean infoWindowShown = false;
|
||||
|
||||
public Marker() {}
|
||||
|
||||
/**
|
||||
* If two markers have the same LatLng, they are equal.
|
||||
*
|
||||
* @param other object
|
||||
* @return boolean - do they have the same LatLng
|
||||
*/
|
||||
public boolean equals(Object other) {
|
||||
if (!(other instanceof Marker)) return false;
|
||||
double lat = position.getLatitude();
|
||||
double lng = position.getLongitude();
|
||||
LatLng otherPosition = ((Marker)other).getPosition();
|
||||
double otherLat = otherPosition.getLatitude();
|
||||
double otherLng = otherPosition.getLongitude();
|
||||
return (lat == otherLat && otherLng == lng);
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
return alpha;
|
||||
}
|
||||
|
||||
public float getAnchorU() {
|
||||
return anchorU;
|
||||
}
|
||||
|
||||
public float getAnchorV() {
|
||||
return anchorV;
|
||||
}
|
||||
|
||||
public LatLng getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public float getRotation() {
|
||||
return rotation;
|
||||
}
|
||||
|
||||
public String getSnippet() {
|
||||
return snippet;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void hideInfoWindow() {
|
||||
//TODO hideInfoWindow
|
||||
infoWindowShown = false;
|
||||
}
|
||||
|
||||
public boolean isDraggable() {
|
||||
return draggable;
|
||||
}
|
||||
|
||||
public boolean isFlat() {
|
||||
return flat;
|
||||
}
|
||||
|
||||
public boolean isInfoWindowShown () {
|
||||
return infoWindowShown;
|
||||
}
|
||||
|
||||
void setAnchor(float u, float v) {
|
||||
this.anchorU = u;
|
||||
this.anchorV = v;
|
||||
}
|
||||
|
||||
void setDraggable(boolean draggable) {
|
||||
this.draggable = draggable;
|
||||
}
|
||||
|
||||
void setFlat(boolean flat) {
|
||||
this.flat = flat;
|
||||
}
|
||||
|
||||
void setInfoWindowAnchor(float u, float v) {
|
||||
infoWindowAnchorU = u;
|
||||
infoWindowAnchorV = v;
|
||||
}
|
||||
|
||||
void setPosition(LatLng latlng) {
|
||||
this.position = position;
|
||||
}
|
||||
|
||||
void setRotation(float rotation) {
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
void setSnippet(String snippet) {
|
||||
this.snippet = snippet;
|
||||
}
|
||||
|
||||
/**
|
||||
* You can specify the name of a sprite to get a marker other than the default marker.
|
||||
* This name can be found in the sprite json file:
|
||||
*
|
||||
* https://github.com/mapbox/mapbox-gl-styles/blob/mb-pages/sprites/mapbox-streets.json
|
||||
*
|
||||
* @param sprite
|
||||
*/
|
||||
void setSprite(String sprite) {
|
||||
this.sprite = sprite;
|
||||
}
|
||||
|
||||
void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
void showInfoWindow() {
|
||||
infoWindowShown = true;
|
||||
}
|
||||
|
||||
|
||||
// TODO Method in Google Maps Android API
|
||||
// public int hashCode()
|
||||
|
||||
// TODO: Implement this method of Google Maps Android API
|
||||
// void setIcon(BitmapDescriptor icon) {
|
||||
//
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
public class MarkerOptions extends AnnotationOptions {
|
||||
|
||||
public MarkerOptions() {
|
||||
annotation = new Marker();
|
||||
}
|
||||
|
||||
public MarkerOptions anchor(float u, float v) {
|
||||
((Marker)annotation).anchorU = u;
|
||||
((Marker)annotation).anchorV = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkerOptions draggable(boolean draggable) {
|
||||
((Marker)annotation).draggable = draggable;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkerOptions flat(boolean flat) {
|
||||
((Marker)annotation).flat = flat;
|
||||
return this;
|
||||
}
|
||||
|
||||
public float getAnchorU() {
|
||||
return ((Marker)annotation).anchorU;
|
||||
}
|
||||
|
||||
public float getAnchorV() {
|
||||
return ((Marker)annotation).anchorV;
|
||||
}
|
||||
|
||||
// TODO: Implement this method of Google Maps Android API
|
||||
// public BitmapDescriptor getIcon () {
|
||||
//
|
||||
// }
|
||||
|
||||
public float getInfoWindowAnchorU() {
|
||||
return ((Marker)annotation).infoWindowAnchorU;
|
||||
}
|
||||
|
||||
public float getInfoWindowAnchorV() {
|
||||
return ((Marker)annotation).infoWindowAnchorV;
|
||||
}
|
||||
|
||||
public Marker getMarker() {
|
||||
return (Marker)annotation;
|
||||
}
|
||||
|
||||
public LatLng getPosition() {
|
||||
return ((Marker)annotation).position;
|
||||
}
|
||||
|
||||
public float getRotation() {
|
||||
return ((Marker)annotation).rotation;
|
||||
}
|
||||
|
||||
public String getSnippet() {
|
||||
return ((Marker)annotation).snippet;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return ((Marker)annotation).title;
|
||||
}
|
||||
|
||||
public MarkerOptions infoWindowAnchor(float u, float v) {
|
||||
((Marker)annotation).infoWindowAnchorU = u;
|
||||
((Marker)annotation).infoWindowAnchorV = v;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isDraggable() {
|
||||
return ((Marker)annotation).draggable;
|
||||
}
|
||||
|
||||
public boolean isFlat() {
|
||||
return ((Marker)annotation).flat;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return ((Marker)annotation).visible;
|
||||
}
|
||||
|
||||
public MarkerOptions position(LatLng position) {
|
||||
((Marker)annotation).position = position;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkerOptions rotation(float rotation) {
|
||||
((Marker)annotation).rotation = rotation;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkerOptions snippet(String snippet) {
|
||||
((Marker)annotation).snippet = snippet;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkerOptions sprite(String sprite) {
|
||||
((Marker)annotation).sprite = sprite;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkerOptions title(String title) {
|
||||
((Marker)annotation).title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MarkerOptions visible(boolean visible) {
|
||||
annotation.visible = visible;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Implement this method of Google Maps Android API
|
||||
// public MarkerOptions icon(BitmapDescriptor icon) {
|
||||
//
|
||||
// }
|
||||
|
||||
// TODO: Implement this method of Google Maps Android API
|
||||
// public void writeToParcel (Parcel out, int flags)
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class MultiPoint extends Annotation {
|
||||
|
||||
List<LatLng> points;
|
||||
|
||||
public MultiPoint() {
|
||||
super();
|
||||
points = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the points.
|
||||
*
|
||||
* @return points - as a copy
|
||||
*/
|
||||
public List<LatLng> getPoints() {
|
||||
return new ArrayList<>(points);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the points of this polyline. This method will take a copy
|
||||
* of the points, so further mutations to points will have no effect
|
||||
* on this polyline.
|
||||
*
|
||||
* @param points
|
||||
*/
|
||||
void setPoints(List<LatLng> points) {
|
||||
this.points = new ArrayList<>(points);
|
||||
}
|
||||
|
||||
|
||||
// TODO: Implement hashCode of Google Maps Android API
|
||||
// public int hashCode() {
|
||||
//
|
||||
// }
|
||||
|
||||
// TODO: Implement isGeodesic of Google Maps Android API
|
||||
// public boolean isGeodesic() {
|
||||
//
|
||||
// }
|
||||
|
||||
// TODO: Implement setGeodesic of Google Maps Android API
|
||||
// public void setGeodesic(boolean geodesic) {
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class MultiPointOptions extends AnnotationOptions {
|
||||
|
||||
public MultiPointOptions() {}
|
||||
|
||||
public List<LatLng> getPoints() {
|
||||
// the getter gives us a copy, which is the safe thing to do...
|
||||
return ((MultiPoint)annotation).getPoints();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class Polygon extends MultiPoint {
|
||||
|
||||
int fillColor = Color.BLACK; // default fillColor is black
|
||||
float strokeAlpha = 1;
|
||||
int strokeColor = Color.BLACK; // default strokeColor is black
|
||||
float strokeWidth = 10; // As specified by Google API Docs (in pixels)
|
||||
|
||||
List<List<LatLng>> holes;
|
||||
|
||||
public Polygon() {
|
||||
super();
|
||||
holes = new ArrayList<>();
|
||||
}
|
||||
|
||||
public int getFillColor() {
|
||||
return fillColor;
|
||||
}
|
||||
|
||||
public List<List<LatLng>> getHoles () {
|
||||
return holes;
|
||||
}
|
||||
|
||||
public int getStrokeColor() {
|
||||
return strokeColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1737
|
||||
* @return stroke width as float
|
||||
*/
|
||||
public float getStrokeWidth() {
|
||||
return strokeWidth;
|
||||
}
|
||||
|
||||
public void setFillAlpha(float alpha) {
|
||||
this.alpha = alpha;
|
||||
}
|
||||
|
||||
public void setFillColor(int color) {
|
||||
fillColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the holes of this polygon. This method will take a copy of the holes,
|
||||
* so further mutations to holes parameter will have no effect on this polygon.
|
||||
*
|
||||
* @param holes
|
||||
*/
|
||||
public void setHoles(List<? extends List<LatLng>> holes) {
|
||||
this.holes = new ArrayList<>();
|
||||
for (List<LatLng> hole : holes) {
|
||||
this.holes.add(new ArrayList<>(hole));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the alpha (opacity) of the stroke
|
||||
*
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
*/
|
||||
public void setStrokeAlpha(float alpha) {
|
||||
strokeAlpha = alpha;
|
||||
}
|
||||
|
||||
public void setStrokeColor(int color) {
|
||||
strokeColor = color;
|
||||
}
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1737
|
||||
* @return stroke width as float
|
||||
*/
|
||||
public void setStrokeWidth(float width) {
|
||||
strokeWidth = width;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Implement equals of Google Maps Android API
|
||||
// public boolean equals (Object other) {
|
||||
//
|
||||
// }
|
||||
|
||||
// TODO: Implement hashCode of Google Maps Android API
|
||||
// public int hashCode () {
|
||||
//
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class PolygonOptions extends MultiPointOptions {
|
||||
|
||||
public PolygonOptions() {
|
||||
annotation = new Polygon();
|
||||
}
|
||||
|
||||
public PolygonOptions add(LatLng point) {
|
||||
((MultiPoint)annotation).points.add(point);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PolygonOptions add(LatLng... points) {
|
||||
for (LatLng point : points) {
|
||||
add(point);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public PolygonOptions addAll(Iterable<LatLng> points) {
|
||||
for (LatLng point : points) {
|
||||
add(point);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1729
|
||||
*
|
||||
* @param points - an iterable (list) of points for cutting a hole
|
||||
* @return PolygonOptions - the options object
|
||||
*/
|
||||
public PolygonOptions addHole (Iterable<LatLng> points) {
|
||||
List<LatLng> hole = new ArrayList<>();
|
||||
for (LatLng point : points) {
|
||||
hole.add(point);
|
||||
}
|
||||
((Polygon)annotation).holes.add(hole);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the polygon.
|
||||
*
|
||||
* @param color - the color in ARGB format
|
||||
* @return PolygonOptions - the options object
|
||||
*/
|
||||
public PolygonOptions fillColor(int color) {
|
||||
((Polygon)annotation).fillColor = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getFillColor() {
|
||||
return ((Polygon)annotation).fillColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1729
|
||||
*
|
||||
* @return a list of lists of points for cutting holes
|
||||
*/
|
||||
public List<List<LatLng>> getHoles() {
|
||||
return ((Polygon)annotation).holes;
|
||||
}
|
||||
|
||||
public Polygon getPolygon() {
|
||||
return ((Polygon)annotation);
|
||||
}
|
||||
|
||||
public int getStrokeColor() {
|
||||
return ((Polygon)annotation).strokeColor;
|
||||
}
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1737
|
||||
*
|
||||
* @return stroke width as float
|
||||
*/
|
||||
public float getStrokeWidth() {
|
||||
return ((Polygon)annotation).strokeWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the stroke of the polygon.
|
||||
*
|
||||
* @param color - the color in ARGB format
|
||||
* @return PolygonOptions - the options object
|
||||
*/
|
||||
public PolygonOptions strokeColor(int color) {
|
||||
((Polygon)annotation).strokeColor = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* UNIMPLEMENTED: Needs implementation in Native.
|
||||
* https://github.com/mapbox/mapbox-gl-native/issues/1737
|
||||
*
|
||||
* @return stroke width as float
|
||||
*/
|
||||
public PolygonOptions strokeWidth(float width) {
|
||||
((Polygon)annotation).strokeWidth = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
public PolygonOptions visible(boolean visible) {
|
||||
annotation.visible = visible;
|
||||
return this;
|
||||
}
|
||||
|
||||
// TODO: Implement writeToParcel of Google Maps Android API
|
||||
// public void writeToParcel(Parcel out, int flags) {
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import android.graphics.Color;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Polyline extends MultiPoint {
|
||||
|
||||
int color = Color.BLACK; // default color is black
|
||||
float width = 10; // As specified by Google API Docs (in pixels)
|
||||
|
||||
public Polyline() {
|
||||
super();
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the color of the polyline.
|
||||
*
|
||||
* @param color - the color in ARGB format
|
||||
*/
|
||||
public void setColor(int color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the width of the polyline.
|
||||
*
|
||||
* @param width in pixels
|
||||
* @return
|
||||
*/
|
||||
public void setWidth(float width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
// TODO: Implement equals of Google Maps Android API
|
||||
// public boolean equals(Object other) {
|
||||
//
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package com.mapbox.mapboxgl.annotations;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PolylineOptions extends MultiPointOptions {
|
||||
|
||||
public PolylineOptions() {
|
||||
annotation = new Polyline();
|
||||
}
|
||||
|
||||
public PolylineOptions add(LatLng point) {
|
||||
((MultiPoint)annotation).points.add(point);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PolylineOptions add(LatLng... points) {
|
||||
for (LatLng point : points) {
|
||||
add(point);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public PolylineOptions addAll(Iterable<LatLng> points) {
|
||||
for (LatLng point : points) {
|
||||
add(point);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the color of the polyline.
|
||||
*
|
||||
* @param color - the color in ARGB format
|
||||
*/
|
||||
public PolylineOptions color(int color) {
|
||||
((Polyline)annotation).color = color;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return ((Polyline)annotation).color;
|
||||
}
|
||||
|
||||
public Polyline getPolyline() {
|
||||
return ((Polyline)annotation);
|
||||
}
|
||||
|
||||
public float getWidth() {
|
||||
return ((Polyline)annotation).width;
|
||||
}
|
||||
|
||||
public PolylineOptions visible(boolean visible) {
|
||||
annotation.visible = visible;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the width of the polyline.
|
||||
*
|
||||
* @param width in pixels
|
||||
* @return
|
||||
*/
|
||||
public PolylineOptions width(float width) {
|
||||
((Polyline)annotation).width = width;
|
||||
return this;
|
||||
}
|
||||
|
||||
// TODO: Implement writeToParcel of Google Maps Android API
|
||||
// public void writeToParcel(Parcel out, int flags) {
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.mapbox.mapboxgl.constants;
|
||||
|
||||
public class GeoConstants {
|
||||
// http://en.wikipedia.org/wiki/Earth_radius#Equatorial_radius
|
||||
public static final int RADIUS_EARTH_METERS = 6378137;
|
||||
public static final double MIN_LATITUDE = -85.05112878;
|
||||
public static final double MAX_LATITUDE = 85.05112878;
|
||||
public static final double MIN_LONGITUDE = -180;
|
||||
public static final double MAX_LONGITUDE = 180;
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.mapbox.mapboxgl.constants;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class MapboxConstants {
|
||||
|
||||
// Default Locale for data processing (ex: String.toLowerCase(MAPBOX_LOCALE, "foo"))
|
||||
public static final Locale MAPBOX_LOCALE = Locale.US;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.mapbox.mapboxgl.constants;
|
||||
|
||||
public class MathConstants {
|
||||
public static final double DEG2RAD = (Math.PI / 180.0);
|
||||
public static final double RAD2DEG = (180.0 / Math.PI);
|
||||
|
||||
public static final double PI = Math.PI;
|
||||
}
|
||||
@@ -0,0 +1,273 @@
|
||||
package com.mapbox.mapboxgl.geometry;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A rectangular geographical area defined in latitude and longitude units.
|
||||
*/
|
||||
public final class BoundingBox implements Parcelable, Serializable {
|
||||
|
||||
private final double mLatNorth;
|
||||
private final double mLatSouth;
|
||||
private final double mLonEast;
|
||||
private final double mLonWest;
|
||||
|
||||
private final boolean mIsValid;
|
||||
|
||||
/**
|
||||
* Construct a new bounding box based on its corners, given in NESW
|
||||
* order.
|
||||
*
|
||||
* @param north Northern Coordinate
|
||||
* @param east Eastern Coordinate
|
||||
* @param south Southern Coordinate
|
||||
* @param west Western Coordinate
|
||||
*/
|
||||
public BoundingBox(final double north, final double east, final double south, final double west) {
|
||||
this.mLatNorth = north;
|
||||
this.mLonEast = east;
|
||||
this.mLatSouth = south;
|
||||
this.mLonWest = west;
|
||||
this.mIsValid = ((this.mLonWest < this.mLonEast) && (this.mLatNorth > this.mLatSouth));
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new bounding box based on its corners, given in NESW
|
||||
* order.
|
||||
*
|
||||
* @param northEast Coordinate
|
||||
* @param southWest Coordinate
|
||||
*/
|
||||
public BoundingBox(final LatLng northEast, final LatLng southWest) {
|
||||
this(northEast.getLatitude(), northEast.getLongitude(), southWest.getLatitude(), southWest.getLongitude());
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a bounding box from another bounding box
|
||||
*
|
||||
* @param other the other bounding box
|
||||
*/
|
||||
public BoundingBox(final BoundingBox other) {
|
||||
this.mLatNorth = other.getLatNorth();
|
||||
this.mLonEast = other.getLonEast();
|
||||
this.mLatSouth = other.getLatSouth();
|
||||
this.mLonWest = other.getLonWest();
|
||||
this.mIsValid = other.isValid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new BoundingBox with no size centered at 0, 0, also known as null island
|
||||
*/
|
||||
public BoundingBox() {
|
||||
this(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the centerpoint of this bounding box by simple interpolation and returns
|
||||
* it as a point. This is a non-geodesic calculation which is not the geographic center.
|
||||
*
|
||||
* @return LatLng center of this BoundingBox
|
||||
*/
|
||||
public LatLng getCenter() {
|
||||
return new LatLng((this.mLatNorth + this.mLatSouth) / 2,
|
||||
(this.mLonEast + this.mLonWest) / 2);
|
||||
}
|
||||
|
||||
public double getLatNorth() {
|
||||
return this.mLatNorth;
|
||||
}
|
||||
|
||||
public double getLatSouth() {
|
||||
return this.mLatSouth;
|
||||
}
|
||||
|
||||
public double getLonEast() {
|
||||
return this.mLonEast;
|
||||
}
|
||||
|
||||
public double getLonWest() {
|
||||
return this.mLonWest;
|
||||
}
|
||||
|
||||
public boolean isValid() {
|
||||
return this.mIsValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the absolute distance, in degrees, between the north and
|
||||
* south boundaries of this bounding box
|
||||
*
|
||||
* @return Span distance
|
||||
*/
|
||||
public double getLatitudeSpan() {
|
||||
return Math.abs(this.mLatNorth - this.mLatSouth);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the absolute distance, in degrees, between the west and
|
||||
* east boundaries of this bounding box
|
||||
*
|
||||
* @return Span distance
|
||||
*/
|
||||
public double getLongitudeSpan() {
|
||||
return Math.abs(this.mLonEast - this.mLonWest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "N:" + this.mLatNorth + "; E:" + this.mLonEast + "; S:" + this.mLatSouth + "; W:" + this.mLonWest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a bounding box that contains all of a list of LatLng
|
||||
* objects. Empty lists will yield invalid bounding boxes.
|
||||
*
|
||||
* @param latLngs List of LatLng objects
|
||||
* @return BoundingBox
|
||||
*/
|
||||
public static BoundingBox fromLatLngs(final List<? extends ILatLng> latLngs) {
|
||||
double minLat = 90,
|
||||
minLon = 180,
|
||||
maxLat = -90,
|
||||
maxLon = -180;
|
||||
|
||||
for (final ILatLng gp : latLngs) {
|
||||
final double latitude = gp.getLatitude();
|
||||
final double longitude = gp.getLongitude();
|
||||
|
||||
minLat = Math.min(minLat, latitude);
|
||||
minLon = Math.min(minLon, longitude);
|
||||
maxLat = Math.max(maxLat, latitude);
|
||||
maxLon = Math.max(maxLon, longitude);
|
||||
}
|
||||
|
||||
return new BoundingBox(maxLat, maxLon, minLat, minLon);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this bounding box matches another one via coordinates.
|
||||
*
|
||||
* @param other another bounding box
|
||||
* @return a boolean indicating whether the bounding boxes are equal
|
||||
*/
|
||||
public boolean equals(final BoundingBox other) {
|
||||
|
||||
return other != null && (other == this || mLatNorth == other.getLatNorth() && mLatSouth == other.getLatSouth() && mLonEast == other.getLonEast() && mLonWest == other.getLonWest());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether this bounding box contains a point and the point
|
||||
* does not touch its boundary.
|
||||
*
|
||||
* @param pGeoPoint the point which may be contained
|
||||
* @return true, if the point is contained within the box.
|
||||
*/
|
||||
public boolean contains(final ILatLng pGeoPoint) {
|
||||
final double latitude = pGeoPoint.getLatitude();
|
||||
final double longitude = pGeoPoint.getLongitude();
|
||||
return ((latitude < this.mLatNorth) && (latitude > this.mLatSouth)) && ((longitude
|
||||
< this.mLonEast) && (longitude > this.mLonWest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new BoundingBox that stretches to contain both this and another BoundingBox.
|
||||
*
|
||||
* @param box BoundingBox to add
|
||||
* @return BoundingBox
|
||||
*/
|
||||
public BoundingBox union(BoundingBox box) {
|
||||
return union(box.getLatNorth(), box.getLonEast(), box.getLatSouth(), box.getLonWest());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new BoundingBox that stretches to include another bounding box,
|
||||
* given by corner points.
|
||||
*
|
||||
* @param pLatNorth Northern Coordinate
|
||||
* @param pLonEast Eastern Coordinate
|
||||
* @param pLatSouth Southern Coordinate
|
||||
* @param pLonWest Western Coordinate
|
||||
* @return BoundingBox
|
||||
*/
|
||||
public BoundingBox union(final double pLatNorth, final double pLonEast, final double pLatSouth,
|
||||
final double pLonWest) {
|
||||
return new BoundingBox((this.mLatNorth < pLatNorth) ? pLatNorth : this.mLatNorth,
|
||||
(this.mLonEast < pLonEast) ? pLonEast : this.mLonEast,
|
||||
(this.mLatSouth > pLatSouth) ? pLatSouth : this.mLatSouth,
|
||||
(this.mLonWest > pLonWest) ? pLonWest : this.mLonWest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new BoundingBox that is the intersection of this with another box
|
||||
*
|
||||
* @param box BoundingBox to intersect with
|
||||
* @return BoundingBox
|
||||
*/
|
||||
public BoundingBox intersect(BoundingBox box) {
|
||||
double maxLonWest = Math.max(this.mLonWest, box.getLonWest());
|
||||
double minLonEast = Math.min(this.mLonEast, box.getLonEast());
|
||||
double maxLatNorth = Math.min(this.mLatNorth, box.getLatNorth());
|
||||
double minLatSouth = Math.max(this.mLatSouth, box.getLatSouth());
|
||||
return new BoundingBox(maxLatNorth, minLonEast, minLatSouth, maxLonWest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new BoundingBox that is the intersection of this with another box
|
||||
*
|
||||
* @param north Northern Coordinate
|
||||
* @param east Eastern Coordinate
|
||||
* @param south Southern Coordinate
|
||||
* @param west Western Coordinate
|
||||
* @return BoundingBox
|
||||
*/
|
||||
public BoundingBox intersect(double north, double east, double south, double west) {
|
||||
return intersect(new BoundingBox(north, east, south, west));
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<BoundingBox> CREATOR =
|
||||
new Parcelable.Creator<BoundingBox>() {
|
||||
@Override
|
||||
public BoundingBox createFromParcel(final Parcel in) {
|
||||
return readFromParcel(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundingBox[] newArray(final int size) {
|
||||
return new BoundingBox[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) ((mLatNorth + 90)
|
||||
+ ((mLatSouth + 90) * 1000)
|
||||
+ ((mLonEast + 180) * 1000000)
|
||||
+ ((mLonEast + 180) * 1000000000));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(final Parcel out, final int arg1) {
|
||||
out.writeDouble(this.mLatNorth);
|
||||
out.writeDouble(this.mLonEast);
|
||||
out.writeDouble(this.mLatSouth);
|
||||
out.writeDouble(this.mLonWest);
|
||||
}
|
||||
|
||||
private static BoundingBox readFromParcel(final Parcel in) {
|
||||
final double latNorth = in.readDouble();
|
||||
final double lonEast = in.readDouble();
|
||||
final double latSouth = in.readDouble();
|
||||
final double lonWest = in.readDouble();
|
||||
return new BoundingBox(latNorth, lonEast, latSouth, lonWest);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.mapbox.mapboxgl.geometry;
|
||||
|
||||
/**
|
||||
* Implementation of iOS MKCoordinateRegion
|
||||
*/
|
||||
public class CoordinateRegion {
|
||||
private LatLng center;
|
||||
private CoordinateSpan span;
|
||||
|
||||
public CoordinateRegion(final LatLng center, final CoordinateSpan span) {
|
||||
this.center = center;
|
||||
this.span = span;
|
||||
}
|
||||
|
||||
public LatLng getCenter() {
|
||||
return center;
|
||||
}
|
||||
|
||||
public void setCenter(final LatLng center) {
|
||||
this.center = center;
|
||||
}
|
||||
|
||||
public CoordinateSpan getSpan() {
|
||||
return span;
|
||||
}
|
||||
|
||||
public void setSpan(final CoordinateSpan span) {
|
||||
this.span = span;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.mapbox.mapboxgl.geometry;
|
||||
|
||||
/**
|
||||
* Implementation of iOS MKCoordinateSpan
|
||||
*/
|
||||
public class CoordinateSpan {
|
||||
|
||||
private double latitudeSpan;
|
||||
private double longitudeSpan;
|
||||
|
||||
public CoordinateSpan(final double latitudeSpan, final double longitudeSpan) {
|
||||
this.latitudeSpan = latitudeSpan;
|
||||
this.longitudeSpan = longitudeSpan;
|
||||
}
|
||||
|
||||
public double getLatitudeSpan() {
|
||||
return latitudeSpan;
|
||||
}
|
||||
|
||||
public void setLatitudeSpan(final double latitudeSpan) {
|
||||
this.latitudeSpan = latitudeSpan;
|
||||
}
|
||||
|
||||
public double getLongitudeSpan() {
|
||||
return longitudeSpan;
|
||||
}
|
||||
|
||||
public void setLongitudeSpan(final double longitudeSpan) {
|
||||
this.longitudeSpan = longitudeSpan;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.mapbox.mapboxgl.geometry;
|
||||
|
||||
/**
|
||||
* A Latitude, Longitude point.
|
||||
*/
|
||||
public interface ILatLng {
|
||||
double getLatitude();
|
||||
|
||||
double getLongitude();
|
||||
|
||||
double getAltitude();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.mapbox.mapboxgl.geometry;
|
||||
|
||||
public interface IProjectedMeters {
|
||||
double getNorthing();
|
||||
|
||||
double getEasting();
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
package com.mapbox.mapboxgl.geometry;
|
||||
|
||||
import android.location.Location;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import com.mapbox.mapboxgl.constants.GeoConstants;
|
||||
import com.mapbox.mapboxgl.constants.MathConstants;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class LatLng implements ILatLng, Parcelable, Serializable {
|
||||
|
||||
public static final Parcelable.Creator<LatLng> CREATOR = new Parcelable.Creator<LatLng>() {
|
||||
public LatLng createFromParcel(Parcel in) {
|
||||
return new LatLng(in);
|
||||
}
|
||||
|
||||
public LatLng[] newArray(int size) {
|
||||
return new LatLng[size];
|
||||
}
|
||||
};
|
||||
|
||||
private double latitude;
|
||||
private double longitude;
|
||||
private double altitude = 0.0;
|
||||
|
||||
/**
|
||||
* Construct a new latitude, longitude point given float arguments
|
||||
* @param latitude Latitude in degrees
|
||||
* @param longitude Longitude in degrees
|
||||
*/
|
||||
public LatLng(double latitude, double longitude) {
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new latitude, longitude, altitude point given float arguments
|
||||
* @param latitude Latitude in degrees
|
||||
* @param longitude Longitude in degress
|
||||
* @param altitude Altitude in meters
|
||||
*/
|
||||
public LatLng(double latitude, double longitude, double altitude) {
|
||||
this.latitude = latitude;
|
||||
this.longitude = longitude;
|
||||
this.altitude = altitude;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform a Location into a LatLng point
|
||||
* @param location Android Location
|
||||
*/
|
||||
public LatLng(Location location) {
|
||||
this(location.getLatitude(), location.getLongitude(), location.getAltitude());
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone an existing latitude longitude point
|
||||
* @param aLatLng LatLng
|
||||
*/
|
||||
public LatLng(LatLng aLatLng) {
|
||||
this.latitude = aLatLng.latitude;
|
||||
this.longitude = aLatLng.longitude;
|
||||
this.altitude = aLatLng.altitude;
|
||||
}
|
||||
|
||||
protected LatLng(Parcel in) {
|
||||
latitude = in.readDouble();
|
||||
longitude = in.readDouble();
|
||||
altitude = in.readDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLatitude() {
|
||||
return latitude;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getLongitude() {
|
||||
return longitude;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getAltitude() {
|
||||
return altitude;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LatLng latLng = (LatLng) o;
|
||||
|
||||
return Double.compare(latLng.altitude, altitude) == 0 && Double.compare(latLng.latitude, latitude) == 0 && Double.compare(latLng.longitude, longitude) == 0;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(latitude);
|
||||
result = (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(longitude);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(altitude);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LatLng [longitude=" + longitude + ", latitude=" + latitude + ", altitude=" + altitude + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeDouble(latitude);
|
||||
out.writeDouble(longitude);
|
||||
out.writeDouble(altitude);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate distance between two points
|
||||
* @param other Other LatLng to compare to
|
||||
* @return distance in meters
|
||||
*/
|
||||
public double distanceTo(LatLng other) {
|
||||
|
||||
final double a1 = MathConstants.DEG2RAD * this.latitude;
|
||||
final double a2 = MathConstants.DEG2RAD * this.longitude;
|
||||
final double b1 = MathConstants.DEG2RAD * other.getLatitude();
|
||||
final double b2 = MathConstants.DEG2RAD * other.getLongitude();
|
||||
|
||||
final double cosa1 = Math.cos(a1);
|
||||
final double cosb1 = Math.cos(b1);
|
||||
|
||||
final double t1 = cosa1 * Math.cos(a2) * cosb1 * Math.cos(b2);
|
||||
final double t2 = cosa1 * Math.sin(a2) * cosb1 * Math.sin(b2);
|
||||
final double t3 = Math.sin(a1) * Math.sin(b1);
|
||||
final double tt = Math.acos(t1 + t2 + t3);
|
||||
|
||||
return GeoConstants.RADIUS_EARTH_METERS * tt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package com.mapbox.mapboxgl.geometry;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class LatLngZoom extends LatLng implements Parcelable, Serializable {
|
||||
|
||||
public static final Parcelable.Creator<LatLngZoom> CREATOR = new Parcelable.Creator<LatLngZoom>() {
|
||||
public LatLngZoom createFromParcel(Parcel in) {
|
||||
return new LatLngZoom(in);
|
||||
}
|
||||
|
||||
public LatLngZoom[] newArray(int size) {
|
||||
return new LatLngZoom[size];
|
||||
}
|
||||
};
|
||||
|
||||
private double zoom;
|
||||
|
||||
public LatLngZoom(double latitude, double longitude, double zoom) {
|
||||
super(latitude, longitude);
|
||||
this.zoom = zoom;
|
||||
}
|
||||
|
||||
public LatLngZoom(LatLng latLng, double zoom) {
|
||||
super(latLng.getLatitude(), latLng.getLongitude());
|
||||
this.zoom = zoom;
|
||||
}
|
||||
|
||||
private LatLngZoom(Parcel in) {
|
||||
super(in);
|
||||
zoom = in.readDouble();
|
||||
}
|
||||
|
||||
public double getZoom() {
|
||||
return zoom;
|
||||
}
|
||||
|
||||
public void setZoom(double zoom) {
|
||||
this.zoom = zoom;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
if (!super.equals(o)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LatLngZoom that = (LatLngZoom) o;
|
||||
|
||||
return Double.compare(that.zoom, zoom) == 0;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = super.hashCode();
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(zoom);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "LatLngZoom [latitude=" + super.getLatitude() + ", longitude=" + super.getLongitude() + ", altitude=" + super.getAltitude() + ", zoom=" + zoom + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
super.writeToParcel(out, flags);
|
||||
out.writeDouble(zoom);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
package com.mapbox.mapboxgl.geometry;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class ProjectedMeters implements IProjectedMeters, Parcelable, Serializable {
|
||||
|
||||
public static final Creator<ProjectedMeters> CREATOR = new Creator<ProjectedMeters>() {
|
||||
public ProjectedMeters createFromParcel(Parcel in) {
|
||||
return new ProjectedMeters(in);
|
||||
}
|
||||
|
||||
public ProjectedMeters[] newArray(int size) {
|
||||
return new ProjectedMeters[size];
|
||||
}
|
||||
};
|
||||
|
||||
private double northing;
|
||||
private double easting;
|
||||
|
||||
public ProjectedMeters(double northing, double easting) {
|
||||
this.northing = northing;
|
||||
this.easting = easting;
|
||||
}
|
||||
|
||||
public ProjectedMeters(ProjectedMeters aProjectedMeters) {
|
||||
this.northing = aProjectedMeters.northing;
|
||||
this.easting = aProjectedMeters.easting;
|
||||
}
|
||||
|
||||
protected ProjectedMeters(Parcel in) {
|
||||
northing = in.readDouble();
|
||||
easting = in.readDouble();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getNorthing() {
|
||||
return northing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getEasting() {
|
||||
return easting;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ProjectedMeters projectedMeters = (ProjectedMeters) o;
|
||||
|
||||
return Double.compare(projectedMeters.easting, easting) == 0 && Double.compare(projectedMeters.northing, northing) == 0;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
long temp;
|
||||
temp = Double.doubleToLongBits(easting);
|
||||
result = (int) (temp ^ (temp >>> 32));
|
||||
temp = Double.doubleToLongBits(northing);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ProjectedMeters [northing=" + northing + ", easting=" + easting + "]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
out.writeDouble(northing);
|
||||
out.writeDouble(easting);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.mapbox.mapboxgl.http;
|
||||
|
||||
import com.mapbox.mapboxgl.constants.MapboxConstants;
|
||||
import com.squareup.okhttp.Call;
|
||||
import com.squareup.okhttp.Callback;
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InterruptedIOException;
|
||||
import java.net.ProtocolException;
|
||||
import java.net.SocketException;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import javax.net.ssl.SSLException;
|
||||
|
||||
class HTTPContext {
|
||||
|
||||
private static final int CONNECTION_ERROR = 0;
|
||||
private static final int TEMPORARY_ERROR = 1;
|
||||
private static final int PERMANENT_ERROR = 2;
|
||||
|
||||
private static HTTPContext mInstance = null;
|
||||
|
||||
private OkHttpClient mClient;
|
||||
|
||||
private HTTPContext() {
|
||||
super();
|
||||
mClient = new OkHttpClient();
|
||||
}
|
||||
|
||||
public static HTTPContext getInstance() {
|
||||
if (mInstance == null) {
|
||||
mInstance = new HTTPContext();
|
||||
}
|
||||
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
public HTTPRequest createRequest(long nativePtr, String resourceUrl, String userAgent, String etag, String modified) {
|
||||
return new HTTPRequest(nativePtr, resourceUrl, userAgent, etag, modified);
|
||||
}
|
||||
|
||||
public class HTTPRequest implements Callback {
|
||||
private long mNativePtr = 0;
|
||||
|
||||
private Call mCall;
|
||||
private Request mRequest;
|
||||
|
||||
private native void nativeOnFailure(long nativePtr, int type, String message);
|
||||
private native void nativeOnResponse(long nativePtr, int code, String message, String etag, String modified, String cacheControl, String expires, byte[] body);
|
||||
|
||||
private HTTPRequest(long nativePtr, String resourceUrl, String userAgent, String etag, String modified) {
|
||||
mNativePtr = nativePtr;
|
||||
Request.Builder builder = new Request.Builder().url(resourceUrl).tag(resourceUrl.toLowerCase(MapboxConstants.MAPBOX_LOCALE)).addHeader("User-Agent", userAgent);
|
||||
if (etag.length() > 0) {
|
||||
builder = builder.addHeader("If-None-Match", etag);
|
||||
} else if (modified.length() > 0) {
|
||||
builder = builder.addHeader("If-Modified-Since", modified);
|
||||
}
|
||||
mRequest = builder.build();
|
||||
}
|
||||
|
||||
public void start() {
|
||||
mCall = HTTPContext.getInstance().mClient.newCall(mRequest);
|
||||
mCall.enqueue(this);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
mCall.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFailure(Request request, IOException e) {
|
||||
int type = PERMANENT_ERROR;
|
||||
if ((e instanceof UnknownHostException) || (e instanceof SocketException) || (e instanceof ProtocolException) || (e instanceof SSLException)) {
|
||||
type = CONNECTION_ERROR;
|
||||
} else if ((e instanceof InterruptedIOException)) {
|
||||
type = TEMPORARY_ERROR;
|
||||
}
|
||||
nativeOnFailure(mNativePtr, type, e.getMessage());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(Response response) throws IOException {
|
||||
byte[] body;
|
||||
try {
|
||||
body = response.body().bytes();
|
||||
} catch (IOException e) {
|
||||
onFailure(mRequest, e);
|
||||
return;
|
||||
} finally {
|
||||
response.body().close();
|
||||
}
|
||||
|
||||
nativeOnResponse(mNativePtr, response.code(), response.message(), response.header("ETag"), response.header("Last-Modified"), response.header("Cache-Control"), response.header("Expires"), body);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,600 @@
|
||||
package com.mapbox.mapboxgl.views;
|
||||
|
||||
import android.graphics.PointF;
|
||||
import android.view.Surface;
|
||||
|
||||
import com.mapbox.mapboxgl.annotations.Marker;
|
||||
import com.mapbox.mapboxgl.annotations.Polygon;
|
||||
import com.mapbox.mapboxgl.annotations.Polyline;
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
import com.mapbox.mapboxgl.geometry.LatLngZoom;
|
||||
import com.mapbox.mapboxgl.geometry.ProjectedMeters;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
// Class that wraps the native methods for convenience
|
||||
class NativeMapView {
|
||||
|
||||
//
|
||||
// Static members
|
||||
//
|
||||
|
||||
//
|
||||
// Instance members
|
||||
//
|
||||
|
||||
// Holds the pointer to JNI NativeMapView
|
||||
private long mNativeMapViewPtr = 0;
|
||||
|
||||
// Used for callbacks
|
||||
private MapView mMapView;
|
||||
|
||||
//
|
||||
// Static methods
|
||||
//
|
||||
|
||||
static {
|
||||
System.loadLibrary("mapbox-gl");
|
||||
}
|
||||
|
||||
//
|
||||
// Constructors
|
||||
//
|
||||
|
||||
public NativeMapView(MapView mapView, String cachePath, String dataPath, String apkPath, float pixelRatio, int availableProcessors, long totalMemory) {
|
||||
if (availableProcessors < 0) {
|
||||
throw new IllegalArgumentException("availableProcessors cannot be negative.");
|
||||
}
|
||||
|
||||
if (totalMemory < 0) {
|
||||
throw new IllegalArgumentException("totalMemory cannot be negative.");
|
||||
}
|
||||
|
||||
mMapView = mapView;
|
||||
|
||||
// Create the NativeMapView
|
||||
mNativeMapViewPtr = nativeCreate(cachePath, dataPath, apkPath, pixelRatio, availableProcessors, totalMemory);
|
||||
}
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
public void initializeDisplay() {
|
||||
nativeInitializeDisplay(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void terminateDisplay() {
|
||||
nativeTerminateDisplay(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void initializeContext() {
|
||||
nativeInitializeContext(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void terminateContext() {
|
||||
nativeTerminateContext(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void createSurface(Surface surface) {
|
||||
nativeCreateSurface(mNativeMapViewPtr, surface);
|
||||
}
|
||||
|
||||
public void destroySurface() {
|
||||
nativeDestroySurface(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void pause() {
|
||||
nativePause(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void resume() {
|
||||
nativeResume(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void update() {
|
||||
nativeUpdate(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
nativeOnInvalidate(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void resizeView(int width, int height) {
|
||||
if (width < 0) {
|
||||
throw new IllegalArgumentException("width cannot be negative.");
|
||||
}
|
||||
|
||||
if (height < 0) {
|
||||
throw new IllegalArgumentException("height cannot be negative.");
|
||||
}
|
||||
|
||||
if (width > 65535) {
|
||||
throw new IllegalArgumentException(
|
||||
"width cannot be greater than 65535.");
|
||||
}
|
||||
|
||||
if (height > 65535) {
|
||||
throw new IllegalArgumentException(
|
||||
"height cannot be greater than 65535.");
|
||||
}
|
||||
nativeViewResize(mNativeMapViewPtr, width, height);
|
||||
}
|
||||
|
||||
public void resizeFramebuffer(int fbWidth, int fbHeight) {
|
||||
if (fbWidth < 0) {
|
||||
throw new IllegalArgumentException("fbWidth cannot be negative.");
|
||||
}
|
||||
|
||||
if (fbHeight < 0) {
|
||||
throw new IllegalArgumentException("fbHeight cannot be negative.");
|
||||
}
|
||||
|
||||
if (fbWidth > 65535) {
|
||||
throw new IllegalArgumentException(
|
||||
"fbWidth cannot be greater than 65535.");
|
||||
}
|
||||
|
||||
if (fbHeight > 65535) {
|
||||
throw new IllegalArgumentException(
|
||||
"fbHeight cannot be greater than 65535.");
|
||||
}
|
||||
nativeFramebufferResize(mNativeMapViewPtr, fbWidth, fbHeight);
|
||||
}
|
||||
|
||||
public void addClass(String clazz) {
|
||||
nativeAddClass(mNativeMapViewPtr, clazz);
|
||||
}
|
||||
|
||||
public void removeClass(String clazz) {
|
||||
nativeRemoveClass(mNativeMapViewPtr, clazz);
|
||||
}
|
||||
|
||||
public boolean hasClass(String clazz) {
|
||||
return nativeHasClass(mNativeMapViewPtr, clazz);
|
||||
}
|
||||
|
||||
public void setClasses(List<String> classes) {
|
||||
nativeSetClasses(mNativeMapViewPtr, classes);
|
||||
}
|
||||
|
||||
public List<String> getClasses() {
|
||||
return nativeGetClasses(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void setDefaultTransitionDuration() {
|
||||
setDefaultTransitionDuration(0);
|
||||
}
|
||||
|
||||
public long getDefaultTransitionDuration() {
|
||||
return nativeGetDefaultTransitionDuration(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void setDefaultTransitionDuration(long milliseconds) {
|
||||
if (milliseconds < 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"milliseconds cannot be negative.");
|
||||
}
|
||||
|
||||
nativeSetDefaultTransitionDuration(mNativeMapViewPtr,
|
||||
milliseconds);
|
||||
}
|
||||
|
||||
public void setStyleUrl(String url) {
|
||||
nativeSetStyleUrl(mNativeMapViewPtr, url);
|
||||
}
|
||||
|
||||
public void setStyleJson(String newStyleJson) {
|
||||
setStyleJson(newStyleJson, "");
|
||||
}
|
||||
|
||||
public void setStyleJson(String newStyleJson, String base) {
|
||||
nativeSetStyleJson(mNativeMapViewPtr, newStyleJson, base);
|
||||
}
|
||||
|
||||
public String getStyleJson() {
|
||||
return nativeGetStyleJson(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void setAccessToken(String accessToken) {
|
||||
nativeSetAccessToken(mNativeMapViewPtr, accessToken);
|
||||
}
|
||||
|
||||
public String getAccessToken() {
|
||||
return nativeGetAccessToken(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void cancelTransitions() {
|
||||
nativeCancelTransitions(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void setGestureInProgress(boolean inProgress) {
|
||||
nativeSetGestureInProgress(mNativeMapViewPtr, inProgress);
|
||||
}
|
||||
|
||||
public void moveBy(double dx, double dy) {
|
||||
moveBy(dx, dy, 0);
|
||||
}
|
||||
|
||||
public void moveBy(double dx, double dy, long duration) {
|
||||
nativeMoveBy(mNativeMapViewPtr, dx, dy, duration);
|
||||
}
|
||||
|
||||
public void setLatLng(LatLng latLng) {
|
||||
setLatLng(latLng, 0);
|
||||
}
|
||||
|
||||
public void setLatLng(LatLng latLng, long duration) {
|
||||
nativeSetLatLng(mNativeMapViewPtr, latLng, duration);
|
||||
}
|
||||
|
||||
public LatLng getLatLng() {
|
||||
return nativeGetLatLng(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void resetPosition() {
|
||||
nativeResetPosition(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void scaleBy(double ds) {
|
||||
scaleBy(ds, -1.0, -1.0);
|
||||
}
|
||||
|
||||
public void scaleBy(double ds, double cx, double cy) {
|
||||
scaleBy(ds, cx, cy, 0);
|
||||
}
|
||||
|
||||
public void scaleBy(double ds, double cx, double cy, long duration) {
|
||||
nativeScaleBy(mNativeMapViewPtr, ds, cx, cy, duration);
|
||||
}
|
||||
|
||||
public void setScale(double scale) {
|
||||
setScale(scale, -1.0, -1.0);
|
||||
}
|
||||
|
||||
public void setScale(double scale, double cx, double cy) {
|
||||
setScale(scale, cx, cy, 0);
|
||||
}
|
||||
|
||||
public void setScale(double scale, double cx, double cy, long duration) {
|
||||
nativeSetScale(mNativeMapViewPtr, scale, cx, cy, duration);
|
||||
}
|
||||
|
||||
public double getScale() {
|
||||
return nativeGetScale(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void setZoom(double zoom) {
|
||||
setZoom(zoom, 0);
|
||||
}
|
||||
|
||||
public void setZoom(double zoom, long duration) {
|
||||
nativeSetZoom(mNativeMapViewPtr, zoom, duration);
|
||||
}
|
||||
|
||||
public double getZoom() {
|
||||
return nativeGetZoom(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void setLatLngZoom(LatLngZoom latLngZoom) {
|
||||
setLatLngZoom(latLngZoom, 0);
|
||||
}
|
||||
|
||||
public void setLatLngZoom(LatLngZoom latLngZoom, long duration) {
|
||||
nativeSetLatLngZoom(mNativeMapViewPtr, latLngZoom, duration);
|
||||
}
|
||||
|
||||
public LatLngZoom getLatLngZoom() {
|
||||
return nativeGetLatLngZoom(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void resetZoom() {
|
||||
nativeResetZoom(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public double getMinZoom() {
|
||||
return nativeGetMinZoom(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public double getMaxZoom() {
|
||||
return nativeGetMaxZoom(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void rotateBy(double sx, double sy, double ex, double ey) {
|
||||
rotateBy(sx, sy, ex, ey, 0);
|
||||
}
|
||||
|
||||
public void rotateBy(double sx, double sy, double ex, double ey,
|
||||
long duration) {
|
||||
nativeRotateBy(mNativeMapViewPtr, sx, sy, ex, ey, duration);
|
||||
}
|
||||
|
||||
public void setBearing(double degrees) {
|
||||
setBearing(degrees, 0);
|
||||
}
|
||||
|
||||
public void setBearing(double degrees, long duration) {
|
||||
nativeSetBearing(mNativeMapViewPtr, degrees, duration);
|
||||
}
|
||||
|
||||
public void setBearing(double degrees, double cx, double cy) {
|
||||
nativeSetBearing(mNativeMapViewPtr, degrees, cx, cy);
|
||||
}
|
||||
|
||||
public double getBearing() {
|
||||
return nativeGetBearing(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void resetNorth() {
|
||||
nativeResetNorth(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public long addMarker(Marker marker) {
|
||||
return nativeAddMarker(mNativeMapViewPtr, marker);
|
||||
}
|
||||
|
||||
public long addPolyline(Polyline polyline) {
|
||||
return nativeAddPolyline(mNativeMapViewPtr, polyline);
|
||||
}
|
||||
|
||||
public long addPolygon(Polygon polygon) {
|
||||
return nativeAddPolygon(mNativeMapViewPtr, polygon);
|
||||
}
|
||||
|
||||
public long[] addPolygons(List<Polygon> polygon) {
|
||||
return nativeAddPolygons(mNativeMapViewPtr, polygon);
|
||||
}
|
||||
|
||||
public void removeAnnotation(long id) {
|
||||
nativeRemoveAnnotation(mNativeMapViewPtr, id);
|
||||
}
|
||||
|
||||
public void removeAnnotations(long[] ids) {
|
||||
nativeRemoveAnnotations(mNativeMapViewPtr, ids);
|
||||
}
|
||||
|
||||
public void setSprite(String symbol, int width, int height, float scale, byte[] pixels) {
|
||||
nativeSetSprite(mNativeMapViewPtr, symbol, width, height, scale, pixels);
|
||||
}
|
||||
|
||||
public void onLowMemory() {
|
||||
nativeOnLowMemory(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void setDebug(boolean debug) {
|
||||
nativeSetDebug(mNativeMapViewPtr, debug);
|
||||
}
|
||||
|
||||
public void toggleDebug() {
|
||||
nativeToggleDebug(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public boolean getDebug() {
|
||||
return nativeGetDebug(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void setCollisionDebug(boolean debug) {
|
||||
nativeSetCollisionDebug(mNativeMapViewPtr, debug);
|
||||
}
|
||||
|
||||
public void toggleCollisionDebug() {
|
||||
nativeToggleCollisionDebug(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public boolean getCollisionDebug() {
|
||||
return nativeGetCollisionDebug(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public boolean isFullyLoaded() {
|
||||
return nativeIsFullyLoaded(mNativeMapViewPtr);
|
||||
}
|
||||
|
||||
public void setReachability(boolean status) {
|
||||
nativeSetReachability(mNativeMapViewPtr, status);
|
||||
}
|
||||
|
||||
//public void ();
|
||||
|
||||
//public void getWorldBoundsLatLng();
|
||||
|
||||
public double getMetersPerPixelAtLatitude(double lat, double zoom) {
|
||||
return nativeGetMetersPerPixelAtLatitude(mNativeMapViewPtr, lat, zoom);
|
||||
}
|
||||
|
||||
public ProjectedMeters projectedMetersForLatLng(LatLng latLng) {
|
||||
return nativeProjectedMetersForLatLng(mNativeMapViewPtr, latLng);
|
||||
}
|
||||
|
||||
public LatLng latLngForProjectedMeters(ProjectedMeters projectedMeters) {
|
||||
return nativeLatLngForProjectedMeters(mNativeMapViewPtr, projectedMeters);
|
||||
}
|
||||
|
||||
public PointF pixelForLatLng(LatLng latLng) {
|
||||
return nativePixelForLatLng(mNativeMapViewPtr, latLng);
|
||||
}
|
||||
|
||||
public LatLng latLngForPixel(PointF pixel) {
|
||||
return nativeLatLngForPixel(mNativeMapViewPtr, pixel);
|
||||
}
|
||||
|
||||
//
|
||||
// Callbacks
|
||||
//
|
||||
|
||||
protected void onInvalidate() {
|
||||
mMapView.onInvalidate();
|
||||
}
|
||||
|
||||
protected void onMapChanged() {
|
||||
mMapView.onMapChanged();
|
||||
}
|
||||
|
||||
protected void onFpsChanged(double fps) {
|
||||
mMapView.onFpsChanged(fps);
|
||||
}
|
||||
|
||||
//
|
||||
// JNI methods
|
||||
//
|
||||
|
||||
@Override
|
||||
protected void finalize() throws Throwable {
|
||||
nativeDestroy(mNativeMapViewPtr);
|
||||
mNativeMapViewPtr = 0;
|
||||
super.finalize();
|
||||
}
|
||||
|
||||
private native long nativeCreate(String cachePath, String dataPath, String apkPath, float pixelRatio, int availableProcessors, long totalMemory);
|
||||
|
||||
private native void nativeDestroy(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeInitializeDisplay(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeTerminateDisplay(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeInitializeContext(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeTerminateContext(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeCreateSurface(long nativeMapViewPtr,
|
||||
Surface surface);
|
||||
|
||||
private native void nativeDestroySurface(long nativeMapViewPtr);
|
||||
|
||||
private native void nativePause(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeResume(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeUpdate(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeOnInvalidate(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeViewResize(long nativeMapViewPtr, int width, int height);
|
||||
|
||||
private native void nativeFramebufferResize(long nativeMapViewPtr, int fbWidth, int fbHeight);
|
||||
|
||||
private native void nativeAddClass(long nativeMapViewPtr, String clazz);
|
||||
|
||||
private native void nativeRemoveClass(long nativeMapViewPtr, String clazz);
|
||||
|
||||
private native boolean nativeHasClass(long nativeMapViewPtr, String clazz);
|
||||
|
||||
private native void nativeSetClasses(long nativeMapViewPtr,
|
||||
List<String> classes);
|
||||
|
||||
private native List<String> nativeGetClasses(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeSetDefaultTransitionDuration(
|
||||
long nativeMapViewPtr, long duration);
|
||||
|
||||
private native long nativeGetDefaultTransitionDuration(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeSetStyleUrl(long nativeMapViewPtr, String url);
|
||||
|
||||
private native void nativeSetStyleJson(long nativeMapViewPtr,
|
||||
String newStyleJson, String base);
|
||||
|
||||
private native String nativeGetStyleJson(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeSetAccessToken(long nativeMapViewPtr, String accessToken);
|
||||
|
||||
private native String nativeGetAccessToken(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeCancelTransitions(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeSetGestureInProgress(long nativeMapViewPtr, boolean inProgress);
|
||||
|
||||
private native void nativeMoveBy(long nativeMapViewPtr, double dx,
|
||||
double dy, long duration);
|
||||
|
||||
private native void nativeSetLatLng(long nativeMapViewPtr, LatLng latLng,
|
||||
long duration);
|
||||
|
||||
private native LatLng nativeGetLatLng(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeResetPosition(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeScaleBy(long nativeMapViewPtr, double ds,
|
||||
double cx, double cy, long duration);
|
||||
|
||||
private native void nativeSetScale(long nativeMapViewPtr, double scale,
|
||||
double cx, double cy, long duration);
|
||||
|
||||
private native double nativeGetScale(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeSetZoom(long nativeMapViewPtr, double zoom,
|
||||
long duration);
|
||||
|
||||
private native double nativeGetZoom(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeSetLatLngZoom(long nativeMapViewPtr,
|
||||
LatLngZoom lonLatZoom, long duration);
|
||||
|
||||
private native LatLngZoom nativeGetLatLngZoom(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeResetZoom(long nativeMapViewPtr);
|
||||
|
||||
private native double nativeGetMinZoom(long nativeMapViewPtr);
|
||||
|
||||
private native double nativeGetMaxZoom(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeRotateBy(long nativeMapViewPtr, double sx,
|
||||
double sy, double ex, double ey, long duration);
|
||||
|
||||
private native void nativeSetBearing(long nativeMapViewPtr, double degrees,
|
||||
long duration);
|
||||
|
||||
private native void nativeSetBearing(long nativeMapViewPtr, double degrees,
|
||||
double cx, double cy);
|
||||
|
||||
private native double nativeGetBearing(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeResetNorth(long nativeMapViewPtr);
|
||||
|
||||
private native long nativeAddMarker(long nativeMapViewPtr, Marker marker);
|
||||
|
||||
private native long nativeAddPolyline(long nativeMapViewPtr, Polyline polyline);
|
||||
|
||||
private native long nativeAddPolygon(long mNativeMapViewPtr, Polygon polygon);
|
||||
|
||||
private native long[] nativeAddPolygons(long mNativeMapViewPtr, List<Polygon> polygon);
|
||||
|
||||
private native void nativeRemoveAnnotation(long nativeMapViewPtr, long id);
|
||||
|
||||
private native void nativeRemoveAnnotations(long nativeMapViewPtr, long[] id);
|
||||
|
||||
private native void nativeSetSprite(long nativeMapViewPtr, String symbol,
|
||||
int width, int height, float scale, byte[] pixels);
|
||||
|
||||
private native void nativeOnLowMemory(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeSetDebug(long nativeMapViewPtr, boolean debug);
|
||||
|
||||
private native void nativeToggleDebug(long nativeMapViewPtr);
|
||||
|
||||
private native boolean nativeGetDebug(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeSetCollisionDebug(long nativeMapViewPtr, boolean debug);
|
||||
|
||||
private native void nativeToggleCollisionDebug(long nativeMapViewPtr);
|
||||
|
||||
private native boolean nativeGetCollisionDebug(long nativeMapViewPtr);
|
||||
|
||||
private native boolean nativeIsFullyLoaded(long nativeMapViewPtr);
|
||||
|
||||
private native void nativeSetReachability(long nativeMapViewPtr, boolean status);
|
||||
|
||||
//private native void nativeGetWorldBoundsMeters(long nativeMapViewPtr);
|
||||
|
||||
//private native void nativeGetWorldBoundsLatLng(long nativeMapViewPtr);
|
||||
|
||||
private native double nativeGetMetersPerPixelAtLatitude(long nativeMapViewPtr, double lat, double zoom);
|
||||
|
||||
private native ProjectedMeters nativeProjectedMetersForLatLng(long nativeMapViewPtr, LatLng latLng);
|
||||
|
||||
private native LatLng nativeLatLngForProjectedMeters(long nativeMapViewPtr, ProjectedMeters projectedMeters);
|
||||
|
||||
private native PointF nativePixelForLatLng(long nativeMapViewPtr, LatLng latLng);
|
||||
|
||||
private native LatLng nativeLatLngForPixel(long nativeMapViewPtr, PointF pixel);
|
||||
}
|
||||
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
|
After Width: | Height: | Size: 5.6 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
@@ -0,0 +1,17 @@
|
||||
<resources>
|
||||
<declare-styleable name="MapView">
|
||||
<attr name="centerLongitude" format="float" />
|
||||
<attr name="centerLatitude" format="float" />
|
||||
<attr name="zoomLevel" format="float" />
|
||||
<attr name="direction" format="float" />
|
||||
<attr name="zoomEnabled" format="boolean" />
|
||||
<attr name="scrollEnabled" format="boolean" />
|
||||
<attr name="rotateEnabled" format="boolean" />
|
||||
<attr name="debugActive" format="boolean" />
|
||||
<attr name="styleUrl" format="string" />
|
||||
<attr name="accessToken" format="string"/>
|
||||
<attr name="styleClasses" format="string"/>
|
||||
<attr name="compassEnabled" format="boolean" />
|
||||
<attr name="myLocationEnabled" format="boolean" />
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<string name="compassContentDescription">Map compass. Click to reset the map rotation to North.</string>
|
||||
</resources>
|
||||
108
android/java/MapboxGLAndroidSDKTestApp/build.gradle
Normal file
@@ -0,0 +1,108 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven { url 'https://maven.fabric.io/public' }
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:1.3.0'
|
||||
classpath 'com.jakewharton.sdkmanager:gradle-plugin:0.12.0'
|
||||
classpath 'io.fabric.tools:gradle:1.+'
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'android-sdk-manager'
|
||||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'io.fabric'
|
||||
|
||||
repositories {
|
||||
maven { url 'https://maven.fabric.io/public' }
|
||||
}
|
||||
|
||||
apply plugin: 'checkstyle'
|
||||
|
||||
task accessToken {
|
||||
def rawDir = new File("MapboxGLAndroidSDKTestApp/src/main/res/raw")
|
||||
rawDir.mkdirs()
|
||||
def tokenFile = new File("MapboxGLAndroidSDKTestApp/src/main/res/raw/token.txt")
|
||||
if (!tokenFile.exists()) {
|
||||
String token = "$System.env.MAPBOX_ACCESS_TOKEN"
|
||||
if (token == null) {
|
||||
throw new InvalidUserDataException("You must set the MAPBOX_ACCESS_TOKEN environment variable.")
|
||||
}
|
||||
tokenFile.write(token)
|
||||
}
|
||||
}
|
||||
|
||||
gradle.projectsEvaluated {
|
||||
preBuild.dependsOn('accessToken')
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "23"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.mapbox.mapboxgl.testapp"
|
||||
minSdkVersion 8
|
||||
targetSdkVersion 23
|
||||
versionCode 4
|
||||
versionName "0.1.3"
|
||||
}
|
||||
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_1_7
|
||||
targetCompatibility JavaVersion.VERSION_1_7
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'META-INF/LICENSE.txt'
|
||||
exclude 'META-INF/NOTICE.txt'
|
||||
}
|
||||
|
||||
lintOptions {
|
||||
checkAllWarnings true
|
||||
warningsAsErrors true
|
||||
disable 'IconDensities'
|
||||
disable 'InvalidPackage'
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile(project(':MapboxGLAndroidSDK')) {
|
||||
transitive = true
|
||||
}
|
||||
compile 'com.android.support:support-annotations:23.0.0'
|
||||
compile 'com.android.support:support-v4:23.0.0'
|
||||
compile 'com.android.support:appcompat-v7:23.0.0'
|
||||
compile 'com.android.support:design:23.0.0'
|
||||
compile('com.crashlytics.sdk.android:crashlytics:2.5.1@aar') {
|
||||
transitive = true;
|
||||
}
|
||||
}
|
||||
|
||||
checkstyle {
|
||||
configFile project.file('../checks.xml')
|
||||
showViolations true
|
||||
}
|
||||
|
||||
android.applicationVariants.all { variant ->
|
||||
def name = variant.buildType.name
|
||||
def checkstyle = project.tasks.create "checkstyle${name.capitalize()}", Checkstyle
|
||||
checkstyle.dependsOn variant.javaCompile
|
||||
checkstyle.source variant.javaCompile.source
|
||||
checkstyle.classpath = project.fileTree(variant.javaCompile.destinationDir)
|
||||
checkstyle.exclude('**/BuildConfig.java')
|
||||
checkstyle.exclude('**/R.java')
|
||||
project.tasks.getByName("check").dependsOn checkstyle
|
||||
}
|
||||
34
android/java/MapboxGLAndroidSDKTestApp/lint.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<lint>
|
||||
<!-- Ignore errors caused by icon burning -->
|
||||
<issue id="IconLauncherShape" severity="ignore">
|
||||
<ignore path="res/drawable-mdpi/icon.png" />
|
||||
<ignore path="res/drawable-hdpi/icon.png" />
|
||||
<ignore path="res/drawable-xdpi/icon.png" />
|
||||
<ignore path="res/drawable-xxdpi/icon.png" />
|
||||
<ignore path="res/drawable-mdpi/icon_burned.png" />
|
||||
<ignore path="res/drawable-hdpi/icon_burned.png" />
|
||||
<ignore path="res/drawable-xdpi/icon_burned.png" />
|
||||
<ignore path="res/drawable-xxdpi/icon_burned.png" />
|
||||
</issue>
|
||||
<issue id="IconDuplicates" severity="ignore">
|
||||
<ignore path="res/drawable-mdpi/icon.png" />
|
||||
<ignore path="res/drawable-hdpi/icon.png" />
|
||||
<ignore path="res/drawable-xdpi/icon.png" />
|
||||
<ignore path="res/drawable-xxdpi/icon.png" />
|
||||
<ignore path="res/drawable-mdpi/icon_burned.png" />
|
||||
<ignore path="res/drawable-hdpi/icon_burned.png" />
|
||||
<ignore path="res/drawable-xdpi/icon_burned.png" />
|
||||
<ignore path="res/drawable-xxdpi/icon_burned.png" />
|
||||
</issue>
|
||||
<issue id="UnusedResources" severity="ignore">
|
||||
<ignore path="res/drawable-mdpi/icon.png" />
|
||||
<ignore path="res/drawable-hdpi/icon.png" />
|
||||
<ignore path="res/drawable-xdpi/icon.png" />
|
||||
<ignore path="res/drawable-xxdpi/icon.png" />
|
||||
<ignore path="res/drawable-mdpi/icon_burned.png" />
|
||||
<ignore path="res/drawable-hdpi/icon_burned.png" />
|
||||
<ignore path="res/drawable-xdpi/icon_burned.png" />
|
||||
<ignore path="res/drawable-xxdpi/icon_burned.png" />
|
||||
</issue>
|
||||
</lint>
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"
|
||||
package="com.mapbox.mapboxgl.testapp">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:fullBackupContent="true"
|
||||
android:icon="@drawable/icon_burned"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme"
|
||||
android:supportsRtl="true">
|
||||
<activity
|
||||
android:name="com.mapbox.mapboxgl.testapp.MainActivity"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<meta-data
|
||||
android:name="io.fabric.ApiKey"
|
||||
android:value="9724157045ff7d083492c6d9ae03e60e8609d461" />
|
||||
</application>
|
||||
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
</manifest>
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"LineString","coordinates":[[-121.3714599609375,38.64583568648869],[-121.48681640624999,38.64047263931154],[-121.53076171875,38.61579745317875],[-121.56509399414061,38.57823196583313],[-121.75186157226561,38.533127435052776],[-121.97021484374999,38.35350340353833],[-122.08007812499999,38.24680876017446],[-122.16796875,38.19718009396176],[-122.23800659179686,38.09457899232253],[-122.27371215820312,38.01455819225337],[-122.33551025390625,37.94094845586459],[-122.27371215820312,37.81846319511331],[-122.4151611328125,37.7652868250379]]}}]}
|
||||
@@ -0,0 +1 @@
|
||||
{"type":"FeatureCollection","features":[{"type":"Feature","properties":{},"geometry":{"type":"Polygon","coordinates":[[[-122.28813171386719,38.617406963286136],[-122.26959228515624,38.6833657775237],[-122.18238830566406,38.55568323796419],[-122.10617065429688,38.51378825951165],[-122.11509704589845,38.50465406475561],[-122.18307495117188,38.542795073979015],[-122.19955444335938,38.496593518947556],[-122.28813171386719,38.617406963286136]]]}}]}
|
||||
@@ -0,0 +1,453 @@
|
||||
package com.mapbox.mapboxgl.testapp;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.PointF;
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.FloatingActionButton;
|
||||
import android.support.design.widget.NavigationView;
|
||||
import android.support.v4.app.ActivityCompat;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.view.GravityCompat;
|
||||
import android.support.v4.widget.DrawerLayout;
|
||||
import android.support.v7.app.ActionBar;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.util.Log;
|
||||
import android.view.GestureDetector;
|
||||
import android.view.MenuItem;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.widget.TextView;
|
||||
import com.crashlytics.android.Crashlytics;
|
||||
import com.mapbox.mapboxgl.annotations.MarkerOptions;
|
||||
import com.mapbox.mapboxgl.annotations.PolygonOptions;
|
||||
import com.mapbox.mapboxgl.annotations.PolylineOptions;
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
import com.mapbox.mapboxgl.views.MapView;
|
||||
import io.fabric.sdk.android.Fabric;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
|
||||
private static final String TAG = "MainActivity";
|
||||
|
||||
//
|
||||
// Static members
|
||||
//
|
||||
|
||||
// Used for saving instance state
|
||||
private static final String STATE_IS_ANNOTATIONS_ON = "isAnnotationsOn";
|
||||
private static final String STATE_SELECTED_STYLE = "selectedStyle";
|
||||
|
||||
// Used for permissions requests
|
||||
private static final int PERMISSIONS_LOCATION = 0;
|
||||
|
||||
//
|
||||
// Instance members
|
||||
//
|
||||
|
||||
// Used for the UI
|
||||
private DrawerLayout mDrawerLayout;
|
||||
private MapView mMapView;
|
||||
private TextView mFpsTextView;
|
||||
private int mSelectedStyle = R.id.actionStyleMapboxStreets;
|
||||
NavigationView mNavigationView;
|
||||
|
||||
// Used for GPS
|
||||
private FloatingActionButton mLocationFAB;
|
||||
|
||||
// Used for Annotations
|
||||
private boolean mIsAnnotationsOn = false;
|
||||
|
||||
//
|
||||
// Lifecycle events
|
||||
//
|
||||
|
||||
// Called when activity is created
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
Fabric.with(this, new Crashlytics());
|
||||
|
||||
// Load the layout
|
||||
setContentView(R.layout.activity_main);
|
||||
|
||||
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
|
||||
setSupportActionBar(toolbar);
|
||||
|
||||
final ActionBar ab = getSupportActionBar();
|
||||
if (ab != null) {
|
||||
ab.setHomeAsUpIndicator(R.drawable.ic_menu);
|
||||
ab.setDisplayHomeAsUpEnabled(true);
|
||||
}
|
||||
|
||||
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
|
||||
|
||||
mNavigationView = (NavigationView) findViewById(R.id.nav_view);
|
||||
if (mNavigationView != null) {
|
||||
setupDrawerContent(mNavigationView);
|
||||
}
|
||||
|
||||
mMapView = (MapView) findViewById(R.id.mainMapView);
|
||||
// Load the access token
|
||||
try {
|
||||
BufferedReader reader = new BufferedReader(new InputStreamReader(getResources().openRawResource(R.raw.token)));
|
||||
String line = reader.readLine();
|
||||
mMapView.setAccessToken(line);
|
||||
} catch (IOException e) {
|
||||
Log.e(TAG, "Error loading access token from token.txt: " + e.toString());
|
||||
}
|
||||
|
||||
mMapView.onCreate(savedInstanceState);
|
||||
mMapView.setOnFpsChangedListener(new MyOnFpsChangedListener());
|
||||
|
||||
final GestureDetector gestureDetector = new GestureDetector(this, new GestureDetector.SimpleOnGestureListener() {
|
||||
public void onLongPress(final MotionEvent e) {
|
||||
float x = e.getX();
|
||||
float y = e.getY();
|
||||
|
||||
// flip y direction vertically to match core GL
|
||||
y = mMapView.getHeight() - y;
|
||||
|
||||
LatLng position = mMapView.fromScreenLocation(new PointF(x, y));
|
||||
|
||||
mMapView.addMarker(new MarkerOptions()
|
||||
.position(position)
|
||||
.title("Dropped Pin")
|
||||
.sprite("default_marker"));
|
||||
}
|
||||
});
|
||||
|
||||
mMapView.setOnTouchListener(new View.OnTouchListener() {
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
return gestureDetector.onTouchEvent(event);
|
||||
}
|
||||
});
|
||||
|
||||
mFpsTextView = (TextView) findViewById(R.id.view_fps);
|
||||
mFpsTextView.setText("");
|
||||
|
||||
mLocationFAB = (FloatingActionButton)findViewById(R.id.locationFAB);
|
||||
mLocationFAB.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
// Toggle GPS position updates
|
||||
toggleGps(!mMapView.isMyLocationEnabled());
|
||||
if (mMapView.isMyLocationEnabled()) {
|
||||
Location location = mMapView.getMyLocation();
|
||||
if (location != null) {
|
||||
mMapView.setZoomLevel(8);
|
||||
mMapView.setCenterCoordinate(new LatLng(location));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Restore saved state
|
||||
if (savedInstanceState != null) {
|
||||
mIsAnnotationsOn = savedInstanceState.getBoolean(STATE_IS_ANNOTATIONS_ON);
|
||||
mSelectedStyle = savedInstanceState.getInt(STATE_SELECTED_STYLE);
|
||||
}
|
||||
|
||||
// Set default UI state
|
||||
mNavigationView.getMenu().findItem(R.id.action_compass).setChecked(mMapView.isCompassEnabled());
|
||||
mNavigationView.getMenu().findItem(R.id.action_debug).setChecked(mMapView.isDebugActive());
|
||||
mNavigationView.getMenu().findItem(R.id.action_markers).setChecked(mIsAnnotationsOn);
|
||||
changeMapStyle(mSelectedStyle);
|
||||
toggleGps(mMapView.isMyLocationEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispatch onStart() to all fragments. Ensure any created loaders are
|
||||
* now started.
|
||||
*/
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
mMapView.onStart();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
mMapView.onStop();
|
||||
}
|
||||
|
||||
// Called when our app goes into the background
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
|
||||
mMapView.onPause();
|
||||
}
|
||||
|
||||
// Called when our app comes into the foreground
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
mMapView.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
mMapView.onDestroy();
|
||||
}
|
||||
|
||||
// Called when we need to save instance state
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
|
||||
mMapView.onSaveInstanceState(outState);
|
||||
outState.putBoolean(STATE_IS_ANNOTATIONS_ON, mIsAnnotationsOn);
|
||||
outState.putInt(STATE_SELECTED_STYLE, mSelectedStyle);
|
||||
}
|
||||
|
||||
// Called when the system is running low on memory
|
||||
@Override
|
||||
public void onLowMemory() {
|
||||
super.onLowMemory();
|
||||
|
||||
mMapView.onLowMemory();
|
||||
}
|
||||
|
||||
//
|
||||
// Other events
|
||||
//
|
||||
|
||||
// Called when pressing action bar items
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
mDrawerLayout.openDrawer(GravityCompat.START);
|
||||
return true;
|
||||
default:
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String permissions[], @NonNull int[] grantResults) {
|
||||
switch (requestCode) {
|
||||
case PERMISSIONS_LOCATION: {
|
||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
enableGps();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setupDrawerContent(NavigationView navigationView) {
|
||||
navigationView.setNavigationItemSelectedListener(
|
||||
new NavigationView.OnNavigationItemSelectedListener() {
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(MenuItem menuItem) {
|
||||
mDrawerLayout.closeDrawers();
|
||||
|
||||
// Respond To Selection
|
||||
switch (menuItem.getItemId()) {
|
||||
|
||||
case R.id.action_debug:
|
||||
// Toggle debug mode
|
||||
mMapView.toggleDebug();
|
||||
toggleFpsCounter(mMapView.isDebugActive());
|
||||
menuItem.setChecked(mMapView.isDebugActive());
|
||||
return true;
|
||||
|
||||
case R.id.action_markers:
|
||||
// Toggle markers
|
||||
toggleAnnotations(!mIsAnnotationsOn);
|
||||
menuItem.setChecked(mIsAnnotationsOn);
|
||||
return true;
|
||||
|
||||
case R.id.action_compass:
|
||||
// Toggle compass
|
||||
mMapView.setCompassEnabled(!mMapView.isCompassEnabled());
|
||||
menuItem.setChecked(mMapView.isCompassEnabled());
|
||||
return true;
|
||||
|
||||
/*
|
||||
case R.id.followNone:
|
||||
mMapView.setUserLocationTrackingMode(MapView.UserLocationTrackingMode.NONE);
|
||||
return true;
|
||||
|
||||
case R.id.followFollow:
|
||||
mMapView.setUserLocationTrackingMode(MapView.UserLocationTrackingMode.FOLLOW);
|
||||
return true;
|
||||
|
||||
case R.id.followBearing:
|
||||
mMapView.setUserLocationTrackingMode(MapView.UserLocationTrackingMode.FOLLOW_BEARING);
|
||||
return true;
|
||||
*/
|
||||
default:
|
||||
return changeMapStyle(menuItem.getItemId());
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void toggleFpsCounter(boolean enableFps) {
|
||||
// Show the FPS counter
|
||||
if (enableFps) {
|
||||
mFpsTextView.setVisibility(View.VISIBLE);
|
||||
mFpsTextView.setText(getResources().getString(R.string.label_fps));
|
||||
} else {
|
||||
mFpsTextView.setVisibility(View.INVISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean changeMapStyle(int id) {
|
||||
switch (id) {
|
||||
case R.id.actionStyleMapboxStreets:
|
||||
mMapView.setStyleUrl(getString(R.string.styleURLMapboxStreets));
|
||||
mNavigationView.getMenu().findItem(id).setChecked(true);
|
||||
mSelectedStyle = id;
|
||||
return true;
|
||||
|
||||
case R.id.actionStyleEmerald:
|
||||
mMapView.setStyleUrl(getString(R.string.styleURLEmerald));
|
||||
mNavigationView.getMenu().findItem(id).setChecked(true);
|
||||
mSelectedStyle = id;
|
||||
return true;
|
||||
|
||||
case R.id.actionStyleLight:
|
||||
mMapView.setStyleUrl(getString(R.string.styleURLLight));
|
||||
mNavigationView.getMenu().findItem(id).setChecked(true);
|
||||
mSelectedStyle = id;
|
||||
return true;
|
||||
|
||||
case R.id.actionStyleDark:
|
||||
mMapView.setStyleUrl(getString(R.string.styleURLDark));
|
||||
mNavigationView.getMenu().findItem(id).setChecked(true);
|
||||
mSelectedStyle = id;
|
||||
return true;
|
||||
|
||||
case R.id.actionStyleSatellite:
|
||||
mMapView.setStyleUrl(getString(R.string.styleURLSatellite));
|
||||
mNavigationView.getMenu().findItem(id).setChecked(true);
|
||||
mSelectedStyle = id;
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enabled / Disable GPS location updates along with updating the UI
|
||||
* @param enableGps true if GPS is to be enabled, false if GPS is to be disabled
|
||||
*/
|
||||
private void toggleGps(boolean enableGps) {
|
||||
if (enableGps) {
|
||||
if ((ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) ||
|
||||
(ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED))
|
||||
{
|
||||
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSIONS_LOCATION);
|
||||
} else {
|
||||
enableGps();
|
||||
}
|
||||
} else {
|
||||
mMapView.setMyLocationEnabled(false);
|
||||
mLocationFAB.setColorFilter(Color.TRANSPARENT);
|
||||
}
|
||||
}
|
||||
|
||||
private void enableGps() {
|
||||
mMapView.setMyLocationEnabled(true);
|
||||
mLocationFAB.setColorFilter(ContextCompat.getColor(this, R.color.primary));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable / Disable Annotations.
|
||||
*
|
||||
* @param enableAnnotations True to display, False to hide
|
||||
*/
|
||||
private void toggleAnnotations(boolean enableAnnotations) {
|
||||
if (enableAnnotations) {
|
||||
if (!mIsAnnotationsOn) {
|
||||
mIsAnnotationsOn = true;
|
||||
addMarkers();
|
||||
addPolyline();
|
||||
addPolygon();
|
||||
mMapView.setZoomLevel(7);
|
||||
mMapView.setCenterCoordinate(new LatLng(38.11727, -122.22839));
|
||||
}
|
||||
} else {
|
||||
if (mIsAnnotationsOn) {
|
||||
mIsAnnotationsOn = false;
|
||||
removeAnnotations();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addMarkers() {
|
||||
LatLng backLot = new LatLng(38.649441, -121.369064);
|
||||
mMapView.addMarker(new MarkerOptions()
|
||||
.position(backLot)
|
||||
.title("Back Lot")
|
||||
.snippet("The back lot behind my house"));
|
||||
|
||||
LatLng cheeseRoom = new LatLng(38.531577,-122.010646);
|
||||
mMapView.addMarker(new MarkerOptions()
|
||||
.position(cheeseRoom)
|
||||
.sprite("dog-park-15")
|
||||
.title("Cheese Room")
|
||||
.snippet("The only air conditioned room on the property!"));
|
||||
}
|
||||
|
||||
private void addPolyline() {
|
||||
try {
|
||||
String geojsonStr = Util.loadStringFromAssets(this, "small_line.geojson");
|
||||
LatLng[] latLngs = Util.parseGeoJSONCoordinates(geojsonStr);
|
||||
MapView map = mMapView;
|
||||
map.addPolyline(new PolylineOptions()
|
||||
.add(latLngs)
|
||||
.width(2)
|
||||
.color(Color.RED));
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error adding Polyline: "+ e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void addPolygon() {
|
||||
try {
|
||||
String geojsonStr = Util.loadStringFromAssets(this, "small_poly.geojson");
|
||||
LatLng[] latLngs = Util.parseGeoJSONCoordinates(geojsonStr);
|
||||
MapView map = mMapView;
|
||||
ArrayList<PolygonOptions> opts = new ArrayList<>();
|
||||
opts.add(new PolygonOptions()
|
||||
.add(latLngs)
|
||||
.strokeColor(Color.MAGENTA)
|
||||
.fillColor(Color.BLUE));
|
||||
map.addPolygons(opts).get(0);
|
||||
} catch (Exception e) {
|
||||
Log.e(TAG, "Error adding Polygon: "+ e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void removeAnnotations() {
|
||||
mMapView.removeAnnotations();
|
||||
}
|
||||
|
||||
// Called when FPS changes
|
||||
private class MyOnFpsChangedListener implements MapView.OnFpsChangedListener {
|
||||
|
||||
@Override
|
||||
public void onFpsChanged(double fps) {
|
||||
mFpsTextView.setText(getResources().getString(R.string.label_fps) + String.format(" %4.2f", fps));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
package com.mapbox.mapboxgl.testapp;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.util.Log;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.mapbox.mapboxgl.views.MapView;
|
||||
|
||||
public class MapFragment extends Fragment {
|
||||
|
||||
//
|
||||
// Static members
|
||||
//
|
||||
|
||||
// Tag used for logging
|
||||
private static final String TAG = "MapFragment";
|
||||
|
||||
//
|
||||
// Instance members
|
||||
//
|
||||
|
||||
// The map
|
||||
private MapView mMap;
|
||||
|
||||
//
|
||||
// Lifecycle events
|
||||
//
|
||||
|
||||
// Called when the fragment is created
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
Log.v(TAG, "onCreateView");
|
||||
|
||||
// Create the map
|
||||
mMap = (MapView) inflater.inflate(R.layout.fragment_main, container, true);
|
||||
|
||||
// Need to pass on any saved state to the map
|
||||
mMap.onCreate(savedInstanceState);
|
||||
|
||||
// Return the map as the root view
|
||||
return mMap;
|
||||
}
|
||||
|
||||
// Called when the fragment is destroyed
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
super.onDestroyView();
|
||||
Log.v(TAG, "onDestroyView");
|
||||
|
||||
// Need to pass on to view
|
||||
mMap.onDestroy();
|
||||
mMap = null;
|
||||
}
|
||||
|
||||
// Called when the fragment is visible
|
||||
@Override
|
||||
public void onStart() {
|
||||
super.onStart();
|
||||
Log.v(TAG, "onStart");
|
||||
|
||||
// Need to pass on to view
|
||||
mMap.onStart();
|
||||
}
|
||||
|
||||
// Called when the fragment is invisible
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
Log.v(TAG, "onStop");
|
||||
|
||||
// Need to pass on to view
|
||||
mMap.onStop();
|
||||
}
|
||||
|
||||
// Called when the fragment is in the background
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
Log.v(TAG, "onPause");
|
||||
|
||||
// Need to pass on to view
|
||||
mMap.onPause();
|
||||
}
|
||||
|
||||
// Called when the fragment is no longer in the background
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
Log.v(TAG, "onResume");
|
||||
|
||||
// Need to pass on to view
|
||||
mMap.onResume();
|
||||
}
|
||||
|
||||
// Called before fragment is destroyed
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle outState) {
|
||||
Log.v(TAG, "onSaveInstanceState");
|
||||
|
||||
// Need to retrieve any saved state from the map
|
||||
mMap.onSaveInstanceState(outState);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
//
|
||||
// Property methods
|
||||
//
|
||||
|
||||
public MapView getMap() {
|
||||
return mMap;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.mapbox.mapboxgl.testapp;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import com.mapbox.mapboxgl.geometry.LatLng;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
public class Util {
|
||||
|
||||
public static String loadStringFromAssets(final Context context, final String fileName) throws IOException {
|
||||
if (TextUtils.isEmpty(fileName)) {
|
||||
throw new NullPointerException("No GeoJSON File Name passed in.");
|
||||
}
|
||||
InputStream is = context.getAssets().open(fileName);
|
||||
BufferedReader rd = new BufferedReader(new InputStreamReader(is, Charset.forName("UTF-8")));
|
||||
return readAll(rd);
|
||||
}
|
||||
|
||||
public static LatLng[] parseGeoJSONCoordinates(String geojsonStr) throws JSONException {
|
||||
JSONObject jsonObject = new JSONObject(geojsonStr);
|
||||
JSONArray features = jsonObject.getJSONArray("features");
|
||||
JSONObject feature = features.getJSONObject(0);
|
||||
JSONObject geometry = feature.getJSONObject("geometry");
|
||||
String type = geometry.getString("type");
|
||||
JSONArray coordinates;
|
||||
if (type.equals("Polygon")) {
|
||||
coordinates = geometry.getJSONArray("coordinates").getJSONArray(0);
|
||||
} else {
|
||||
coordinates = geometry.getJSONArray("coordinates");
|
||||
}
|
||||
int len = coordinates.length();
|
||||
LatLng[] latLngs = new LatLng[coordinates.length()];
|
||||
for (int i = 0; i < len; ++i) {
|
||||
JSONArray coord = coordinates.getJSONArray(i);
|
||||
double lng = coord.getDouble(0);
|
||||
double lat = coord.getDouble(1);
|
||||
latLngs[i] = new LatLng(lat, lng);
|
||||
}
|
||||
return latLngs;
|
||||
}
|
||||
|
||||
private static String readAll(Reader rd) throws IOException {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
int cp;
|
||||
while ((cp = rd.read()) != -1) {
|
||||
sb.append((char) cp);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 116 B |
|
After Width: | Height: | Size: 549 B |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 2.5 KiB |
|
After Width: | Height: | Size: 99 B |
|
After Width: | Height: | Size: 341 B |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 135 B |
|
After Width: | Height: | Size: 660 B |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 183 B |
|
After Width: | Height: | Size: 976 B |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 235 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<android.support.v4.widget.DrawerLayout
|
||||
android:id="@+id/drawer_layout"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/primary"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/content_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@+id/toolbar">
|
||||
|
||||
<android.support.design.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.mapbox.mapboxgl.views.MapView
|
||||
android:id="@+id/mainMapView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/view_fps"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="10dp"
|
||||
android:text="@string/label_fps"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"/>
|
||||
|
||||
|
||||
<android.support.design.widget.FloatingActionButton
|
||||
android:id="@+id/locationFAB"
|
||||
android:src="@drawable/ic_my_location_black_24dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end|bottom"
|
||||
android:layout_margin="@dimen/fab_margin"
|
||||
app:backgroundTint="@color/white"
|
||||
app:borderWidth="0dp"
|
||||
/>
|
||||
</android.support.design.widget.CoordinatorLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<android.support.design.widget.NavigationView
|
||||
android:id="@+id/nav_view"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:fitsSystemWindows="true"
|
||||
app:menu="@menu/menu_drawer"/>
|
||||
|
||||
</android.support.v4.widget.DrawerLayout>
|
||||
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.mapbox.mapboxgl.views.MapView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:mapbox="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
@@ -0,0 +1,55 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<item
|
||||
android:id="@+id/action_debug"
|
||||
android:icon="@android:drawable/ic_menu_info_details"
|
||||
android:title="@string/action_debug"
|
||||
android:checkable="true"
|
||||
/>
|
||||
<item
|
||||
android:id="@+id/action_markers"
|
||||
android:icon="@android:drawable/ic_menu_myplaces"
|
||||
android:title="@string/action_point_annotations"
|
||||
android:checkable="true"
|
||||
/>
|
||||
<item android:id="@+id/action_compass"
|
||||
android:icon="@android:drawable/ic_menu_compass"
|
||||
android:title="@string/action_compass"
|
||||
android:checkable="true"
|
||||
/>
|
||||
|
||||
<!--
|
||||
<group android:id="@+id/locationFollowModesSeparator"/>
|
||||
|
||||
<group android:id="@+id/locationFollowModes" android:checkableBehavior="single">
|
||||
<item android:id="@+id/followNone"
|
||||
android:title="@string/action_location_none"/>
|
||||
<item android:id="@+id/followFollow"
|
||||
android:title="@string/action_location_follow"/>
|
||||
<item android:id="@+id/followBearing"
|
||||
android:title="@string/action_location_bearing"/>
|
||||
</group>
|
||||
-->
|
||||
|
||||
<group android:id="@+id/stylesSeparator"/>
|
||||
|
||||
<group android:id="@+id/stylesGroup" android:checkableBehavior="single">
|
||||
<item
|
||||
android:id="@+id/actionStyleMapboxStreets"
|
||||
android:title="@string/styleMapboxStreets" />
|
||||
<item
|
||||
android:id="@+id/actionStyleEmerald"
|
||||
android:title="@string/styleEmerald" />
|
||||
<item
|
||||
android:id="@+id/actionStyleLight"
|
||||
android:title="@string/styleLight" />
|
||||
<item
|
||||
android:id="@+id/actionStyleDark"
|
||||
android:title="@string/styleDark" />
|
||||
<item
|
||||
android:id="@+id/actionStyleSatellite"
|
||||
android:title="@string/styleSatellite" />
|
||||
</group>
|
||||
|
||||
</menu>
|
||||
@@ -0,0 +1,3 @@
|
||||
<?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">
|
||||
</menu>
|
||||
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="primary">#1E8CAB</color>
|
||||
<color name="primaryDark">#166B83</color>
|
||||
<color name="accent">#E55E5E</color>
|
||||
<color name="white">#FFFFFF</color>
|
||||
</resources>
|
||||
@@ -0,0 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<dimen name="fab_margin">16dp</dimen>
|
||||
</resources>
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string name="app_name">Mapbox GL</string>
|
||||
|
||||
<string name="action_gps">Toggle GPS location</string>
|
||||
<string name="action_location_none">Disable tracking</string>
|
||||
<string name="action_location_follow">Use follow tracking mode</string>
|
||||
<string name="action_location_bearing">Use bearing tracking mode tracking</string>
|
||||
<string name="action_compass">Toggle compass</string>
|
||||
<string name="action_debug">Toggle debug mode</string>
|
||||
<string name="action_point_annotations">Toggle point annotations</string>
|
||||
|
||||
<string name="label_fps">FPS:</string>
|
||||
|
||||
<string name="styleMapboxStreets">Mapbox Streets</string>
|
||||
<string name="styleEmerald">Emerald</string>
|
||||
<string name="styleLight">Light</string>
|
||||
<string name="styleDark">Dark</string>
|
||||
<string name="styleSatellite">Satellite</string>
|
||||
|
||||
<string name="styleURLMapboxStreets">asset://styles/mapbox-streets-v7.json</string>
|
||||
<string name="styleURLEmerald">asset://styles/emerald-v7.json</string>
|
||||
<string name="styleURLLight">asset://styles/light-v7.json</string>
|
||||
<string name="styleURLDark">asset://styles/dark-v7.json</string>
|
||||
<string name="styleURLSatellite">asset://styles/satellite-v7.json</string>
|
||||
|
||||
<string-array name="outdoors_class_list">
|
||||
<item>Day</item>
|
||||
<item>Night</item>
|
||||
</string-array>
|
||||
|
||||
</resources>
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<style name="AppTheme" parent="AppBaseTheme" />
|
||||
|
||||
<style name="AppBaseTheme" parent="@style/Theme.AppCompat.Light.NoActionBar">
|
||||
<item name="colorPrimary">@color/primary</item>
|
||||
<item name="colorPrimaryDark">@color/primaryDark</item>
|
||||
<item name="colorAccent">@color/accent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
4
android/java/build.gradle
Normal file
@@ -0,0 +1,4 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
task wrapper(type: Wrapper) {
|
||||
gradleVersion = '2.5'
|
||||
}
|
||||