├── .circleci
└── config.yml
├── .github
└── stale.yml
├── .gitignore
├── .gitmodules
├── .npmignore
├── @mauron85_react-native-background-geolocation.podspec
├── CHANGES.md
├── CHANGES_zh-Hans.md
├── CONTRIBUTORS.md
├── DISTANCE_FILTER_PROVIDER.md
├── ISSUE_TEMPLATE.md
├── LICENSE
├── PROVIDERS.md
├── README.md
├── android
├── README.md
├── build.gradle
├── gradle.properties
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── gradlew
├── lib
│ ├── build.gradle
│ └── src
│ │ ├── androidTest
│ │ └── java
│ │ │ └── com
│ │ │ └── marianhello
│ │ │ └── bgloc
│ │ │ └── react
│ │ │ └── ConfigMapperTest.java
│ │ ├── main
│ │ ├── AndroidManifest.xml
│ │ ├── java
│ │ │ └── com
│ │ │ │ ├── iodine
│ │ │ │ └── start
│ │ │ │ │ ├── ArrayUtil.java
│ │ │ │ │ └── MapUtil.java
│ │ │ │ └── marianhello
│ │ │ │ └── bgloc
│ │ │ │ └── react
│ │ │ │ ├── BackgroundGeolocationModule.java
│ │ │ │ ├── BackgroundGeolocationPackage.java
│ │ │ │ ├── ConfigMapper.java
│ │ │ │ ├── data
│ │ │ │ └── LocationMapper.java
│ │ │ │ └── headless
│ │ │ │ ├── HeadlessService.java
│ │ │ │ └── HeadlessTaskRunner.java
│ │ └── res
│ │ │ ├── mipmap-hdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-mdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── mipmap-xxxhdpi
│ │ │ └── ic_launcher.png
│ │ │ ├── values
│ │ │ └── strings.xml
│ │ │ └── xml
│ │ │ ├── authenticator.xml
│ │ │ └── syncadapter.xml
│ │ └── test
│ │ └── java
│ │ └── com
│ │ └── marianhello
│ │ └── bgloc
│ │ └── react
│ │ └── ConfigMapperTest.java
└── settings.gradle
├── index.d.ts
├── index.js
├── ios
├── RCTBackgroundGeolocation.xcodeproj
│ └── project.pbxproj
├── RCTBackgroundGeolocation
│ ├── RCTBackgroundGeolocation.h
│ └── RCTBackgroundGeolocation.m
├── README.md
├── npm_download.sh
└── pkgversion.js
├── issuehunt-shield-v1.svg
├── package.json
├── react-native.config.js
├── res
└── dummy.apk
└── scripts
├── config.js
├── google_cloud.sh
├── isInstalled.js
├── npm_deprecate.sh
├── postlink.js
└── postunlink.js
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Android Gradle CircleCI 2.0 configuration file
2 | #
3 | # Check https://circleci.com/docs/2.0/language-android/ for more details
4 | # https://github.com/flyve-mdm/android-mdm-agent/blob/develop/.circleci/config.yml
5 |
6 | version: 2
7 | reference:
8 |
9 | ## Workspaces
10 | project_dir: &project_dir
11 | ~/mauron85_bgloc
12 |
13 | android_config: &android_config
14 | working_directory: ~/mauron85_bgloc/android
15 | docker:
16 | # specify the version you desire here
17 | - image: circleci/android:api-28-alpha
18 | # Specify service dependencies here if necessary
19 | # CircleCI maintains a library of pre-built images
20 | # documented at https://circleci.com/docs/2.0/circleci-images/
21 | # - image: circleci/postgres:9.4
22 | environment:
23 | # Customize the JVM maximum heap limit
24 | JVM_OPTS: -Xmx3200m
25 | TERM: dumb
26 |
27 | project_checkout: &project_checkout
28 | checkout:
29 | path: *project_dir
30 |
31 | submodule_checkout: &submodule_checkout
32 | run:
33 | name: Checkout git submodules
34 | command: git submodule init && git submodule update
35 |
36 | gradle_key: &gradle_key
37 | jars-{{ checksum "build.gradle" }}-{{ checksum "lib/build.gradle" }}
38 |
39 | restore_gradle_cache: &restore_gradle_cache
40 | restore_cache:
41 | key: *gradle_key
42 |
43 | save_gradle_cache: &save_gradle_cache
44 | save_cache:
45 | key: *gradle_key
46 | paths:
47 | - ~/.gradle
48 | - ~/.m2
49 |
50 | android_dependencies: &android_dependencies
51 | run:
52 | name: Download Android Dependencies
53 | command: ./gradlew androidDependencies
54 |
55 | jobs:
56 | # unit test
57 | build:
58 | <<: *android_config
59 | steps:
60 | - *project_checkout
61 | - *submodule_checkout
62 | - *restore_gradle_cache
63 | - *android_dependencies
64 | - *save_gradle_cache
65 | - run:
66 | name: Run Build
67 | command: ./gradlew build -x lint -x test
68 | # - store_artifacts:
69 | # path: build/reports
70 | # destination: reports
71 | # - store_test_results:
72 | # path: build/test-results
73 | # See https://circleci.com/docs/2.0/deployment-integrations/ for deploy examples
74 |
75 | # Test Instrumentation with Android 4.1 JELLY_BEAN API 16
76 | test_instrumentation:
77 | <<: *android_config
78 | steps:
79 | - *project_checkout
80 | - *submodule_checkout
81 | - *restore_gradle_cache
82 | - *android_dependencies
83 | - *save_gradle_cache
84 | - run:
85 | name: Create debug apk
86 | command: ./gradlew assembleDebug assembleAndroidTest
87 | - run:
88 | name: Run Tests on Firebase test lab
89 | command: source ../scripts/google_cloud.sh
90 |
91 | workflows:
92 | version: 2
93 | build_and_test:
94 | jobs:
95 | - build
96 | - test_instrumentation:
97 | requires:
98 | - build
99 |
--------------------------------------------------------------------------------
/.github/stale.yml:
--------------------------------------------------------------------------------
1 | # Number of days of inactivity before an issue becomes stale
2 | daysUntilStale: 180
3 | # Number of days of inactivity before a stale issue is closed
4 | daysUntilClose: 7
5 | # Issues with these labels will never be considered stale
6 | exemptLabels:
7 | - pinned
8 | - security
9 | # Label to use when marking an issue as stale
10 | staleLabel: stale
11 | # Comment to post when marking an issue as stale. Set to `false` to disable
12 | markComment: >
13 | This issue has been automatically marked as stale because it has not had
14 | recent activity. It will be closed if no further activity occurs. Thank you
15 | for your contributions.
16 | # Comment to post when closing a stale issue. Set to `false` to disable
17 | closeComment: >
18 | This issue has been automatically closed, because it has not had
19 | recent activity. If you believe this issue shouldn't be closed, please
20 | reopen or write down a comment requesting issue reopening with explanation
21 | why you think it's important. Thank you for your contributions.
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | npm-debug.log
4 |
5 | # Xcode
6 | xcuserdata
7 | project.xcworkspace
8 | ios/react-native
9 |
10 | # Android/IJ
11 | .idea
12 | .gradle
13 | local.properties
14 | *.iml
15 | build
16 | *.skip
17 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "ios-common"]
2 | path = ios/common
3 | url = https://github.com/mauron85/background-geolocation-ios.git
4 | [submodule "android-common"]
5 | path = android/common
6 | url = https://github.com/mauron85/background-geolocation-android.git
7 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .github
2 | .DS_Store
3 | node_modules
4 | npm-debug.log
5 |
6 | # Xcode
7 | xcuserdata
8 | project.xcworkspace
9 | ios/react-native
10 |
11 | # Android/IJ
12 | .idea
13 | .gradle
14 | local.properties
15 | *.iml
16 | build
17 | *.skip
18 |
19 | # Git modules
20 | .gitmodules
21 | .git
22 |
23 | # CircleCI
24 | .circleci
25 | res/
26 |
--------------------------------------------------------------------------------
/@mauron85_react-native-background-geolocation.podspec:
--------------------------------------------------------------------------------
1 | require 'json'
2 |
3 | package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4 |
5 | Pod::Spec.new do |s|
6 | s.name = "@mauron85_react-native-background-geolocation"
7 | s.version = package['version']
8 | s.summary = package['description']
9 | s.license = package['license']
10 |
11 | s.authors = package['author']
12 | s.homepage = package['homepage']
13 | s.platform = :ios, "9.0"
14 |
15 | s.source = { :path => "ios" }
16 | s.source_files = "ios/**/*.{h,m}"
17 | s.exclude_files = "ios/common/BackgroundGeolocationTests/*.{h,m}"
18 |
19 | s.dependency 'React'
20 | end
21 |
--------------------------------------------------------------------------------
/CHANGES.md:
--------------------------------------------------------------------------------
1 | ## Changelog
2 |
3 | ### [0.6.3] - 2019-09-16
4 | ### Fixed
5 | - Android fix RejectedExecutionException (fixes #319 #259 #243 #149 #68)
6 | - Android add stop guard
7 |
8 | ### [0.6.2] - 2019-09-10
9 | ### Changed
10 | - Android remove preoreo target
11 | - Android add android.permission.FOREGROUND_SERVICE permission
12 |
13 | ### [0.6.1] - 2019-08-29
14 | ### Changed
15 | - Remove deprecated isLocationEnabled method
16 | - Android use react-native headless JS instead of jsevaluator
17 |
18 | ### [0.6.0] - 2019-08-27
19 | ### Fixed
20 | - Android fix conflicting provider (fixes #344)
21 |
22 | ### Changed
23 | - Android autolinking for RN 0.60
24 |
25 | ### [0.5.6] - 2019-08-27
26 | ### Fixed
27 | - Android allow to start service from background on API >=26 (fixes #356)
28 |
29 | ### [0.5.5] - 2019-08-13
30 | ### Fixed
31 | - Android fix tone generator crash
32 | - Android Removed minsdk from manifest (fixes #357) - @maleriepace
33 | - Android add additional check for applicationId (PR #36 common repo) - @mysport12
34 | - Android minSdk version should not be declared on manifest - @wesleycoder and @maleriepace
35 | - Android Change the react-native link command repositories (PR #374) - @mantaroh
36 | - Update CHANGES_zh-Hans.md - @Kennytian
37 | - Fixed typo in README - @diegogurpegui
38 |
39 | Many thanks to all contributors
40 |
41 | ### [0.5.2] - 2019-03-28
42 | ### Fixed
43 | - Android fix don't start service on app visibility change events fixes
44 | - Android ignore failing instrumentation tests
45 |
46 | ### [0.5.1] - 2019-03-25
47 | ### Fixed
48 | - Android fix #360 - When app crashes for other reasons the service is started by the system
49 |
50 | ### [0.5.0] - 2019-01-31
51 |
52 | ### Added
53 | - ios implement config.stopOnTerminate using startMonitoringSignificantLocationChanges
54 |
55 | Commit: [5149178c65322d04f4e9e47bd278b17cf0e4bd9a](https://github.com/mauron85/background-geolocation-ios/commit/5149178c65322d04f4e9e47bd278b17cf0e4bd9a)
56 | Origin-PR: [#7](https://github.com/mauron85/background-geolocation-ios/pull/7)
57 | Contributed-By: [@StanislavMayorov](https://github.com/StanislavMayorov)
58 |
59 | ### Fixed
60 | - Android - cannot find symbol Assert.assertNotNull
61 |
62 | Commit: [ec334ba6a8612c399d608bbfc4aacfad68fc2105](https://github.com/mauron85/background-geolocation-android/commit/ec334ba6a8612c399d608bbfc4aacfad68fc2105)
63 | Origin-PR: [#25](https://github.com/mauron85/background-geolocation-android/pull/25)
64 | Origin-Issue: [#340](https://github.com/mauron85/react-native-background-geolocation/issues/340)
65 | Contributed-By: [@scurtoni](https://github.com/scurtoni)
66 |
67 | ### [0.5.0-alpha.XY] - unreleased
68 |
69 | This release brings abstractions, allowing code reuse
70 | between ReactNative Cordova plugin variants.
71 | As result enabling faster pace of development and
72 | bug fixing on shared codebase.
73 |
74 | ### Added
75 | - post/sync attributes customization via `postTemplate` config prop
76 | - iOS ACTIVITY_PROVIDER (experimental)
77 | - enable partial plugin reconfiguration
78 | - on "activity" changed event
79 | - Android Use gradle to choose authority (PR #136) by @jsdario
80 | - iOS configuration persistence
81 |
82 | Since alpha.8:
83 | - Android automatic linking with react-native link
84 | - iOS checkStatus returns status of location services (locationServicesEnabled)
85 | - iOS RAW_LOCATION_PROVIDER continue to run on app terminate
86 |
87 | Since alpha.10:
88 | - Android checkStatus returns status of location services (locationServicesEnabled)
89 |
90 | Since alpha.15:
91 | - Android location parameters isFromMockProvider, mockLocationsEnabled, radius, provider
92 | - Android Headless Task
93 |
94 | Since alpha.16:
95 | - iOS add background modes and permissions on postlink
96 | - add crossplatform prepublish script execution (PR #165) by @dobrynia
97 |
98 | Since alpha.17:
99 | - Android allow to override version of libraries with ext declaration
100 |
101 | Since alpha.19:
102 | - Android Oreo experimental support
103 |
104 | Since alpha.20:
105 | - option to get logs by offset and filter by log level
106 | - log uncaught exceptions
107 |
108 | Since alpha.22:
109 | - method forceSync
110 |
111 | Since alpha.26:
112 | - Android add httpHeaders validation
113 |
114 | Since alpha.28:
115 | - implement getCurrentLocation
116 | - iOS implement getStationaryLocation
117 |
118 | Since alpha.31:
119 | - Android Gradle3 support (experimental)
120 |
121 | Since alpha.37:
122 | - Transforming/filtering locations in native code (by [@danielgindi](https://github.com/danielgindi/))
123 | More info: https://github.com/mauron85/background-geolocation-android/pull/8
124 |
125 | Since alpha.40:
126 | - notificationsEnabled config option (by [@danielgindi](https://github.com/danielgindi/))
127 | More info: https://github.com/mauron85/react-native-background-geolocation/pull/269
128 | - Allow stopping location updates on status "285 Updates Not Required" (by [@danielgindi](https://github.com/danielgindi/))
129 | More info: https://github.com/mauron85/react-native-background-geolocation/pull/271
130 |
131 | Since alpha.43:
132 | - Listen for 401 Unauthorized status codes received from http server (by [@FeNoMeNa](https://github.com/FeNoMeNa/))
133 | More info: https://github.com/mauron85/react-native-background-geolocation/pull/308/files
134 |
135 | Since alpha.44:
136 | - typescript definitions (index.d.ts)
137 | - Android allow override minSdkVersion
138 |
139 | Since alpha.45:
140 | - allow nested location props in postTemplate
141 |
142 | Since alpha.47:
143 | - Android make sync account name configurable
144 | in "android/app/src/main/res/values/strings.xml"
145 | ```
146 | Sync Locations
147 | ```
148 |
149 | ### Changed
150 |
151 | Since alpha.6:
152 | - iOS saveBatteryOnBackground defaults to false
153 |
154 | Since alpha.8:
155 | - shared code base with Cordova
156 |
157 | Since alpha.11:
158 | - Android derive sync authority and provider from applicationId
159 | - Android remove android.permission.GET_ACCOUNTS
160 |
161 | Since alpha.19:
162 | - Android postlink register project in settings.gradle instead of file copying
163 | (BREAKING CHANGE - read android-setup section)
164 |
165 | Since alpha.20:
166 | - iOS use Android log format (BREAKING CHANGE)
167 |
168 | Since alpha.22:
169 | - Android remove sync delay when conditions are met
170 | - Android consider HTTP 201 response code as succesful post
171 | - Android obey system sync setting
172 |
173 | Since alpha.26:
174 | - Android show service notification only when in background
175 | - Android remove config option startForeground (related to above)
176 | - Android remove wake locks from both Android providers (by @grassick)
177 | - Android remove restriction on postTemplate string only values
178 |
179 | Since alpha.28:
180 | - Android bring back startForeground config option (BREAKING CHANGE!)
181 |
182 | startForeground has slightly different meaning.
183 |
184 | If false (default) then service will create notification and promotes
185 | itself to foreground service, when client unbinds from service.
186 | This typically happens when application is moving to background.
187 | If app is moving back to foreground (becoming visible to user)
188 | service destroys notification and also stop being foreground service.
189 |
190 | If true service will create notification and will stay in foreground at all times.
191 |
192 | Since alpha.30:
193 | - Android internal changes (permission handling)
194 | - Android gradle build changes
195 |
196 | Since alpha.38:
197 | - Android disable notification sound and vibration on oreo
198 | (PR: [#9](https://github.com/mauron85/background-geolocation-android/pull/9)
199 | by [@danielgindi](https://github.com/danielgindi/),
200 | Closes #260)
201 |
202 | Since alpha.48:
203 | - removeAllListeners - remove all event listeners when calling without parameter
204 |
205 | ### Fixed
206 |
207 | Since alpha.4:
208 | - iOS open location settings on iOS 10 and later (PR #158) by @asafron
209 |
210 | Since alpha.8:
211 | - checkStatus authorization
212 | - Android fix for Build Failed: cannot find symbol
213 |
214 | Since alpha.9:
215 | - Android fix #118 - NullPointerException LocationService.onTaskRemoved
216 | - Android permission - check and request permissions in runtime
217 |
218 | Since alpha.13:
219 | - Android fix allowBackup attribute conflict
220 |
221 | Since alpha.14:
222 | - Android fix #166 - Error: more than one library with package name
223 | 'com.google.android.gms.license'
224 |
225 | Since alpha.15:
226 | - Android only pass valid location parameters
227 | - iOS reset connectivity status on stop
228 | - iOS fix App Store Rejection - Prefs Non-Public URL Scheme
229 |
230 | Since alpha.17:
231 | - Android fix service accidently started with default or stored config
232 |
233 | Since alpha.21:
234 | - Android uninstall common module on postunlink
235 | - Android prevent multiple registration of common project
236 | - Android fix some nullpointer exceptions 92649c70e0ce0072464f47f1d096bef40047b8a6
237 | - iOS update plist on changes only
238 |
239 | Since alpha.22:
240 | - Android add guards to prevent some race conditions
241 | - Android config null handling
242 |
243 | Since alpha.25:
244 | - Android issue #185 - handle invalid configuration
245 |
246 | Since alpha.27:
247 | - iOS fix forceSync params
248 | - fix #183 - Error when adding 'activity' event listener
249 |
250 | Since alpha.28:
251 | - iOS display debug notifications in foreground on iOS >= 10
252 | - iOS fix error message format
253 | - iOS activity provider stationary event
254 |
255 | Since alpha.35:
256 | - Android getCurrentLocation runs on background thread (PR #219 by [@djereg](https://github.com/djereg/))
257 | - iOS Fix crash on delete all location ([7392e39](https://github.com/mauron85/background-geolocation-ios/commit/7392e391c3de3ff0d6f5ef2ef19c34aba612bf9b) by [@acerbetti](https://github.com/acerbetti/))
258 |
259 | Since alpha.36:
260 | - Android Defer start and configure until service is ready
261 | (PR: [#7](https://github.com/mauron85/background-geolocation-android/pull/7)
262 | Commit: [00e1314](https://github.com/mauron85/background-geolocation-android/commit/00e131478ad4e37576eb85581bb663b65302a4e0) by [@danielgindi](https://github.com/danielgindi/),
263 | fixes #201, #181, #172)
264 |
265 | Since alpha.38:
266 | - iOS Avoid taking control of UNUserNotificationCenter
267 | (PR: [#268](https://github.com/mauron85/react-native-background-geolocation/pull/268)
268 | by [@danielgindi](https://github.com/danielgindi/),
269 | fixes #206, #256)
270 |
271 | Since alpha.41:
272 | - Android fix locationService treating success as errors
273 | (PR: [#13](https://github.com/mauron85/background-geolocation-android/pull/13)
274 | by [@hoisel](https://github.com/hoisel/))
275 |
276 | Since alpha.42:
277 | - Android make sure mService exists when we call start or stop
278 | (PR: [#17](https://github.com/mauron85/background-geolocation-android/pull/17)
279 | by [@ivosabev](https://github.com/ivosabev/),
280 | fixes #257, #280)
281 |
282 | Since alpha.44:
283 | - Android automatically use gradle4 template when gradle >= 4.4 is detected
284 | (no need for gradle3EXPERIMENTAL)
285 | - Android upgrade default libraries to version compatible with RN57
286 | - Android fix gradle4 compile, testCompile deprecated warnings
287 | - Android fix service crash on boot for Android 8 when startOnBoot option is used
288 |
289 | Since alpha.46:
290 | - Android use global location content provider (in attempt to fix db locking issue)
291 | - fix type definition
292 |
293 | Since alpha.48:
294 | - Android prefix content_authority to prevent collision with other plugins (fixes #320)
295 |
296 | Since alpha.49:
297 | - Android fix App Crashes when entering / leaving Background (fixes #319)
298 |
299 | Since alpha.50:
300 | - Android fix service checkStatus isStarted
301 | - Android fix crash on permission when started from background
302 |
303 | ### [0.4.1] - 2017-12-19
304 | #### Changed
305 | - react native peer dependency >0.49.0
306 |
307 | ### [0.4.0] - 2017-12-13
308 | release
309 |
310 | ### [0.4.0-rc.3] - 2017-11-23
311 | ### Added
312 | - iOS send http headers on background sync
313 |
314 | ### [0.4.0-rc.2] - 2017-11-13
315 |
316 | ### Fixed
317 | - Android ConfigMapper mapToConfig missing config props (fixes #122)
318 |
319 | ### Added
320 | - Android return location id for getLocations
321 |
322 | ### [0.4.0-rc.1] - 2017-11-10
323 |
324 | ### Fixed
325 | - iOS fix crash when calling getConfig before configure
326 |
327 | #### Added
328 | - checkStatus if service is running
329 | - events [start, stop, authorization, background, foreground]
330 | - implement all methods for both platforms
331 | - new RAW_LOCATION_PROVIDER
332 |
333 | #### Changed
334 |
335 | - start and stop methods doesn't accept callback (use event listeners instead)
336 | - for background syncing syncUrl option is required
337 | - on Android DISTANCE_FILTER_PROVIDER now accept arbitrary values (before only 10, 100, 1000)
338 | - all plugin constants are in directly BackgroundGeolocation namespace. (check index.js)
339 | - plugin can be started without executing configure (stored settings or defaults will be used)
340 | - location property locationId renamed to just id
341 | - iOS pauseLocationUpdates now default to false (becuase iOS docs now states that you need to restart manually if you set it to true)
342 | - iOS finish method replaced with startTask and endTask
343 |
344 | ### [0.3.3] - 2017-11-01
345 | #### Fixed
346 | - Android location sync should also be completed on 201 status code (PR #71)
347 |
348 | ### [0.3.2] - 2017-11-01
349 | #### Fixed
350 | - iOS implementation for isLocationEnabled (PR #92)
351 |
352 | ### [0.3.1] - 2017-10-04
353 | #### Fixed
354 | - (tpisto) iOS compile error in React Native 0.48.x (fixes #108)
355 |
356 | ### [0.3.0-alpha.1] - 2017-08-15
357 | #### Fixed
358 | - RN 0.47 compatibility (fixes #95)
359 |
360 | ### [0.2.0-alpha.7] - 2017-03-21
361 | #### Fixed
362 | - iOS fixing build issue #44
363 |
364 | ### [0.2.0-alpha.6] - 2017-02-18
365 | #### Fixed
366 | - iOS RN 0.40 compatibility
367 |
368 | ### [0.2.0-alpha.5] - 2016-09-15
369 | #### Fixed
370 | - Android fix issue #10
371 |
372 | ### [0.2.0-alpha.4] - 2016-09-10
373 | #### Fixed
374 | - Android fix crash on destroy when plugin was not configured
375 |
376 | ### [0.2.0-alpha.3] - 2016-09-07
377 | #### Fixed
378 | - fix Android issue #10 - crash on refresh
379 |
380 | #### Added
381 | - Android onStationary
382 | - Android getLogEntries
383 |
384 | #### Removed
385 | - Android location filtering
386 |
387 | #### Changed
388 | - Android project directory structure
389 | (please read updated install instructions)
390 | - Android db logging instead of file
391 |
392 | ### [0.2.0-alpha.2] - 2016-08-31
393 | #### Fixed
394 | - fix config not persisted
395 | - tmp fix Android time long to int conversion
396 |
397 | #### Added
398 | - Android isLocationEnabled
399 | - Android showAppSettings
400 | - Android showLocationSettings
401 | - Android getLocations
402 | - Android getConfig
403 |
404 | ### [0.2.0-alpha.1] - 2016-08-17
405 | #### Changed
406 | - upgrading plugin to match cordova 2.2.0-alpha.6
407 |
408 | ### [0.1.1] - 2016-06-08
409 | #### Fixed
410 | - fix iOS crash on stop
411 |
412 | ### [0.1.0] - 2016-06-07
413 | #### Added
414 | - initial iOS implementation
415 |
416 | ### [0.0.1] - 2016-06-04
417 | - initial Android implementation
418 |
--------------------------------------------------------------------------------
/CHANGES_zh-Hans.md:
--------------------------------------------------------------------------------
1 | ## 变更日志
2 |
3 | ### [0.6.2] - 2019-09-10
4 | ### 变量
5 | - Android 端移除 preoreo 目标
6 | - Android 端添加 android.permission.FOREGROUND_SERVICE 权限
7 |
8 | ### [0.6.1] - 2019-08-29
9 | ### 变更
10 | - 移除过时的 isLocationEnabled 方法
11 | - Android 端用 react-native headless js 替换 jsevaluator
12 |
13 | ### [0.6.0] - 2019-08-27
14 | ### 修复
15 | - 修复 Android 端提供者(provider)冲突 (fixes #344)
16 |
17 | ### 变更
18 | - 支持 RN 0.60 的自动链接(autolinking)
19 |
20 | ### [0.5.6] - 2019-08-27
21 | ### 修复
22 | - Android API >= 26 允许从后台开启服务 (fixes #356)
23 |
24 | ### [0.5.5] - 2019-08-13
25 | ### 修复
26 | - Android 修复 ToneGenerator 闪退问题
27 | - Android 从 manifest 里删除 minSdk (fixes #357) - @maleriepace
28 | - Android 为 applicationId 添加选项检查 (PR #36 common repo) - @mysport12
29 | - Android 不会在 manifest 里声明 minSdk 版本了 @wesleycoder 和 @maleriepace
30 | - Android 改变 react-native link command 仓库地址 (PR #374) - @mantaroh
31 | - 更新 CHANGES_zh-Hans.md 翻译文档 - @Kennytian
32 | - 修正 README 里的错别字 - @diegogurpegui
33 | - 感谢所有的贡献者
34 |
35 | ### [0.5.2] - 2019-03-28
36 | ### 修复
37 | - Android 修复程序无法启动 APP VisibilityChange 事件缺陷
38 | - Android 忽略失败的 instrumentation 测试项
39 |
40 | ### [0.5.1] - 2019-03-25
41 | ### 修复
42 | - Android 修复 #360 - 当应用因其他原因崩溃时,系统会启动该服务
43 |
44 | ### [0.5.0] - 2019-01-31
45 |
46 | ### 新增
47 | - 用 startMonitoringSignificantLocationChanges 实现 iOS config.stopOnTerminate 功能
48 |
49 | Commit: [5149178c65322d04f4e9e47bd278b17cf0e4bd9a](https://github.com/mauron85/background-geolocation-ios/commit/5149178c65322d04f4e9e47bd278b17cf0e4bd9a)
50 | Origin-PR: [#7](https://github.com/mauron85/background-geolocation-ios/pull/7)
51 | Contributed-By: [@StanislavMayorov](https://github.com/StanislavMayorov)
52 |
53 | ### 修复
54 | - Android - 无法找到 Assert.assertNotNull 标识
55 |
56 | Commit: [ec334ba6a8612c399d608bbfc4aacfad68fc2105](https://github.com/mauron85/background-geolocation-android/commit/ec334ba6a8612c399d608bbfc4aacfad68fc2105)
57 | Origin-PR: [#25](https://github.com/mauron85/background-geolocation-android/pull/25)
58 | Origin-Issue: [#340](https://github.com/mauron85/react-native-background-geolocation/issues/340)
59 | Contributed-By: [@scurtoni](https://github.com/scurtoni)
60 |
61 | ### [0.5.0-alpha.XY] - 未发布
62 |
63 | 此版本提供了抽象代码以复用 React Native Cordova 插件之间变量,从而加快开发速度修复共享代码库的错误。
64 |
65 | ### 新增
66 | - 通过 `postTemplate` 配置属性来提交/同步
67 | - iOS ACTIVITY_PROVIDER(实验性)
68 | - 允许部分插件复用配置
69 | - 在 'activity' 上改变事件
70 | - Android 使用 gradle 选择权限 由 @jsdario(PR#136)
71 | - iOS 配置持久化
72 |
73 | 从 alpha.8 开始:
74 | - Android 自动 link react-native 配置
75 | - iOS checkStatus 返回位置服务的状态(locationServicesEnabled)
76 | - iOS RAW_LOCATION_PROVIDER 持续在应用终止时运行
77 |
78 | 从 alpha.10 开始:
79 | - Android checkStatus 返回位置服务的状态(locationServicesEnabled)
80 |
81 | 从 alpha.15 开始:
82 | - Android 位置参数 isFromMockProvider,mockLocationsEnabled,radius,provider
83 | - Android 无头任务
84 |
85 | 自 alpha.16 开始:
86 | - iOS 在 postlink 上添加后台模式和权限
87 | - 添加跨平台预发布脚本执行 由 @dobrynia 提供(PR#165)
88 |
89 | 从 alpha.17 开始:
90 | - Android 允许使用 ext 声明覆盖库的版本
91 |
92 | 自alpha.19 开始:
93 | - Android Oreo 实验支持
94 |
95 | 自 alpha.20 开始:
96 | - 按日期级别获取日志并按日志级别过滤的选项
97 | - 记录未捕获的异常
98 |
99 | 从 alpha.22 开始:
100 | - 方法 forceSync
101 |
102 | 从 alpha.26 开始:
103 | - Android 添加 httpHeaders 验证
104 |
105 | 从 alpha.28 开始:
106 | - 实现 getCurrentLocation
107 | - iOS 实现 getStationaryLocation
108 |
109 | 从 alpha.31 开始:
110 | - Android Gradle 3 支持(实验性)
111 |
112 | 从 alpha.37 开始:
113 | - 在原生代码中转换/过滤位置(由[@danielgindi](https://github.com/danielgindi/))
114 | 更多信息:https://github.com/mauron85/background-geolocation-android/pull/8
115 |
116 | 从 alpha.40 开始:
117 | - notificationsEnabled 配置选项(由[@danielgindi](https://github.com/danielgindi/))
118 | 更多信息:https://github.com/mauron85/react-native-background-geolocation/pull/269
119 | -允许在停止状态「285 Updates Not Required」更新位置(由[@danielgindi](https://github.com/danielgindi/))
120 | 更多信息:https://github.com/mauron85/react-native-background-geolocation/pull/271
121 |
122 | ### 变更
123 |
124 | 从 alpha.6 开始:
125 | - iOS saveBatteryOnBackground 默认为 false
126 |
127 | 从 alpha.8 开始:
128 | - 与 Cordova 共享代码库
129 |
130 | 从 alpha.11 开始:
131 | - Android 从 applicationId 派生同步权限和提供者
132 | - Android 删除 android.permission.GET_ACCOUNTS
133 |
134 | 自 alpha.19 开始:
135 | - 在 settings.gradle 中的 Android postlink 注册项目,而不是文件复制(**重大变更** - 阅读 android-setup 部分)
136 |
137 | 自 alpha.20 开始:
138 | - iOS使用Android日志格式(**重大变更**)
139 |
140 | 自 alpha.22 开始:
141 | - 满足条件时 Android 删除同步延迟
142 | - Android 认为 HTTP 201 是成功的请求
143 | - Android 服从系统同步设置
144 |
145 | 从 alpha.26 开始:
146 | - Android 仅在后台显示服务通知
147 | - Android 删除配置选项 startForeground(与上面相关)
148 | - Android 从两个 Android 提供商处删除唤醒锁(由 @grassick 提供)
149 | - Android 仅对 postTemplate 字符串值删除限制
150 |
151 | 从 alpha.28 开始:
152 | - Android 带回了 startForeground 配置选项(**重大变更**!)
153 |
154 | startForeground 的含义略有不同。
155 |
156 | 如果为 false(默认),则服务将创建通知并进行提升
157 | 当客户端从服务解除绑定时,它本身就是前台服务。
158 | 这通常发生在应用程序移至后台时。
159 | 如果应用程序正在移回前台(对用户可见)
160 | 服务会销毁通知并停止前台服务。
161 |
162 | 如果真正的服务将创建通知并始终保持在前台。
163 |
164 | 从 alpha.30 开始:
165 | - Android 内部更改(权限处理)
166 | - Android gradle 构建更改
167 |
168 | 从 alpha.38 开始:
169 | - Android 禁用 Oreo 的通知声音和振动
170 | (PR:[#9](https://github.com/mauron85/background-geolocation-android/pull/9)
171 | 由 [@danielgindi](https://github.com/danielgindi/),关闭#260)
172 |
173 | ### 修复
174 |
175 | 从 alpha.4 开始:
176 | - @asafron 可在 iOS 10 及更高版本(PR#158)上的打开 iOS 位置设置
177 |
178 | 从 alpha.8 开始:
179 | - checkStatus 授权
180 | - 修复 Android 找不到符号的编译错误
181 |
182 | 自 alpha.9 开始:
183 | - Android 修复 #118 - NullPointerException LocationService.onTaskRemoved
184 | - Android 权限 - 在运行时检查和请求权限
185 |
186 | 从 alpha.13 开始:
187 | - Android 修复 allowBackup 属性冲突
188 |
189 | 从alpha.14开始:
190 | - Android 修复#166 - 错误:含有 'com.google.android.gms.license' 多个库
191 |
192 | 从 alpha.15 开始:
193 | - Android 仅传递有效的位置参数
194 | - 停止时 iOS 重置连接状态
195 | - iOS 修复 App Store 拒绝问题 - Prefs 非公共 URL Scheme
196 |
197 | 从 alpha.17 开始:
198 | - Android 修复服务意外用默认配置或存储配置启动
199 |
200 | 从 alpha.21 开始:
201 | - Android 在 postunlink 上卸载 Android 的常用模块
202 | - Android 防止注册多个 common 项目
203 | - Android 修复一些空指针异常 92649c70e0ce0072464f47f1d096bef40047b8a6
204 | - iOS 只更新了 info.plist
205 |
206 | 从 alpha.22 开始:
207 | - Android 为防止一些逆向工程添加混淆
208 | - Android 处理配置为 null 的情况
209 |
210 | 从 alpha.25 开始:
211 | - Android 问题 #185 - 处理无效配置
212 |
213 | 从 alpha.27 开始:
214 | - iOS 修复强制同步参数
215 | - 修复 #183 - 添加 'activity' 事件侦听器时出错
216 |
217 | 从 alpha.28 开始:
218 | - iOS 在 iOS >= 10 的前台显示调试通知
219 | - iOS 修复错误消息格式
220 | - iOS 行动提供者静止不动(原文iOS activity provider stationary event)
221 |
222 | 从 alpha.35 开始:
223 | - Android getCurrentLocation 在后台线程上运行 (PR #219 by [@djereg](https://github.com/djereg/))
224 | - iOS 修复删除所有位置时崩溃的问题 ([7392e39](https://github.com/mauron85/background-geolocation-ios/commit/7392e391c3de3ff0d6f5ef2ef19c34aba612bf9b) by [@acerbetti](https://github.com/acerbetti/))
225 |
226 | 从 alpha.36 开始:
227 | - Android Defer 启动并配置,直到服务准备就绪
228 | (PR: [#7](https://github.com/mauron85/background-geolocation-android/pull/7)
229 | Commit: [00e1314](https://github.com/mauron85/background-geolocation-android/commit/00e131478ad4e37576eb85581bb663b65302a4e0) by [@danielgindi](https://github.com/danielgindi/),
230 | 修复 #201, #181, #172)
231 |
232 | 从 alpha.38 开始:
233 | - iOS 避免控制 UNUserNotificationCenter
234 | (PR: [#268](https://github.com/mauron85/react-native-background-geolocation/pull/268)
235 | by [@danielgindi](https://github.com/danielgindi/),
236 | 修复 #206, #256)
237 |
238 | ### [0.4.1] - 2017-12-19
239 | #### 变更
240 | - react native 版本必须大于 0.49.0
241 |
242 | ### [0.4.0] - 2017-12-13
243 | 发布 0.4.0
244 |
245 | ### [0.4.0-rc.3] - 2017-11-23
246 | ### 新增
247 | - iOS 在后台同步时发送 http headers
248 |
249 | ### [0.4.0-rc.2] - 2017-11-13
250 |
251 | ### 修复
252 | - Android ConfigMapper mapToConfig 缺少配置属性(修复#122)
253 |
254 | ### 新增
255 | - Android 为 getLocations 方法返回 location id
256 |
257 | ### [0.4.0-rc.1] - 2017-11-10
258 |
259 | ### 修复
260 | - 修复 iOS 在配置之前调用 getConfig 方法
261 |
262 | #### 新增
263 | - checkStatus 判断服务是否正在运行
264 | - 事件 [start, stop, authorization, background, foreground]
265 | - 实现两个平台的所有方法
266 | - RAW_LOCATION_PROVIDER 模式
267 |
268 | #### 变更
269 | - start 和 stop 方法不接受回调(改为使用事件监听器)
270 | - syncUrl 为后台同步的必填项
271 | - Android 上的 DISTANCE_FILTER_PROVIDER 现在接受任意值(之前只能 10, 100, 1000 之前选择)
272 | - 所有插件常量都直接在 BackgroundGeolocation 命名空间中。(查看 index.js)
273 | - 可以在不执行 configure 的情况下启动插件(使用存储的设置或默认值)
274 | - location 属性 locationId 重命名为 id
275 | - iOS pauseLocationUpdates 现在默认为 false(因为 iOS 文档现在声明如果将其设置为true,则需要手动重启)
276 | - iOS finish 方法替换为 startTask 和 endTask
277 |
278 | ### [0.3.3] - 2017-11-01
279 | #### 修复
280 | - 状态码是 201 时 Android 也应该同步位置 (PR #71)
281 |
282 | ### [0.3.2] - 2017-11-01
283 | #### 修复
284 | - 为 iOS 实现 isLocationEnabled 属性(PR #92)
285 |
286 | ### [0.3.1] - 2017-10-04
287 | #### 修复
288 | - (tpisto) React Native 0.48.x 中的 iOS 编译错误(修复#108)
289 |
290 | ### [0.3.0-alpha.1] - 2017-08-15
291 | #### 修复
292 | - 兼容 iOS RN 0.47 版 (修复 #95)
293 |
294 | ### [0.2.0-alpha.7] - 2017-03-21
295 | #### 修复
296 | - 修复 iOS 问题 #44
297 |
298 | ### [0.2.0-alpha.6] - 2017-02-18
299 | #### 修复
300 | - 兼容 iOS RN 0.40 版
301 |
302 | ### [0.2.0-alpha.5] - 2016-09-15
303 | #### 修复
304 | - 修复 Android 问题 #10
305 |
306 | ### [0.2.0-alpha.4] - 2016-09-10
307 | #### 修复
308 | - 修复了 Android 在未配置插件时销毁的崩溃问题
309 |
310 | ### [0.2.0-alpha.3] - 2016-09-07
311 | #### 修复
312 | - 修复 Android 问题 #10 - 刷新时崩溃
313 |
314 | #### 新增
315 | - Android onStationary 方法
316 | - Android getLogEntries 方法
317 |
318 | #### 删除
319 | - Android 位置过滤
320 |
321 | #### 变更
322 | - Android 项目目录结构
323 | (请阅读更新安装说明)
324 | - 用 Android 数据库代替文件来记录日志
325 |
326 | ### [0.2.0-alpha.2] - 2016-08-31
327 | #### 修复
328 | - 修复 config 参数无法保持的问题
329 | - 临时修复 Android 时间长到 int 型转换
330 |
331 | #### 新增
332 | - Android isLocationEnabled 属性
333 | - Android showAppSettings 方法
334 | - Android showLocationSettings 方法
335 | - Android getLocations 方法
336 | - Android getConfig 方法
337 |
338 | ### [0.2.0-alpha.1] - 2016-08-17
339 | #### 变更
340 | - 为适配 cordova 2.2.0-alpha.6 升级插件
341 |
342 | ### [0.1.1] - 2016-06-08
343 | #### 修复
344 | - 修复 iOS 停止时崩溃问题
345 |
346 | ### [0.1.0] - 2016-06-07
347 | #### 新增
348 | - 初始 iOS 实现
349 |
350 | ### [0.0.1] - 2016-06-04
351 | - 初始 Android 实现
352 |
--------------------------------------------------------------------------------
/CONTRIBUTORS.md:
--------------------------------------------------------------------------------
1 | Many thanks to all contributors
2 |
3 | * [christocracy](https://github.com/christocracy)
4 | * [huttj](https://github.com/huttj)
5 | * [erikkemperman](https://github.com/erikkemperman)
6 | * [codebling](https://github.com/codebling)
7 | * [pmwisdom](https://github.com/pmwisdom)
8 | * [dobrynia](https://github.com/dobrynia)
9 |
--------------------------------------------------------------------------------
/DISTANCE_FILTER_PROVIDER.md:
--------------------------------------------------------------------------------
1 | ## Behaviour
2 |
3 | This provider has features allowing you to control the behaviour of background-tracking, striking a balance between accuracy and battery-usage. In stationary-mode, the plugin attempts to decrease its power usage and accuracy by setting up a circular stationary-region of configurable `stationaryRadius`. iOS has a nice system [Significant Changes API](https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/CLLocationManager/CLLocationManager.html#//apple_ref/occ/instm/CLLocationManager/startMonitoringSignificantLocationChanges), which allows the os to suspend your app until a cell-tower change is detected (typically 2-3 city-block change) Android uses [LocationManager#addProximityAlert](http://developer.android.com/reference/android/location/LocationManager.html).
4 |
5 | When the plugin detects your user has moved beyond his stationary-region, it engages the native platform's geolocation system for aggressive monitoring according to the configured `desiredAccuracy`, `distanceFilter` and `interval`. The plugin attempts to intelligently scale `distanceFilter` based upon the current reported speed. Each time `distanceFilter` is determined to have changed by 5m/s, it recalculates it by squaring the speed rounded-to-nearest-five and adding `distanceFilter` (I arbitrarily came up with that formula. Better ideas?).
6 |
7 | `(round(speed, 5))^2 + distanceFilter`
8 |
9 | ### distanceFilter
10 | is calculated as the square of speed-rounded-to-nearest-5 and adding configured #distanceFilter.
11 |
12 | `(round(speed, 5))^2 + distanceFilter`
13 |
14 | For example, at biking speed of 7.7 m/s with a configured distanceFilter of 30m:
15 |
16 | `=> round(7.7, 5)^2 + 30`
17 | `=> (10)^2 + 30`
18 | `=> 100 + 30`
19 | `=> 130`
20 |
21 | A gps location will be recorded each time the device moves 130m.
22 |
23 | At highway speed of 30 m/s with distanceFilter: 30,
24 |
25 | `=> round(30, 5)^2 + 30`
26 | `=> (30)^2 + 30`
27 | `=> 900 + 30`
28 | `=> 930`
29 |
30 | A gps location will be recorded every 930m
31 |
32 | Note the following real example of background-geolocation on highway 101 towards San Francisco as the driver slows down as he runs into slower traffic (geolocations become compressed as distanceFilter decreases)
33 |
34 | 
35 |
36 | Compare now background-geolocation in the scope of a city. In this image, the left-hand track is from a cab-ride, while the right-hand track is walking speed.
37 |
38 | 
39 |
40 | **NOTE:** `distanceFilter` is elastically auto-calculated by the plugin: When speed increases, distanceFilter increases; when speed decreases, so does distanceFilter.
41 |
--------------------------------------------------------------------------------
/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | ## Your Environment
5 |
6 |
7 | * Plugin version:
8 | * Platform: iOS or Android
9 | * OS version:
10 | * Device manufacturer and model:
11 |
12 | * Running in Simulator:
13 | * React Native version:
14 | * Plugin configuration options:
15 | * Link to your project:
16 |
17 | ## Context
18 |
19 |
20 | ## Expected Behavior
21 |
22 |
23 | ## Actual Behavior
24 |
25 |
26 | ## Possible Fix
27 |
28 |
29 | ## Steps to Reproduce
30 |
31 |
32 | 1.
33 | 2.
34 | 3.
35 | 4.
36 |
37 | ## Context
38 |
39 |
40 | ## Debug logs
41 |
44 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/PROVIDERS.md:
--------------------------------------------------------------------------------
1 | # Location providers
2 |
3 | ## Which provider should I use?
4 |
5 | ### DISTANCE_FILTER_PROVIDER
6 |
7 | This is classic provider, originally from cristocracy. It's best to use this one as background location provider. It is using Stationary API and elastic distance filter to achieve optimal battery and data usage. You can read more about this provider in [DISTANCE_FILTER_PROVIDER.md](/DISTANCE_FILTER_PROVIDER.md).
8 |
9 | ### ACTIVITY_PROVIDER (Android only)
10 |
11 | This one is best to use as foreground location provider (but works in background as well). It uses Android FusedLocationProviderApi and ActivityRecognitionApi for maximum battery saving. This provider is alternative to w3c ```window.navigator.watchPosition```, but you're in control how often should updates be polled from GPS. Slower updates means lower battery consumption. You can adjust position update interval by settings options ```interval``` and ```fastestInterval```. Option ```fastestInterval``` is used, when there are other apps asking for positions. In that case your app can be updated more often and ```fastestInterval``` is the upper limit of how fast can your app process location updates. Option ```activitiesInterval``` specifies how often activity recognition occurs. Larger values will result in fewer activity detections while improving battery life. Smaller values will result in more frequent activity detections but will consume more power since the device must be woken up more frequently
12 |
13 | ### RAW_PROVIDER
14 |
15 | This provider doesn't do any location processing, but rather returns locations as recorded by device sensors.
16 |
--------------------------------------------------------------------------------
/android/README.md:
--------------------------------------------------------------------------------
1 | # Run tests
2 |
3 | # Unit
4 |
5 | Notice: currently not possible - [read explanation](lib/src/test/java/com/marianhello/bgloc/react/ConfigMapperTest.java)
6 |
7 | ```
8 | ndkDir=$(pwd)/react-ndk/all/x86_64 \
9 | JAVA_OPTS="-Djava.library.path=\".:$ndkDir\"" \
10 | LD_LIBRARY_PATH="$ndkDir:$LD_LIBRARY_PATH" ./gradlew lib:test
11 | ```
12 |
13 | # Instrumented
14 |
15 | Test, that run on android device can be run from Android Studio.
16 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 |
2 | buildscript {
3 | repositories {
4 | maven {
5 | url 'https://maven.google.com/'
6 | name 'Google'
7 | }
8 | jcenter()
9 | }
10 | dependencies {
11 | classpath 'com.android.tools.build:gradle:3.4.1'
12 | }
13 | }
14 |
15 | allprojects {
16 | repositories {
17 | mavenLocal()
18 | maven {
19 | // All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
20 | url "$rootDir/../node_modules/react-native/android"
21 | }
22 | maven {
23 | url 'https://maven.google.com/'
24 | name 'Google'
25 | }
26 | jcenter()
27 | // repo for react-native
28 | // https://mvnrepository.com/artifact/com.facebook.react/react-native?repo=springio-plugins-release
29 | maven {
30 | url 'http://repo.spring.io/plugins-release/'
31 | name 'Spring Plugins'
32 | }
33 | }
34 | }
35 |
36 | ext {
37 | reactNativeLibVersion = "0.55.3"
38 | }
39 |
40 | task clean(type: Delete) {
41 | delete rootProject.buildDir
42 | }
--------------------------------------------------------------------------------
/android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 |
3 | # IDE (e.g. Android Studio) users:
4 | # Gradle settings configured through the IDE *will override*
5 | # any settings specified in this file.
6 |
7 | # For more details on how to configure your build environment visit
8 | # http://www.gradle.org/docs/current/userguide/build_environment.html
9 |
10 | # Specifies the JVM arguments used for the daemon process.
11 | # The setting is particularly useful for tweaking memory settings.
12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m
13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14 |
15 | # When configured, Gradle will run in incubating parallel mode.
16 | # This option should only be used with decoupled projects. More details, visit
17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18 | # org.gradle.parallel=true
19 |
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mauron85/react-native-background-geolocation/f0d434291cfae4a0e510e1e7a05d4e1e7508870e/android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn ( ) {
37 | echo "$*"
38 | }
39 |
40 | die ( ) {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158 | function splitJvmOpts() {
159 | JVM_OPTS=("$@")
160 | }
161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163 |
164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
165 |
--------------------------------------------------------------------------------
/android/lib/build.gradle:
--------------------------------------------------------------------------------
1 | // Notice: Oreo builds are disabled by default until all problems are resolved!!!
2 | //
3 | // For Oreo compatibility we are forced to use supportLibVersion >= 26.1.0
4 | // Unfortunately Android stopped supporting downloading libraries through the SDK Manager,
5 | // @see https://developer.android.com/topic/libraries/support-library/setup.html
6 | //
7 | // You can enable oreo by adding following into root build.gradle:
8 | //
9 | // allprojects {
10 | // repositories {
11 | // maven { url 'https://maven.google.com' }
12 | // }
13 | // }
14 | //
15 | // ext {
16 | // compileSdkVersion = 26
17 | // targetSdkVersion = 26
18 | // buildToolsVersion = "26.0.2"
19 | // supportLibVersion = "26.1.0"
20 | // googlePlayServicesVersion = "11.8.0"
21 | // }
22 | //
23 | //
24 | // If you don't like this please ask react guys nicely to add google maven repo into
25 | // their templates.
26 |
27 | apply plugin: 'com.android.library'
28 |
29 | apply from: '../common/VERSIONS.gradle'
30 | def hasApp = findProject(':app') != null
31 |
32 | // https://hackernoon.com/android-how-to-add-gradle-dependencies-using-foreach-c4cbcc070458
33 | def projDependencies = [
34 | [configuration: "implementation", dependency: libs.slf4j],
35 | [configuration: "implementation", dependency: libs.reactNative],
36 | [configuration: "testImplementation", dependency: testLibs.testRunner],
37 | [configuration: "testImplementation", dependency: testLibs.testRules],
38 | [configuration: "testImplementation", dependency: testLibs.junit],
39 | [configuration: "testImplementation", dependency: testLibs.powermockMockito],
40 | [configuration: "testImplementation", dependency: testLibs.powermockjUnit],
41 | [configuration: "testImplementation", dependency: testLibs.powermockClassloading],
42 | [configuration: "testImplementation", dependency: testLibs.mockitoCore],
43 | [configuration: "testImplementation", dependency: testLibs.festAssertCore],
44 | [configuration: "testImplementation", dependency: testLibs.robolectric],
45 | [configuration: "androidTestImplementation", dependency: testLibs.testRunner],
46 | [configuration: "androidTestImplementation", dependency: testLibs.testRules],
47 | ]
48 |
49 | repositories {
50 | // Google dependencies are now hosted at Maven
51 | // unfortunately this is ignored when installing as react-native plugin
52 | maven {
53 | url 'https://maven.google.com'
54 | }
55 | jcenter()
56 | }
57 |
58 | android {
59 | compileSdkVersion project.ext.getCompileSdkVersion()
60 | buildToolsVersion project.ext.getBuildToolsVersion()
61 | if (hasApp) {
62 | evaluationDependsOn(':app')
63 | }
64 |
65 | // Tip: https://stackoverflow.com/questions/39987669/renamingdelegatingcontext-is-deprecated-how-do-we-test-sqlite-db-now/52170737#52170737
66 | // Gradle automatically adds 'android.test.runner' as a dependency.
67 | useLibrary 'android.test.runner'
68 | useLibrary 'android.test.base'
69 | useLibrary 'android.test.mock'
70 |
71 | defaultConfig {
72 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
73 | minSdkVersion project.ext.getMinSdkVersion()
74 | targetSdkVersion project.ext.getTargetSdkVersion()
75 | versionCode 1 // intentionally not updating version as we're not uploading to any java repository
76 | versionName "1.0"
77 | }
78 |
79 | lintOptions {
80 | abortOnError false
81 | }
82 | }
83 |
84 | dependencies {
85 | implementation project(path: ':@mauron85_react-native-background-geolocation-common')
86 |
87 | projDependencies.each {
88 | add(it.configuration, it.dependency)
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/android/lib/src/androidTest/java/com/marianhello/bgloc/react/ConfigMapperTest.java:
--------------------------------------------------------------------------------
1 | package com.marianhello.bgloc.react;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 | import android.support.test.filters.SmallTest;
7 |
8 | import com.facebook.react.bridge.Arguments;
9 | import com.facebook.react.bridge.ReadableMap;
10 | import com.facebook.react.bridge.WritableMap;
11 | import com.facebook.soloader.SoLoader;
12 | import com.marianhello.bgloc.Config;
13 | import com.marianhello.bgloc.data.ArrayListLocationTemplate;
14 | import com.marianhello.bgloc.data.HashMapLocationTemplate;
15 | import com.marianhello.bgloc.data.LocationTemplate;
16 | import com.marianhello.bgloc.data.LocationTemplateFactory;
17 |
18 | import junit.framework.Assert;
19 |
20 | import org.json.JSONException;
21 | import org.junit.Before;
22 | import org.junit.Test;
23 | import org.junit.runner.RunWith;
24 |
25 | import java.io.IOException;
26 | import java.util.ArrayList;
27 | import java.util.HashMap;
28 |
29 | @RunWith(AndroidJUnit4.class)
30 | @SmallTest
31 | public class ConfigMapperTest {
32 |
33 | private Context mContext;
34 |
35 | @Before
36 | public void setUp() throws IOException {
37 | Context mContext = InstrumentationRegistry.getContext();
38 | SoLoader.init(mContext, 0);
39 | }
40 |
41 | @Test
42 | public void testDefaultToJSONObject() {
43 | Config config = Config.getDefault();
44 | ReadableMap map = ConfigMapper.toMap(config);
45 |
46 | Assert.assertEquals(config.getStationaryRadius(), map.getDouble("stationaryRadius"), 0f);
47 | Assert.assertEquals(config.getDistanceFilter().intValue(), map.getInt("distanceFilter"));
48 | Assert.assertEquals(config.getDesiredAccuracy().intValue(), map.getInt("desiredAccuracy"));
49 | Assert.assertEquals(config.isDebugging().booleanValue(), map.getBoolean("debug"));
50 | Assert.assertEquals(config.getNotificationTitle(), map.getString("notificationTitle"));
51 | Assert.assertEquals(config.getNotificationText(), map.getString("notificationText"));
52 | Assert.assertEquals(config.getStopOnTerminate().booleanValue(), map.getBoolean("stopOnTerminate"));
53 | Assert.assertEquals(config.getStartOnBoot().booleanValue(), map.getBoolean("startOnBoot"));
54 | Assert.assertEquals(config.getLocationProvider().intValue(), map.getInt("locationProvider"));
55 | Assert.assertEquals(config.getInterval().intValue(), map.getInt("interval"));
56 | Assert.assertEquals(config.getFastestInterval().intValue(), map.getInt("fastestInterval"));
57 | Assert.assertEquals(config.getActivitiesInterval().intValue(), map.getInt("activitiesInterval"));
58 | Assert.assertEquals(config.getNotificationIconColor(), map.getString("notificationIconColor"));
59 | Assert.assertEquals(config.getLargeNotificationIcon(), map.getString("notificationIconLarge"));
60 | Assert.assertEquals(config.getSmallNotificationIcon(), map.getString("notificationIconSmall"));
61 | Assert.assertEquals(config.getStartForeground().booleanValue(), map.getBoolean("startForeground"));
62 | Assert.assertEquals(config.getStopOnStillActivity().booleanValue(), map.getBoolean("stopOnStillActivity"));
63 | Assert.assertEquals(config.getUrl(), map.getString("url"));
64 | Assert.assertEquals(config.getSyncUrl(), map.getString("syncUrl"));
65 | Assert.assertEquals(config.getSyncThreshold().intValue(), map.getInt("syncThreshold"));
66 | Assert.assertEquals(config.getHttpHeaders(), map.getMap("httpHeaders").toHashMap());
67 | Assert.assertEquals(config.getMaxLocations().intValue(), map.getInt("maxLocations"));
68 | Assert.assertEquals(LocationTemplateFactory.getDefault(), LocationTemplateFactory.fromHashMap(map.getMap("postTemplate").toHashMap()));
69 | }
70 |
71 | @Test
72 | public void testNullableProps() throws JSONException {
73 | WritableMap map = Arguments.createMap();
74 | map.putNull("url");
75 | map.putNull("syncUrl");
76 | map.putNull("notificationIconColor");
77 | map.putNull("notificationTitle");
78 | map.putNull("notificationText");
79 | map.putNull("notificationIconLarge");
80 | map.putNull("notificationIconSmall");
81 |
82 | Config config = ConfigMapper.fromMap((ReadableMap)map);
83 |
84 | Assert.assertEquals(Config.NullString, config.getUrl());
85 | Assert.assertTrue(config.hasUrl());
86 | Assert.assertFalse(config.hasValidUrl());
87 |
88 | Assert.assertEquals(Config.NullString, config.getSyncUrl());
89 | Assert.assertTrue(config.hasSyncUrl());
90 | Assert.assertFalse(config.hasValidSyncUrl());
91 |
92 | Assert.assertEquals(Config.NullString, config.getNotificationIconColor());
93 | Assert.assertFalse(config.hasNotificationIconColor());
94 |
95 | Assert.assertEquals(Config.NullString, config.getNotificationTitle());
96 | Assert.assertTrue(config.hasNotificationTitle());
97 |
98 | Assert.assertEquals(Config.NullString, config.getNotificationText());
99 | Assert.assertTrue(config.hasNotificationText());
100 |
101 | Assert.assertEquals(Config.NullString, config.getLargeNotificationIcon());
102 | Assert.assertFalse(config.hasLargeNotificationIcon());
103 |
104 | Assert.assertEquals(Config.NullString, config.getSmallNotificationIcon());
105 | Assert.assertFalse(config.hasSmallNotificationIcon());
106 | }
107 |
108 | @Test
109 | public void testNullablePropsToJSONObject() throws JSONException {
110 | Config config = new Config();
111 | config.setUrl(Config.NullString);
112 | config.setSyncUrl(Config.NullString);
113 | config.setNotificationIconColor(Config.NullString);
114 | config.setNotificationTitle(Config.NullString);
115 | config.setNotificationText(Config.NullString);
116 | config.setLargeNotificationIcon(Config.NullString);
117 | config.setSmallNotificationIcon(Config.NullString);
118 |
119 | ReadableMap map = ConfigMapper.toMap(config);
120 |
121 | Assert.assertEquals(null, map.getString("url"));
122 | Assert.assertEquals(null, map.getString("syncUrl"));
123 | Assert.assertEquals(null, map.getString("notificationIconColor"));
124 | Assert.assertEquals(null, map.getString("notificationTitle"));
125 | Assert.assertEquals(null, map.getString("notificationText"));
126 | Assert.assertEquals(null, map.getString("notificationIconLarge"));
127 | Assert.assertEquals(null, map.getString("notificationIconSmall"));
128 | }
129 |
130 | @Test
131 | public void testNullHashMapTemplateToJSONObject() {
132 | Config config = new Config();
133 | LocationTemplate tpl = new HashMapLocationTemplate((HashMap)null);
134 | config.setTemplate(tpl);
135 |
136 | ReadableMap jConfig = ConfigMapper.toMap(config);
137 | Assert.assertEquals(null, jConfig.getMap("postTemplate"));
138 | }
139 |
140 | @Test
141 | public void testEmptyHashMapTemplateToJSONObject() {
142 | Config config = new Config();
143 | HashMap map = new HashMap();
144 | LocationTemplate tpl = new HashMapLocationTemplate(map);
145 | config.setTemplate(tpl);
146 |
147 | ReadableMap jConfig = ConfigMapper.toMap(config);
148 | Assert.assertFalse(jConfig.getMap("postTemplate").keySetIterator().hasNextKey());
149 | }
150 |
151 | @Test
152 | public void testHashMapTemplateToJSONObject() {
153 | Config config = new Config();
154 | HashMap map = new HashMap();
155 | map.put("foo", "bar");
156 | map.put("pretzels", 123);
157 | LocationTemplate tpl = new HashMapLocationTemplate(map);
158 | config.setTemplate(tpl);
159 |
160 | ReadableMap jConfig = ConfigMapper.toMap(config);
161 | Assert.assertEquals("{ NativeMap: {\"foo\":\"bar\",\"pretzels\":123} }", jConfig.getMap("postTemplate").toString());
162 | }
163 |
164 | @Test
165 | public void testNullArrayListLocationTemplateToJSONObject() {
166 | Config config = new Config();
167 | LocationTemplate tpl = new ArrayListLocationTemplate((ArrayListLocationTemplate)null);
168 | config.setTemplate(tpl);
169 |
170 | ReadableMap jConfig = ConfigMapper.toMap(config);
171 | Assert.assertEquals(null, jConfig.getMap("postTemplate"));
172 | }
173 |
174 | @Test
175 | public void testEmptyArrayListLocationTemplateToJSONObject() {
176 | Config config = new Config();
177 | ArrayList list = new ArrayList();
178 | LocationTemplate tpl = new ArrayListLocationTemplate(list);
179 | config.setTemplate(tpl);
180 |
181 | ReadableMap jConfig = ConfigMapper.toMap(config);
182 | Assert.assertTrue(jConfig.getArray("postTemplate").size() == 0);
183 | }
184 |
185 | @Test
186 | public void testArrayListLocationTemplateToJSONObject() {
187 | Config config = new Config();
188 | ArrayList list = new ArrayList();
189 | list.add("foo");
190 | list.add(123);
191 | list.add("foo");
192 |
193 | LocationTemplate tpl = new ArrayListLocationTemplate(list);
194 | config.setTemplate(tpl);
195 |
196 | ReadableMap jConfig = ConfigMapper.toMap(config);
197 | Assert.assertEquals("[\"foo\",123,\"foo\"]", jConfig.getArray("postTemplate").toString());
198 | }
199 | }
--------------------------------------------------------------------------------
/android/lib/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
20 |
22 |
23 |
27 |
28 |
29 |
30 |
32 |
33 |
35 |
36 |
37 |
38 |
41 |
42 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/android/lib/src/main/java/com/iodine/start/ArrayUtil.java:
--------------------------------------------------------------------------------
1 |
2 | /*
3 | ArrayUtil exposes a set of helper methods for working with
4 | ReadableArray (by React Native), Object[], and JSONArray.
5 | */
6 |
7 | package com.iodine.start;
8 |
9 | import com.facebook.react.bridge.Arguments;
10 | import com.facebook.react.bridge.ReadableArray;
11 | import com.facebook.react.bridge.ReadableType;
12 | import com.facebook.react.bridge.WritableArray;
13 |
14 | import java.util.Map;
15 |
16 | import org.json.JSONArray;
17 | import org.json.JSONObject;
18 | import org.json.JSONException;
19 |
20 | public class ArrayUtil {
21 |
22 | public static JSONArray toJSONArray(ReadableArray readableArray) throws JSONException {
23 | JSONArray jsonArray = new JSONArray();
24 |
25 | for (int i = 0; i < readableArray.size(); i++) {
26 | ReadableType type = readableArray.getType(i);
27 |
28 | switch (type) {
29 | case Null:
30 | jsonArray.put(i, null);
31 | break;
32 | case Boolean:
33 | jsonArray.put(i, readableArray.getBoolean(i));
34 | break;
35 | case Number:
36 | jsonArray.put(i, readableArray.getDouble(i));
37 | break;
38 | case String:
39 | jsonArray.put(i, readableArray.getString(i));
40 | break;
41 | case Map:
42 | jsonArray.put(i, MapUtil.toJSONObject(readableArray.getMap(i)));
43 | break;
44 | case Array:
45 | jsonArray.put(i, ArrayUtil.toJSONArray(readableArray.getArray(i)));
46 | break;
47 | }
48 | }
49 |
50 | return jsonArray;
51 | }
52 |
53 | public static Object[] toArray(JSONArray jsonArray) throws JSONException {
54 | Object[] array = new Object[jsonArray.length()];
55 |
56 | for (int i = 0; i < jsonArray.length(); i++) {
57 | Object value = jsonArray.get(i);
58 |
59 | if (value instanceof JSONObject) {
60 | value = MapUtil.toMap((JSONObject) value);
61 | }
62 | if (value instanceof JSONArray) {
63 | value = ArrayUtil.toArray((JSONArray) value);
64 | }
65 |
66 | array[i] = value;
67 | }
68 |
69 | return array;
70 | }
71 |
72 | public static Object[] toArray(ReadableArray readableArray) {
73 | Object[] array = new Object[readableArray.size()];
74 |
75 | for (int i = 0; i < readableArray.size(); i++) {
76 | ReadableType type = readableArray.getType(i);
77 |
78 | switch (type) {
79 | case Null:
80 | array[i] = null;
81 | break;
82 | case Boolean:
83 | array[i] = readableArray.getBoolean(i);
84 | break;
85 | case Number:
86 | array[i] = readableArray.getDouble(i);
87 | break;
88 | case String:
89 | array[i] = readableArray.getString(i);
90 | break;
91 | case Map:
92 | array[i] = MapUtil.toMap(readableArray.getMap(i));
93 | break;
94 | case Array:
95 | array[i] = ArrayUtil.toArray(readableArray.getArray(i));
96 | break;
97 | }
98 | }
99 |
100 | return array;
101 | }
102 |
103 | public static WritableArray toWritableArray(Object[] array) {
104 | WritableArray writableArray = Arguments.createArray();
105 |
106 | for (int i = 0; i < array.length; i++) {
107 | Object value = array[i];
108 |
109 | if (value == null) {
110 | writableArray.pushNull();
111 | }
112 | if (value instanceof Boolean) {
113 | writableArray.pushBoolean((Boolean) value);
114 | }
115 | if (value instanceof Double) {
116 | writableArray.pushDouble((Double) value);
117 | }
118 | if (value instanceof Integer) {
119 | writableArray.pushInt((Integer) value);
120 | }
121 | if (value instanceof String) {
122 | writableArray.pushString((String) value);
123 | }
124 | if (value instanceof Map) {
125 | writableArray.pushMap(MapUtil.toWritableMap((Map) value));
126 | }
127 | if (value.getClass().isArray()) {
128 | writableArray.pushArray(ArrayUtil.toWritableArray((Object[]) value));
129 | }
130 | }
131 |
132 | return writableArray;
133 | }
134 | }
--------------------------------------------------------------------------------
/android/lib/src/main/java/com/iodine/start/MapUtil.java:
--------------------------------------------------------------------------------
1 | /*
2 | MapUtil exposes a set of helper methods for working with
3 | ReadableMap (by React Native), Map, and JSONObject.
4 | */
5 |
6 | package com.iodine.start;
7 |
8 | import com.facebook.react.bridge.Arguments;
9 | import com.facebook.react.bridge.ReadableMap;
10 | import com.facebook.react.bridge.ReadableMapKeySetIterator;
11 | import com.facebook.react.bridge.ReadableType;
12 | import com.facebook.react.bridge.WritableMap;
13 |
14 | import java.util.Map;
15 | import java.util.HashMap;
16 | import java.util.Iterator;
17 |
18 | import org.json.JSONArray;
19 | import org.json.JSONObject;
20 | import org.json.JSONException;
21 |
22 | public class MapUtil {
23 |
24 | public static JSONObject toJSONObject(ReadableMap readableMap) throws JSONException {
25 | JSONObject jsonObject = new JSONObject();
26 |
27 | ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
28 |
29 | while (iterator.hasNextKey()) {
30 | String key = iterator.nextKey();
31 | ReadableType type = readableMap.getType(key);
32 |
33 | switch (type) {
34 | case Null:
35 | jsonObject.put(key, null);
36 | break;
37 | case Boolean:
38 | jsonObject.put(key, readableMap.getBoolean(key));
39 | break;
40 | case Number:
41 | jsonObject.put(key, readableMap.getDouble(key));
42 | break;
43 | case String:
44 | jsonObject.put(key, readableMap.getString(key));
45 | break;
46 | case Map:
47 | jsonObject.put(key, MapUtil.toJSONObject(readableMap.getMap(key)));
48 | break;
49 | case Array:
50 | jsonObject.put(key, ArrayUtil.toJSONArray(readableMap.getArray(key)));
51 | break;
52 | }
53 | }
54 |
55 | return jsonObject;
56 | }
57 |
58 | public static Map toMap(JSONObject jsonObject) throws JSONException {
59 | Map map = new HashMap<>();
60 | Iterator iterator = jsonObject.keys();
61 |
62 | while (iterator.hasNext()) {
63 | String key = iterator.next();
64 | Object value = jsonObject.get(key);
65 |
66 | if (value instanceof JSONObject) {
67 | value = MapUtil.toMap((JSONObject) value);
68 | }
69 | if (value instanceof JSONArray) {
70 | value = ArrayUtil.toArray((JSONArray) value);
71 | }
72 |
73 | map.put(key, value);
74 | }
75 |
76 | return map;
77 | }
78 |
79 | public static Map toMap(ReadableMap readableMap) {
80 | Map map = new HashMap<>();
81 | ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
82 |
83 | while (iterator.hasNextKey()) {
84 | String key = iterator.nextKey();
85 | ReadableType type = readableMap.getType(key);
86 |
87 | switch (type) {
88 | case Null:
89 | map.put(key, null);
90 | break;
91 | case Boolean:
92 | map.put(key, readableMap.getBoolean(key));
93 | break;
94 | case Number:
95 | map.put(key, readableMap.getDouble(key));
96 | break;
97 | case String:
98 | map.put(key, readableMap.getString(key));
99 | break;
100 | case Map:
101 | map.put(key, MapUtil.toMap(readableMap.getMap(key)));
102 | break;
103 | case Array:
104 | map.put(key, ArrayUtil.toArray(readableMap.getArray(key)));
105 | break;
106 | }
107 | }
108 |
109 | return map;
110 | }
111 |
112 | public static WritableMap toWritableMap(Map map) {
113 | WritableMap writableMap = Arguments.createMap();
114 | Iterator iterator = map.entrySet().iterator();
115 |
116 | while (iterator.hasNext()) {
117 | Map.Entry pair = (Map.Entry)iterator.next();
118 | Object value = pair.getValue();
119 |
120 | if (value == null) {
121 | writableMap.putNull((String) pair.getKey());
122 | } else if (value instanceof Boolean) {
123 | writableMap.putBoolean((String) pair.getKey(), (Boolean) value);
124 | } else if (value instanceof Double) {
125 | writableMap.putDouble((String) pair.getKey(), (Double) value);
126 | } else if (value instanceof Integer) {
127 | writableMap.putInt((String) pair.getKey(), (Integer) value);
128 | } else if (value instanceof String) {
129 | writableMap.putString((String) pair.getKey(), (String) value);
130 | } else if (value instanceof Map) {
131 | writableMap.putMap((String) pair.getKey(), MapUtil.toWritableMap((Map) value));
132 | } else if (value.getClass() != null && value.getClass().isArray()) {
133 | writableMap.putArray((String) pair.getKey(), ArrayUtil.toWritableArray((Object[]) value));
134 | }
135 | }
136 |
137 | return writableMap;
138 | }
139 | }
--------------------------------------------------------------------------------
/android/lib/src/main/java/com/marianhello/bgloc/react/BackgroundGeolocationModule.java:
--------------------------------------------------------------------------------
1 | package com.marianhello.bgloc.react;
2 |
3 | import android.content.Context;
4 |
5 | import com.facebook.react.bridge.Arguments;
6 | import com.facebook.react.bridge.Callback;
7 | import com.facebook.react.bridge.LifecycleEventListener;
8 | import com.facebook.react.bridge.ReactApplicationContext;
9 | import com.facebook.react.bridge.ReactContextBaseJavaModule;
10 | import com.facebook.react.bridge.ReactMethod;
11 | import com.facebook.react.bridge.ReadableMap;
12 | import com.facebook.react.bridge.WritableArray;
13 | import com.facebook.react.bridge.WritableMap;
14 | import com.facebook.react.modules.core.DeviceEventManagerModule;
15 | import com.marianhello.bgloc.BackgroundGeolocationFacade;
16 | import com.marianhello.bgloc.Config;
17 | import com.marianhello.bgloc.PluginDelegate;
18 | import com.marianhello.bgloc.PluginException;
19 | import com.marianhello.bgloc.data.BackgroundActivity;
20 | import com.marianhello.bgloc.data.BackgroundLocation;
21 | import com.marianhello.bgloc.react.data.LocationMapper;
22 | import com.marianhello.bgloc.react.headless.HeadlessTaskRunner;
23 | import com.marianhello.logging.LogEntry;
24 | import com.marianhello.logging.LoggerManager;
25 |
26 | import org.json.JSONException;
27 |
28 | import java.util.Collection;
29 |
30 | public class BackgroundGeolocationModule extends ReactContextBaseJavaModule implements LifecycleEventListener, PluginDelegate {
31 |
32 | public static final String LOCATION_EVENT = "location";
33 | public static final String STATIONARY_EVENT = "stationary";
34 | public static final String ACTIVITY_EVENT = "activity";
35 |
36 | public static final String FOREGROUND_EVENT = "foreground";
37 | public static final String BACKGROUND_EVENT = "background";
38 | public static final String AUTHORIZATION_EVENT = "authorization";
39 |
40 | public static final String START_EVENT = "start";
41 | public static final String STOP_EVENT = "stop";
42 | public static final String ABORT_REQUESTED_EVENT = "abort_requested";
43 | public static final String HTTP_AUTHORIZATION_EVENT = "http_authorization";
44 | public static final String ERROR_EVENT = "error";
45 |
46 | private static final int PERMISSIONS_REQUEST_CODE = 1;
47 |
48 | private BackgroundGeolocationFacade facade;
49 | private org.slf4j.Logger logger;
50 |
51 | public static class ErrorMap {
52 | public static ReadableMap from(String message, int code) {
53 | WritableMap out = Arguments.createMap();
54 | out.putInt("code", code);
55 | out.putString("message", message);
56 | return out;
57 | }
58 |
59 | public static ReadableMap from(String message, Throwable cause, int code) {
60 | WritableMap out = Arguments.createMap();
61 | out.putInt("code", code);
62 | out.putString("message", message);
63 | out.putMap("cause", from(cause));
64 | return out;
65 | }
66 |
67 | public static ReadableMap from(PluginException e) {
68 | WritableMap out = Arguments.createMap();
69 | out.putInt("code", e.getCode());
70 | out.putString("message", e.getMessage());
71 | if (e.getCause() != null) {
72 | out.putMap("cause", from(e.getCause()));
73 | }
74 |
75 | return out;
76 | }
77 |
78 | private static WritableMap from(Throwable e) {
79 | WritableMap out = Arguments.createMap();
80 | out.putString("message", e.getMessage());
81 | return out;
82 | }
83 | }
84 |
85 | public BackgroundGeolocationModule(ReactApplicationContext reactContext) {
86 | super(reactContext);
87 | reactContext.addLifecycleEventListener(this);
88 |
89 | facade = new BackgroundGeolocationFacade(getContext(), this);
90 | logger = LoggerManager.getLogger(BackgroundGeolocationModule.class);
91 | }
92 |
93 | @Override
94 | public String getName() {
95 | return "BackgroundGeolocation";
96 | }
97 |
98 | /**
99 | * Called when the activity will start interacting with the user.
100 | *
101 | */
102 | @Override
103 | public void onHostResume() {
104 | logger.info("App will be resumed");
105 | facade.resume();
106 | sendEvent(FOREGROUND_EVENT, null);
107 | }
108 |
109 | /**
110 | * Called when the system is about to start resuming a previous activity.
111 | */
112 | @Override
113 | public void onHostPause() {
114 | logger.info("App will be paused");
115 | facade.pause();
116 | sendEvent(BACKGROUND_EVENT, null);
117 | }
118 |
119 | /**
120 | * The final call you receive before your activity is destroyed.
121 | * Checks to see if it should turn off
122 | */
123 | @Override
124 | public void onHostDestroy() {
125 | logger.info("Destroying plugin");
126 | facade.destroy();
127 | // facade = null;
128 | }
129 |
130 | private void runOnBackgroundThread(Runnable runnable) {
131 | // currently react-native has no other thread we can run on
132 | new Thread(runnable).start();
133 | }
134 |
135 |
136 | @ReactMethod
137 | public void start() {
138 | facade.start();
139 | }
140 |
141 | @ReactMethod
142 | public void stop() {
143 | facade.stop();
144 | }
145 |
146 | @ReactMethod
147 | public void switchMode(Integer mode, Callback success, Callback error) {
148 | facade.switchMode(mode);
149 | }
150 |
151 | @ReactMethod
152 | public void configure(final ReadableMap options, final Callback success, final Callback error) {
153 | runOnBackgroundThread(new Runnable() {
154 | @Override
155 | public void run() {
156 | try {
157 | Config config = ConfigMapper.fromMap(options);
158 | facade.configure(config);
159 | success.invoke(true);
160 | } catch (JSONException e) {
161 | logger.error("Configuration error: {}", e.getMessage());
162 | error.invoke(ErrorMap.from("Configuration error", e, PluginException.CONFIGURE_ERROR));
163 | } catch (PluginException e) {
164 | logger.error("Configuration error: {}", e.getMessage());
165 | error.invoke(ErrorMap.from(e));
166 | }
167 | }
168 | });
169 | }
170 |
171 | @ReactMethod
172 | public void showLocationSettings() {
173 | BackgroundGeolocationFacade.showLocationSettings(getContext());
174 | }
175 |
176 | @ReactMethod
177 | public void showAppSettings() {
178 | BackgroundGeolocationFacade.showAppSettings(getContext());
179 | }
180 |
181 | @ReactMethod
182 | public void getStationaryLocation(Callback success, Callback error) {
183 | BackgroundLocation stationaryLocation = facade.getStationaryLocation();
184 | if (stationaryLocation != null) {
185 | success.invoke(LocationMapper.toWriteableMap(stationaryLocation));
186 | } else {
187 | success.invoke();
188 | }
189 | }
190 |
191 | @ReactMethod
192 | public void getLocations(final Callback success, final Callback error) {
193 | runOnBackgroundThread(new Runnable() {
194 | public void run() {
195 | WritableArray locationsArray = Arguments.createArray();
196 | Collection locations = facade.getLocations();
197 | for (BackgroundLocation location : locations) {
198 | locationsArray.pushMap(LocationMapper.toWriteableMapWithId(location));
199 | }
200 | success.invoke(locationsArray);
201 | }
202 | });
203 | }
204 |
205 | @ReactMethod
206 | public void getValidLocations(final Callback success, Callback error) {
207 | runOnBackgroundThread(new Runnable() {
208 | public void run() {
209 | WritableArray locationsArray = Arguments.createArray();
210 | Collection locations = facade.getValidLocations();
211 | for (BackgroundLocation location : locations) {
212 | locationsArray.pushMap(LocationMapper.toWriteableMapWithId(location));
213 | }
214 | success.invoke(locationsArray);
215 | }
216 | });
217 | }
218 |
219 | @ReactMethod
220 | public void deleteLocation(final Integer locationId, final Callback success, Callback error) {
221 | runOnBackgroundThread(new Runnable() {
222 | public void run() {
223 | facade.deleteLocation(locationId.longValue());
224 | success.invoke(true);
225 | }
226 | });
227 | }
228 |
229 | @ReactMethod
230 | public void deleteAllLocations(final Callback success, Callback error) {
231 | runOnBackgroundThread(new Runnable() {
232 | public void run() {
233 | facade.deleteAllLocations();
234 | success.invoke(true);
235 | }
236 | });
237 | }
238 |
239 | @ReactMethod
240 | public void getCurrentLocation(final ReadableMap options, final Callback success, final Callback error) {
241 | runOnBackgroundThread(new Runnable() {
242 | public void run() {
243 | try {
244 | int timeout = options.hasKey("timeout") ? options.getInt("timeout") : Integer.MAX_VALUE;
245 | long maximumAge = options.hasKey("maximumAge") ? options.getInt("maximumAge") : Long.MAX_VALUE;
246 | boolean enableHighAccuracy = options.hasKey("enableHighAccuracy") && options.getBoolean("enableHighAccuracy");
247 |
248 | BackgroundLocation location = facade.getCurrentLocation(timeout, maximumAge, enableHighAccuracy);
249 | success.invoke(LocationMapper.toWriteableMap(location));
250 | } catch (PluginException e) {
251 | error.invoke(ErrorMap.from(e));
252 | }
253 | }
254 | });
255 | }
256 |
257 | @ReactMethod
258 | public void getConfig(final Callback success, final Callback error) {
259 | runOnBackgroundThread(new Runnable() {
260 | public void run() {
261 | Config config = facade.getConfig();
262 | ReadableMap out = ConfigMapper.toMap(config);
263 | success.invoke(out);
264 | }
265 | });
266 | }
267 |
268 | @ReactMethod
269 | public void getLogEntries(final Integer limit, final Integer offset, final String minLevel, final Callback success, final Callback error) {
270 | runOnBackgroundThread(new Runnable() {
271 | public void run() {
272 | WritableArray logEntriesArray = Arguments.createArray();
273 | Collection logEntries = facade.getLogEntries(limit, offset, minLevel);
274 | for (LogEntry logEntry : logEntries) {
275 | WritableMap out = Arguments.createMap();
276 | out.putInt("id", logEntry.getId());
277 | out.putInt("context", logEntry.getContext());
278 | out.putString("level", logEntry.getLevel());
279 | out.putString("message", logEntry.getMessage());
280 | out.putString("timestamp", new Long(logEntry.getTimestamp()).toString());
281 | out.putString("logger", logEntry.getLoggerName());
282 | if (logEntry.hasStackTrace()) {
283 | out.putString("stackTrace", logEntry.getStackTrace());
284 | }
285 |
286 | logEntriesArray.pushMap(out);
287 | }
288 | success.invoke(logEntriesArray);
289 | }
290 | });
291 | }
292 |
293 | @ReactMethod
294 | public void checkStatus(final Callback success, final Callback error) {
295 | runOnBackgroundThread(new Runnable() {
296 | public void run() {
297 | try {
298 | WritableMap out = Arguments.createMap();
299 | out.putBoolean("isRunning", facade.isRunning());
300 | out.putBoolean("hasPermissions", facade.hasPermissions()); //@Deprecated
301 | out.putBoolean("locationServicesEnabled", facade.locationServicesEnabled());
302 | out.putInt("authorization", getAuthorizationStatus());
303 | success.invoke(out);
304 | } catch (PluginException e) {
305 | logger.error("Location service checked failed: {}", e.getMessage());
306 | error.invoke(ErrorMap.from(e));
307 | }
308 | }
309 | });
310 | }
311 |
312 | @ReactMethod
313 | public void registerHeadlessTask(Callback success, Callback error) {
314 | logger.debug("Registering headless task");
315 | facade.registerHeadlessTask(HeadlessTaskRunner.class.getName());
316 | success.invoke();
317 | }
318 |
319 | @ReactMethod
320 | public void forceSync(Callback success, Callback error) {
321 | facade.forceSync();
322 | success.invoke();
323 | }
324 |
325 | private void sendEvent(String eventName, Object params) {
326 | getReactApplicationContext()
327 | .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
328 | .emit(eventName, params);
329 | }
330 |
331 | private void sendError(PluginException error) {
332 | WritableMap out = Arguments.createMap();
333 | out.putInt("code", error.getCode());
334 | out.putString("message", error.getMessage());
335 |
336 | sendEvent(ERROR_EVENT, out);
337 | }
338 |
339 | private void sendError(int code, String message) {
340 | WritableMap out = Arguments.createMap();
341 | out.putInt("code", code);
342 | out.putString("message", message);
343 |
344 | sendEvent(ERROR_EVENT, out);
345 | }
346 |
347 | public int getAuthorizationStatus() {
348 | return facade.getAuthorizationStatus();
349 | }
350 |
351 | public Context getContext() {
352 | return getReactApplicationContext().getBaseContext();
353 | }
354 |
355 | @Override
356 | public void onAuthorizationChanged(int authStatus) {
357 | sendEvent(AUTHORIZATION_EVENT, authStatus);
358 | }
359 |
360 | @Override
361 | public void onLocationChanged(BackgroundLocation location) {
362 | sendEvent(LOCATION_EVENT, LocationMapper.toWriteableMapWithId(location));
363 | }
364 |
365 | @Override
366 | public void onStationaryChanged(BackgroundLocation location) {
367 | sendEvent(STATIONARY_EVENT, LocationMapper.toWriteableMapWithId(location));
368 | }
369 |
370 | @Override
371 | public void onActivityChanged(BackgroundActivity activity) {
372 | WritableMap out = Arguments.createMap();
373 | out.putInt("confidence", activity.getConfidence());
374 | out.putString("type", BackgroundActivity.getActivityString(activity.getType()));
375 | sendEvent(ACTIVITY_EVENT, out);
376 | }
377 |
378 | @Override
379 | public void onServiceStatusChanged(int status) {
380 | switch (status) {
381 | case BackgroundGeolocationFacade.SERVICE_STARTED:
382 | sendEvent(START_EVENT, null);
383 | return;
384 | case BackgroundGeolocationFacade.SERVICE_STOPPED:
385 | sendEvent(STOP_EVENT, null);
386 | return;
387 | }
388 | }
389 |
390 | @Override
391 | public void onError(PluginException error) {
392 | sendError(error);
393 | }
394 |
395 | @Override
396 | public void onAbortRequested() {
397 | sendEvent(ABORT_REQUESTED_EVENT, null);
398 | }
399 |
400 | @Override
401 | public void onHttpAuthorization() {
402 | sendEvent(HTTP_AUTHORIZATION_EVENT, null);
403 | }
404 | }
405 |
--------------------------------------------------------------------------------
/android/lib/src/main/java/com/marianhello/bgloc/react/BackgroundGeolocationPackage.java:
--------------------------------------------------------------------------------
1 | package com.marianhello.bgloc.react;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collections;
5 | import java.util.List;
6 |
7 | import com.facebook.react.ReactPackage;
8 | import com.facebook.react.bridge.JavaScriptModule;
9 | import com.facebook.react.bridge.NativeModule;
10 | import com.facebook.react.bridge.ReactApplicationContext;
11 | import com.facebook.react.uimanager.ViewManager;
12 |
13 | public class BackgroundGeolocationPackage implements ReactPackage {
14 |
15 | @Override
16 | public List createNativeModules(ReactApplicationContext reactContext) {
17 | List modules = new ArrayList();
18 | modules.add(new BackgroundGeolocationModule(reactContext));
19 | return modules;
20 | }
21 |
22 | @Override
23 | public List createViewManagers(ReactApplicationContext reactContext) {
24 | return Collections.emptyList();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/android/lib/src/main/java/com/marianhello/bgloc/react/ConfigMapper.java:
--------------------------------------------------------------------------------
1 | package com.marianhello.bgloc.react;
2 |
3 | import com.facebook.react.bridge.Arguments;
4 | import com.facebook.react.bridge.ReadableMap;
5 | import com.facebook.react.bridge.ReadableMapKeySetIterator;
6 | import com.facebook.react.bridge.ReadableType;
7 | import com.facebook.react.bridge.WritableMap;
8 | import com.iodine.start.ArrayUtil;
9 | import com.iodine.start.MapUtil;
10 | import com.marianhello.bgloc.Config;
11 | import com.marianhello.bgloc.data.ArrayListLocationTemplate;
12 | import com.marianhello.bgloc.data.HashMapLocationTemplate;
13 | import com.marianhello.bgloc.data.LocationTemplate;
14 | import com.marianhello.bgloc.data.LocationTemplateFactory;
15 |
16 | import org.json.JSONException;
17 | import org.json.JSONObject;
18 |
19 | import java.util.HashMap;
20 | import java.util.Iterator;
21 | import java.util.Map;
22 |
23 | /**
24 | * Created by finch on 29.11.2016.
25 | */
26 |
27 | public class ConfigMapper {
28 | public static Config fromMap(ReadableMap options) throws JSONException {
29 | Config config = new Config();
30 | if (options.hasKey("stationaryRadius")) config.setStationaryRadius((float) options.getDouble("stationaryRadius"));
31 | if (options.hasKey("distanceFilter")) config.setDistanceFilter(options.getInt("distanceFilter"));
32 | if (options.hasKey("desiredAccuracy")) config.setDesiredAccuracy(options.getInt("desiredAccuracy"));
33 | if (options.hasKey("debug")) config.setDebugging(options.getBoolean("debug"));
34 | if (options.hasKey("notificationTitle")) config.setNotificationTitle(
35 | !options.isNull("notificationTitle") ? options.getString("notificationTitle") : Config.NullString
36 | );
37 | if (options.hasKey("notificationText")) config.setNotificationText(
38 | !options.isNull("notificationText") ? options.getString("notificationText") : Config.NullString
39 | );
40 | if (options.hasKey("notificationIconLarge")) config.setLargeNotificationIcon(
41 | !options.isNull("notificationIconLarge") ? options.getString("notificationIconLarge") : Config.NullString
42 | );
43 | if (options.hasKey("notificationIconSmall")) config.setSmallNotificationIcon(
44 | !options.isNull("notificationIconSmall") ? options.getString("notificationIconSmall") : Config.NullString
45 | );
46 | if (options.hasKey("notificationIconColor")) config.setNotificationIconColor(
47 | !options.isNull("notificationIconColor") ? options.getString("notificationIconColor") : Config.NullString
48 | );
49 | if (options.hasKey("stopOnTerminate")) config.setStopOnTerminate(options.getBoolean("stopOnTerminate"));
50 | if (options.hasKey("startOnBoot")) config.setStartOnBoot(options.getBoolean("startOnBoot"));
51 | if (options.hasKey("startForeground")) config.setStartForeground(options.getBoolean("startForeground"));
52 | if (options.hasKey("notificationsEnabled")) config.setNotificationsEnabled(options.getBoolean("notificationsEnabled"));
53 | if (options.hasKey("locationProvider")) config.setLocationProvider(options.getInt("locationProvider"));
54 | if (options.hasKey("interval")) config.setInterval(options.getInt("interval"));
55 | if (options.hasKey("fastestInterval")) config.setFastestInterval(options.getInt("fastestInterval"));
56 | if (options.hasKey("activitiesInterval")) config.setActivitiesInterval(options.getInt("activitiesInterval"));
57 | if (options.hasKey("stopOnStillActivity")) config.setStopOnStillActivity(options.getBoolean("stopOnStillActivity"));
58 | if (options.hasKey("url")) config.setUrl(
59 | !options.isNull("url") ? options.getString("url") : Config.NullString
60 | );
61 | if (options.hasKey("syncUrl")) config.setSyncUrl(
62 | !options.isNull("syncUrl") ? options.getString("syncUrl") : Config.NullString
63 | );
64 | if (options.hasKey("syncThreshold")) config.setSyncThreshold(options.getInt("syncThreshold"));
65 | if (options.hasKey("httpHeaders")) {
66 | HashMap httpHeaders = new HashMap();
67 | ReadableType type = options.getType("httpHeaders");
68 | if (type != ReadableType.Map) {
69 | throw new JSONException("httpHeaders must be object");
70 | }
71 | JSONObject httpHeadersJson = MapUtil.toJSONObject(options.getMap("httpHeaders"));
72 | config.setHttpHeaders(httpHeadersJson);
73 | }
74 | if (options.hasKey("maxLocations")) config.setMaxLocations(options.getInt("maxLocations"));
75 |
76 | if (options.hasKey("postTemplate")) {
77 | if (options.isNull("postTemplate")) {
78 | config.setTemplate(LocationTemplateFactory.getDefault());
79 | } else {
80 | ReadableType type = options.getType("postTemplate");
81 | Object postTemplate = null;
82 | if (type == ReadableType.Map) {
83 | postTemplate = MapUtil.toJSONObject(options.getMap("postTemplate"));
84 | } else if (type == ReadableType.Array) {
85 | postTemplate = ArrayUtil.toJSONArray(options.getArray("postTemplate"));
86 | }
87 | config.setTemplate(LocationTemplateFactory.fromJSON(postTemplate));
88 | }
89 | }
90 |
91 | return config;
92 | }
93 |
94 | public static ReadableMap toMap(Config config) {
95 | WritableMap out = Arguments.createMap();
96 | WritableMap httpHeaders = Arguments.createMap();
97 | if (config.getStationaryRadius() != null) {
98 | out.putDouble("stationaryRadius", config.getStationaryRadius());
99 | }
100 | if (config.getDistanceFilter() != null) {
101 | out.putInt("distanceFilter", config.getDistanceFilter());
102 | }
103 | if (config.getDesiredAccuracy() != null) {
104 | out.putInt("desiredAccuracy", config.getDesiredAccuracy());
105 | }
106 | if (config.isDebugging() != null) {
107 | out.putBoolean("debug", config.isDebugging());
108 | }
109 | if (config.getNotificationTitle() != null) {
110 | if (config.getNotificationTitle() != Config.NullString) {
111 | out.putString("notificationTitle", config.getNotificationTitle());
112 | } else {
113 | out.putNull("notificationTitle");
114 | }
115 | }
116 | if (config.getNotificationText() != null) {
117 | if (config.getNotificationText() != Config.NullString) {
118 | out.putString("notificationText", config.getNotificationText());
119 | } else {
120 | out.putNull("notificationText");
121 | }
122 | }
123 | if (config.getLargeNotificationIcon() != null) {
124 | if (config.getLargeNotificationIcon() != Config.NullString) {
125 | out.putString("notificationIconLarge", config.getLargeNotificationIcon());
126 | } else {
127 | out.putNull("notificationIconLarge");
128 | }
129 | }
130 | if (config.getSmallNotificationIcon() != null) {
131 | if (config.getSmallNotificationIcon() != Config.NullString) {
132 | out.putString("notificationIconSmall", config.getSmallNotificationIcon());
133 | } else {
134 | out.putNull("notificationIconSmall");
135 | }
136 | }
137 | if (config.getNotificationIconColor() != null) {
138 | if (config.getNotificationIconColor() != Config.NullString) {
139 | out.putString("notificationIconColor", config.getNotificationIconColor());
140 | } else {
141 | out.putNull("notificationIconColor");
142 | }
143 | }
144 | if (config.getStopOnTerminate() != null) {
145 | out.putBoolean("stopOnTerminate", config.getStopOnTerminate());
146 | }
147 | if (config.getStartOnBoot() != null) {
148 | out.putBoolean("startOnBoot", config.getStartOnBoot());
149 | }
150 | if (config.getStartForeground() != null) {
151 | out.putBoolean("startForeground", config.getStartForeground());
152 | }
153 | if (config.getNotificationsEnabled() != null) {
154 | out.putBoolean("notificationsEnabled", config.getNotificationsEnabled());
155 | }
156 | if (config.getLocationProvider() != null) {
157 | out.putInt("locationProvider", config.getLocationProvider());
158 | }
159 | if (config.getInterval() != null) {
160 | out.putInt("interval", config.getInterval());
161 | }
162 | if (config.getFastestInterval() != null) {
163 | out.putInt("fastestInterval", config.getFastestInterval());
164 | }
165 | if (config.getActivitiesInterval() != null) {
166 | out.putInt("activitiesInterval", config.getActivitiesInterval());
167 | }
168 | if (config.getStopOnStillActivity() != null) {
169 | out.putBoolean("stopOnStillActivity", config.getStopOnStillActivity());
170 | }
171 | if (config.getUrl() != null) {
172 | if (config.getUrl() != Config.NullString) {
173 | out.putString("url", config.getUrl());
174 | } else {
175 | out.putNull("url");
176 | }
177 | }
178 | if (config.getSyncUrl() != null) {
179 | if (config.getSyncUrl() != Config.NullString) {
180 | out.putString("syncUrl", config.getSyncUrl());
181 | } else {
182 | out.putNull("syncUrl");
183 | }
184 | }
185 | if (config.getSyncThreshold() != null) {
186 | out.putInt("syncThreshold", config.getSyncThreshold());
187 | }
188 | // httpHeaders
189 | Iterator> it = config.getHttpHeaders().entrySet().iterator();
190 | while (it.hasNext()) {
191 | Map.Entry pair = it.next();
192 | httpHeaders.putString(pair.getKey(), pair.getValue());
193 | }
194 | out.putMap("httpHeaders", httpHeaders);
195 | if (config.getMaxLocations() != null) {
196 | out.putInt("maxLocations", config.getMaxLocations());
197 | }
198 |
199 | LocationTemplate tpl = config.getTemplate();
200 | if (tpl instanceof HashMapLocationTemplate) {
201 | Map map = ((HashMapLocationTemplate)tpl).toMap();
202 | if (map != null) {
203 | out.putMap("postTemplate", MapUtil.toWritableMap(map));
204 | } else {
205 | out.putNull("postTemplate");
206 | }
207 | } else if (tpl instanceof ArrayListLocationTemplate) {
208 | Object[] keys = ((ArrayListLocationTemplate)tpl).toArray();
209 | if (keys != null) {
210 | out.putArray("postTemplate", ArrayUtil.toWritableArray(keys));
211 | } else {
212 | out.putNull("postTemplate");
213 | }
214 | }
215 | return out;
216 | }
217 | }
218 |
--------------------------------------------------------------------------------
/android/lib/src/main/java/com/marianhello/bgloc/react/data/LocationMapper.java:
--------------------------------------------------------------------------------
1 | package com.marianhello.bgloc.react.data;
2 |
3 | import com.facebook.react.bridge.Arguments;
4 | import com.facebook.react.bridge.WritableMap;
5 | import com.marianhello.bgloc.data.BackgroundLocation;
6 | import com.marianhello.utils.Convert;
7 |
8 | /**
9 | * Created by finch on 29.11.2016.
10 | */
11 |
12 | public class LocationMapper {
13 | public static WritableMap toWriteableMap(BackgroundLocation location) {
14 | WritableMap out = Arguments.createMap();
15 | out.putString("provider", location.getProvider());
16 | Integer locationProvider = location.getLocationProvider();
17 | if (locationProvider != null) out.putInt("locationProvider", locationProvider);
18 | out.putDouble("time", new Long(location.getTime()).doubleValue());
19 | out.putDouble("latitude", location.getLatitude());
20 | out.putDouble("longitude", location.getLongitude());
21 | if (location.hasAccuracy()) out.putDouble("accuracy", location.getAccuracy());
22 | if (location.hasSpeed()) out.putDouble("speed", location.getSpeed());
23 | if (location.hasAltitude()) out.putDouble("altitude", location.getAltitude());
24 | if (location.hasBearing()) out.putDouble("bearing", location.getBearing());
25 | if (location.hasRadius()) out.putDouble("radius", location.getRadius());
26 | if (location.hasIsFromMockProvider()) out.putBoolean("isFromMockProvider", location.isFromMockProvider());
27 | if (location.hasMockLocationsEnabled()) out.putBoolean("mockLocationsEnabled", location.areMockLocationsEnabled());
28 |
29 | return out;
30 | }
31 |
32 | public static WritableMap toWriteableMapWithId(BackgroundLocation location) {
33 | WritableMap out = toWriteableMap(location);
34 | Long locationId = location.getLocationId();
35 | if (locationId != null) out.putInt("id", Convert.safeLongToInt(locationId));
36 |
37 | return out;
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/android/lib/src/main/java/com/marianhello/bgloc/react/headless/HeadlessService.java:
--------------------------------------------------------------------------------
1 | package com.marianhello.bgloc.react.headless;
2 |
3 | import android.content.Intent;
4 | import android.os.Bundle;
5 | import android.support.annotation.Nullable;
6 |
7 | import com.facebook.react.HeadlessJsTaskService;
8 | import com.facebook.react.bridge.Arguments;
9 | import com.facebook.react.jstasks.HeadlessJsTaskConfig;
10 |
11 | public class HeadlessService extends HeadlessJsTaskService {
12 | public final String TASK_KEY = "com.marianhello.bgloc.react.headless.Task";
13 |
14 | @Override
15 | protected @Nullable
16 | HeadlessJsTaskConfig getTaskConfig(Intent intent) {
17 | Bundle extras = intent.getExtras();
18 | if (extras != null) {
19 | return new HeadlessJsTaskConfig(
20 | TASK_KEY,
21 | Arguments.fromBundle(extras),
22 | 60000, // timeout for the task
23 | true // optional: defines whether or not the task is allowed in foreground. Default is false
24 | );
25 | }
26 | return null;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/android/lib/src/main/java/com/marianhello/bgloc/react/headless/HeadlessTaskRunner.java:
--------------------------------------------------------------------------------
1 | package com.marianhello.bgloc.react.headless;
2 |
3 | import android.content.Intent;
4 |
5 | import com.marianhello.bgloc.headless.Task;
6 | import com.marianhello.bgloc.headless.AbstractTaskRunner;
7 |
8 | public class HeadlessTaskRunner extends AbstractTaskRunner {
9 | @Override
10 | public void runTask(Task task) {
11 | Intent service = new Intent(mContext, HeadlessService.class);
12 | service.putExtras(task.getBundle());
13 | mContext.startService(service);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/android/lib/src/main/res/mipmap-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mauron85/react-native-background-geolocation/f0d434291cfae4a0e510e1e7a05d4e1e7508870e/android/lib/src/main/res/mipmap-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/lib/src/main/res/mipmap-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mauron85/react-native-background-geolocation/f0d434291cfae4a0e510e1e7a05d4e1e7508870e/android/lib/src/main/res/mipmap-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/lib/src/main/res/mipmap-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mauron85/react-native-background-geolocation/f0d434291cfae4a0e510e1e7a05d4e1e7508870e/android/lib/src/main/res/mipmap-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/lib/src/main/res/mipmap-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mauron85/react-native-background-geolocation/f0d434291cfae4a0e510e1e7a05d4e1e7508870e/android/lib/src/main/res/mipmap-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/lib/src/main/res/mipmap-xxxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mauron85/react-native-background-geolocation/f0d434291cfae4a0e510e1e7a05d4e1e7508870e/android/lib/src/main/res/mipmap-xxxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/android/lib/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | app_name
4 |
--------------------------------------------------------------------------------
/android/lib/src/main/res/xml/authenticator.xml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
--------------------------------------------------------------------------------
/android/lib/src/main/res/xml/syncadapter.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
--------------------------------------------------------------------------------
/android/lib/src/test/java/com/marianhello/bgloc/react/ConfigMapperTest.java:
--------------------------------------------------------------------------------
1 | package com.marianhello.bgloc.react;
2 |
3 | import com.facebook.react.bridge.Arguments;
4 | import com.facebook.react.bridge.JavaOnlyArray;
5 | import com.facebook.react.bridge.JavaOnlyMap;
6 | import com.facebook.react.bridge.ReadableMap;
7 | import com.marianhello.bgloc.Config;
8 |
9 | import junit.framework.Assert;
10 |
11 | import org.junit.Before;
12 | import org.junit.Ignore;
13 | import org.junit.Test;
14 | import org.junit.runner.RunWith;
15 | import org.mockito.invocation.InvocationOnMock;
16 | import org.mockito.stubbing.Answer;
17 | import org.powermock.api.mockito.PowerMockito;
18 | import org.powermock.core.classloader.annotations.PowerMockIgnore;
19 | import org.powermock.core.classloader.annotations.PrepareForTest;
20 | import org.robolectric.RobolectricTestRunner;
21 |
22 | /**
23 | * Running following test suite is currently NOT possible!
24 | * Run instrumented test (androidTest) instead.
25 | *
26 | * TL;DR
27 | * It requires jni native lib "reactnativejni" (libreactnativejni.so),
28 | * which with lot of effort can be built for Linux.
29 | * However "libreactnativejni.so" has dependency on "libandroid.so" which
30 | * doesn't exist for Linux.
31 |
32 | * Related links::
33 | * [1] https://facebook.github.io/react-native/docs/building-from-source.html
34 | * [2] https://stackoverflow.com/questions/35275772/unsatisfiedlinkerror-when-unit-testing-writablenativemap/36504987#comment87006105_36504987
35 | * [3] https://stackoverflow.com/questions/50005396/libreactnativejni-so-is-built-as-elf32-i386-on-64bit-android-ndk/50007861#50007861
36 | * [5] https://github.com/SoftwareMansion/jsc-android-buildscripts
37 | */
38 |
39 | @PrepareForTest({Arguments.class})
40 | @RunWith(RobolectricTestRunner.class)
41 | @PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
42 | public class ConfigMapperTest {
43 | @Before
44 | public void setUp() {
45 | PowerMockito.mockStatic(Arguments.class);
46 | PowerMockito.when(Arguments.createArray()).thenAnswer(new Answer