@josuelmm/cordova-background-geolocation 3.0.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -0
- package/README.md +114 -8
- package/RELEASE.MD +1 -1
- package/android/CDVBackgroundGeolocation/src/main/java/com/marianhello/bgloc/cordova/ConfigMapper.java +20 -0
- package/android/CDVBackgroundGeolocation/src/main/java/com/tenforwardconsulting/bgloc/cordova/BackgroundGeolocationPlugin.java +32 -2
- package/android/CDVBackgroundGeolocation/src/test/java/com/marianhello/ConfigMapperTest.java +12 -0
- package/android/common/src/main/java/com/marianhello/bgloc/BackgroundGeolocationFacade.java +24 -1
- package/android/common/src/main/java/com/marianhello/bgloc/Config.java +87 -0
- package/android/common/src/main/java/com/marianhello/bgloc/HttpPostService.java +34 -1
- package/android/common/src/main/java/com/marianhello/bgloc/data/LocationDAO.java +5 -0
- package/android/common/src/main/java/com/marianhello/bgloc/data/provider/ContentProviderLocationDAO.java +11 -0
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteConfigurationContract.java +10 -0
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteConfigurationDAO.java +24 -0
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteLocationDAO.java +13 -0
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteOpenHelper.java +13 -1
- package/android/common/src/main/java/com/marianhello/bgloc/service/LocationServiceImpl.java +29 -42
- package/android/common/src/main/java/com/marianhello/bgloc/sync/SyncAdapter.java +14 -9
- package/angular/background-geolocation.service.ts +14 -0
- package/angular/dist/background-geolocation.service.d.ts +2 -0
- package/angular/dist/esm2022/background-geolocation.service.mjs +7 -1
- package/angular/dist/fesm2022/josuelmm-cordova-background-geolocation.mjs +6 -0
- package/angular/dist/fesm2022/josuelmm-cordova-background-geolocation.mjs.map +1 -1
- package/ios/CDVBackgroundGeolocation/CDVBackgroundGeolocation.h +2 -0
- package/ios/CDVBackgroundGeolocation/CDVBackgroundGeolocation.m +16 -0
- package/ios/common/BackgroundGeolocation/MAURBackgroundGeolocationFacade.h +2 -0
- package/ios/common/BackgroundGeolocation/MAURBackgroundGeolocationFacade.m +22 -0
- package/ios/common/BackgroundGeolocation/MAURConfig.h +3 -0
- package/ios/common/BackgroundGeolocation/MAURConfig.m +20 -1
- package/ios/common/BackgroundGeolocation/MAURConfigurationContract.h +1 -0
- package/ios/common/BackgroundGeolocation/MAURConfigurationContract.m +1 -0
- package/ios/common/BackgroundGeolocation/MAURGeolocationOpenHelper.m +5 -1
- package/ios/common/BackgroundGeolocation/MAURPostLocationTask.m +4 -3
- package/ios/common/BackgroundGeolocation/MAURSQLiteConfigurationDAO.m +16 -9
- package/ios/common/BackgroundGeolocation/MAURSQLiteLocationDAO.h +2 -0
- package/ios/common/BackgroundGeolocation/MAURSQLiteLocationDAO.m +20 -0
- package/package.json +3 -2
- package/plugin.xml +1 -1
- package/www/BackgroundGeolocation.d.ts +65 -0
- package/www/BackgroundGeolocation.js +12 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.1.0](https://github.com/josuelmm/cordova-background-geolocation/tree/3.1.0) (2026-02-21)
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- **`getPendingSyncCount(success?, fail?)`** — Returns the number of locations pending to be synced (not yet sent to `syncUrl`). Use with `forceSync()` to show "X locations pending" and let the user trigger sync on demand. (Android, iOS)
|
|
8
|
+
- **`clearSync(success?, fail?)`** — Clears the pending sync queue: discards all locations waiting to be sent to `syncUrl` (they will not be synced). Use when the user wants to discard pending locations (e.g. "Clear queue" button). (Android, iOS)
|
|
9
|
+
- **Config option `sync`** (default `true`) — When `false`, automatic sync and `forceSync()` do not run; locations are still stored and can be synced later by setting `sync: true`. (Android, iOS)
|
|
10
|
+
- **Config options for sync notification texts (Android):** `notificationSyncTitle`, `notificationSyncText`, `notificationSyncCompletedText`, `notificationSyncFailedText` — Customize or localize the notification shown while locations are syncing to the server.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Android:** `forceSync()` now correctly calls `callbackContext.success()` so the JS Promise resolves.
|
|
15
|
+
- **Android SyncAdapter:** Use `currentSyncConfig` (not out-of-scope `config`) when building sync notifications.
|
|
16
|
+
- **Android & iOS:** When `sync` was never set in config, DB column `sync_enabled` could be NULL; the plugin now treats NULL as “not set” (sync enabled by default) instead of “sync disabled”, so `forceSync()` and automatic sync work when the user did not pass `sync: false`.
|
|
17
|
+
- **Android sync with `Content-Type: application/x-www-form-urlencoded`:** Batch sync was sending one POST with `locations=<url-encoded-json-array>`, which many servers reject (400). Sync now sends **one POST per location** with the same flat `key=value&key=value` format as real-time posting, so the same endpoint accepts both.
|
|
18
|
+
|
|
19
|
+
### Changed
|
|
20
|
+
|
|
21
|
+
- Version bump to 3.1.0.
|
|
22
|
+
|
|
23
|
+
[Full Changelog](https://github.com/josuelmm/cordova-background-geolocation/compare/3.0.2...3.1.0)
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## [3.0.2](https://github.com/josuelmm/cordova-background-geolocation/tree/3.0.2) (2026-02-21)
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
|
|
31
|
+
- **Android (API 34+):** `getServiceInfo()` was returning an incomplete `ServiceInfo` (foregroundServiceType 0x0), causing "Cannot startForeground: manifest foregroundServiceType unknown/0". Fix:
|
|
32
|
+
- Use **`PackageManager.ComponentInfoFlags.of(0)`** (not `GET_META_DATA`) when calling `getServiceInfo()` on API 33+, so the system returns a complete `ServiceInfo` with the real `foregroundServiceType`.
|
|
33
|
+
- Renamed to **`getManifestForegroundServiceType()`**; never invent a fallback (no 0x4 when unknown). If the type is 0, return 0 and do not call `startForeground()` — log an error and return so the app must fix its manifest (e.g. `tools:replace="android:foregroundServiceType"` with `location`).
|
|
34
|
+
- Use `LocationServiceImpl.class` for `ComponentName`. Read `foregroundServiceType` from `ServiceInfo` (reflection only for the field so the plugin compiles with compileSdk 33).
|
|
35
|
+
|
|
36
|
+
[Full Changelog](https://github.com/josuelmm/cordova-background-geolocation/compare/3.0.1...3.0.2)
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
3
40
|
## [3.0.1](https://github.com/josuelmm/cordova-background-geolocation/tree/3.0.1) (2026-02-21)
|
|
4
41
|
|
|
5
42
|
### Fixed
|
package/README.md
CHANGED
|
@@ -161,7 +161,31 @@ BackgroundGeolocation.FOREGROUND_MODE
|
|
|
161
161
|
|
|
162
162
|
### 1. Configure
|
|
163
163
|
|
|
164
|
-
Set your preferred provider, accuracy, intervals, and optional server
|
|
164
|
+
Set your preferred provider, accuracy, intervals, and optional server URLs. All options are optional; you can reconfigure later with a subset (options are merged).
|
|
165
|
+
|
|
166
|
+
**Main options:**
|
|
167
|
+
|
|
168
|
+
| Option | Description |
|
|
169
|
+
|--------|-------------|
|
|
170
|
+
| `locationProvider` | `ACTIVITY_PROVIDER`, `DISTANCE_FILTER_PROVIDER`, or `RAW_PROVIDER` |
|
|
171
|
+
| `desiredAccuracy` | `HIGH_ACCURACY`, `MEDIUM_ACCURACY`, `LOW_ACCURACY`, `PASSIVE_ACCURACY` |
|
|
172
|
+
| `distanceFilter` | Minimum metres the device must move before an update (e.g. 50) |
|
|
173
|
+
| `stationaryRadius` | Metres from “stationary” point before aggressive tracking (e.g. 50) |
|
|
174
|
+
| `interval` / `fastestInterval` / `activitiesInterval` | Android timing (ms) |
|
|
175
|
+
| `notificationTitle` / `notificationText` | Android foreground notification text |
|
|
176
|
+
| `url` | Server URL where **each** location is posted immediately (if post fails, it goes to sync queue) |
|
|
177
|
+
| `syncUrl` | Server URL where **pending** locations are sent in batch (when count reaches `syncThreshold` or on `forceSync()`) |
|
|
178
|
+
| `syncThreshold` | Number of pending locations before automatic batch sync (default 100) |
|
|
179
|
+
| `sync` | When `true` (default), automatic sync and `forceSync()` run. When `false`, sync is disabled (locations are still stored). |
|
|
180
|
+
| `httpHeaders` | Headers for every POST (e.g. `{ 'Content-Type': 'application/json', 'Authorization': 'Bearer TOKEN' }`) |
|
|
181
|
+
| `postTemplate` | Object or array of properties to send (use `@latitude`, `@longitude`, etc.). See [Custom post template](docs/api.md#custom-post-template). |
|
|
182
|
+
| `maxLocations` | Max locations kept in DB (default 10000). Should be > `syncThreshold`. |
|
|
183
|
+
|
|
184
|
+
**Android-only:** `notificationSyncTitle`, `notificationSyncText`, `notificationSyncCompletedText`, `notificationSyncFailedText` — texts shown in the notification while syncing (defaults in English; set for localization). `startForeground`, `notificationsEnabled`, `startOnBoot`, `stopOnTerminate`, `enableWatchdog`.
|
|
185
|
+
|
|
186
|
+
**iOS-only:** `activityType`, `pauseLocationUpdates`, `saveBatteryOnBackground`.
|
|
187
|
+
|
|
188
|
+
Example:
|
|
165
189
|
|
|
166
190
|
```js
|
|
167
191
|
BackgroundGeolocation.configure({
|
|
@@ -176,15 +200,17 @@ BackgroundGeolocation.configure({
|
|
|
176
200
|
fastestInterval: 5000,
|
|
177
201
|
activitiesInterval: 10000,
|
|
178
202
|
url: 'https://yourserver.com/location',
|
|
179
|
-
|
|
180
|
-
|
|
203
|
+
syncUrl: 'https://yourserver.com/location',
|
|
204
|
+
syncThreshold: 5,
|
|
205
|
+
sync: true,
|
|
181
206
|
httpHeaders: {
|
|
182
|
-
'
|
|
207
|
+
'Content-Type': 'application/json',
|
|
183
208
|
'Authorization': 'Bearer YOUR_TOKEN'
|
|
184
209
|
},
|
|
185
210
|
postTemplate: {
|
|
186
211
|
lat: '@latitude',
|
|
187
|
-
lon: '@longitude'
|
|
212
|
+
lon: '@longitude',
|
|
213
|
+
timestamp: '@time'
|
|
188
214
|
}
|
|
189
215
|
});
|
|
190
216
|
```
|
|
@@ -224,7 +250,82 @@ BackgroundGeolocation.on('http_authorization', function () {
|
|
|
224
250
|
BackgroundGeolocation.stop();
|
|
225
251
|
```
|
|
226
252
|
|
|
227
|
-
|
|
253
|
+
### 5. Sync queue (syncUrl): pending count, force sync, clear queue
|
|
254
|
+
|
|
255
|
+
When you use `syncUrl`, locations that fail to post to `url` (or that are only queued for sync) are sent in batch to `syncUrl`. You can:
|
|
256
|
+
|
|
257
|
+
- **Get pending count** — `getPendingSyncCount()` returns how many locations are waiting to be synced.
|
|
258
|
+
- **Force sync now** — `forceSync()` sends all pending locations immediately (ignores `syncThreshold`). No-op if `sync: false`.
|
|
259
|
+
- **Clear queue** — `clearSync()` discards all pending locations (they will not be sent). Use for a “Clear queue” or “Discard” button.
|
|
260
|
+
|
|
261
|
+
```js
|
|
262
|
+
// Show "X locations pending" and let user sync or clear
|
|
263
|
+
BackgroundGeolocation.getPendingSyncCount()
|
|
264
|
+
.then(function (count) {
|
|
265
|
+
console.log('Pending to sync:', count);
|
|
266
|
+
// e.g. show UI: "Sync (5)" or "Clear queue"
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
// User taps "Sync now"
|
|
270
|
+
BackgroundGeolocation.forceSync().then(function () {
|
|
271
|
+
console.log('Sync completed');
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// User taps "Clear queue"
|
|
275
|
+
BackgroundGeolocation.clearSync().then(function () {
|
|
276
|
+
console.log('Queue cleared');
|
|
277
|
+
});
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### 6. Other methods (summary)
|
|
281
|
+
|
|
282
|
+
| Method | Description |
|
|
283
|
+
|--------|-------------|
|
|
284
|
+
| `getConfig(success, fail)` | Get current configuration (merged options). |
|
|
285
|
+
| `getLocations(success, fail)` | Get all stored locations. |
|
|
286
|
+
| `getValidLocations(success, fail)` | Get locations not yet posted (valid only). |
|
|
287
|
+
| `deleteLocation(id, success, fail)` | Delete one location by id. |
|
|
288
|
+
| `deleteAllLocations(success, fail)` | Delete all stored locations. |
|
|
289
|
+
| `getCurrentLocation(success, fail, options)` | One-shot location (e.g. timeout, maximumAge). |
|
|
290
|
+
| `getPluginVersion(success, fail)` | Plugin version string (e.g. "3.1.0"). |
|
|
291
|
+
| `checkStatus(success, fail)` | Service status (isRunning, authorization, etc.). |
|
|
292
|
+
| `showAppSettings()` / `openSettings()` | Open app settings. |
|
|
293
|
+
| `showLocationSettings()` | Open system location settings. |
|
|
294
|
+
| `getLogEntries(limit, fromId, minLevel, success, fail)` | Debug log entries. |
|
|
295
|
+
|
|
296
|
+
All methods return a **Promise** if you omit the `success` / `fail` callbacks.
|
|
297
|
+
|
|
298
|
+
### 7. Events (summary)
|
|
299
|
+
|
|
300
|
+
Subscribe with `BackgroundGeolocation.on(eventName, callback)`. Unsubscribe with the returned object’s `remove()` or by calling `removeAllListeners(eventName)`.
|
|
301
|
+
|
|
302
|
+
| Event | Payload | When |
|
|
303
|
+
|-------|---------|------|
|
|
304
|
+
| `location` | Location object | New location (foreground/background). |
|
|
305
|
+
| `stationary` | Location | Device stopped (activity provider). |
|
|
306
|
+
| `activity` | Activity type | Activity changed (walking, driving, still). |
|
|
307
|
+
| `error` | `{ code, message }` | Error (e.g. permission, timeout). |
|
|
308
|
+
| `start` | — | Tracking started. |
|
|
309
|
+
| `stop` | — | Tracking stopped. |
|
|
310
|
+
| `authorization` | status | Permission status changed. |
|
|
311
|
+
| `background` / `foreground` | — | App entered background/foreground. |
|
|
312
|
+
| `http_authorization` | — | Server returned 401; refresh token and reconfigure headers. |
|
|
313
|
+
| `abort_requested` | — | Server returned 285 (updates not required). |
|
|
314
|
+
|
|
315
|
+
Full event payloads and options: [Events](docs/events.md). Full API (all options, all methods): [API](docs/api.md).
|
|
316
|
+
|
|
317
|
+
### New in 3.1.0
|
|
318
|
+
|
|
319
|
+
- **`getPendingSyncCount()`** — Number of locations pending to be synced. Use with `forceSync()` for “X pending” UI.
|
|
320
|
+
- **`forceSync()`** — Sends all pending locations to `syncUrl` immediately. Promise now resolves correctly on Android.
|
|
321
|
+
- **`clearSync()`** — Clears the pending sync queue (discard without sending).
|
|
322
|
+
- **Config `sync`** (default `true`) — Set `sync: false` to disable automatic sync and `forceSync()`; locations are still stored.
|
|
323
|
+
- **Config `notificationSyncTitle`, `notificationSyncText`, `notificationSyncCompletedText`, `notificationSyncFailedText`** (Android) — Customize or localize the notification shown while syncing.
|
|
324
|
+
- **Sync with `Content-Type: application/x-www-form-urlencoded`** — Batch sync now sends **one POST per location** (same flat format as real-time), so the same server endpoint works for both.
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
More (stationary, activity, headless task, Angular) is in the [documentation](https://josuelmm.github.io/cordova-background-geolocation/). For **Angular** (service, methods, events), see [docs/angular.md](docs/angular.md).
|
|
228
329
|
|
|
229
330
|
---
|
|
230
331
|
|
|
@@ -293,8 +394,13 @@ No extra wrapper (e.g. Awesome Cordova Plugins) is required.
|
|
|
293
394
|
|
|
294
395
|
## Documentation and changelog
|
|
295
396
|
|
|
296
|
-
- [Documentation](https://josuelmm.github.io/cordova-background-geolocation/) (API, options, examples)
|
|
297
|
-
- [
|
|
397
|
+
- **[Documentation](https://josuelmm.github.io/cordova-background-geolocation/)** — Full docs (API, options, examples).
|
|
398
|
+
- **[API reference](docs/api.md)** — All `configure` options, every method (`configure`, `start`, `stop`, `getPendingSyncCount`, `forceSync`, `clearSync`, `getConfig`, `getLocations`, etc.), TypeScript types.
|
|
399
|
+
- **[HTTP posting](docs/http_posting.md)** — `url` vs `syncUrl`, headers, Content-Type (JSON vs form-urlencoded), sync batch behaviour, `getPendingSyncCount` / `forceSync` / `clearSync`.
|
|
400
|
+
- **[Events](docs/events.md)** — All events (`location`, `error`, `stationary`, `activity`, `http_authorization`, etc.) and payloads.
|
|
401
|
+
- **[Angular / Ionic](docs/angular.md)** — Injectable service, module, same API.
|
|
402
|
+
- **[Example](docs/example.md)** — Full example with events and sync.
|
|
403
|
+
- **[CHANGELOG](CHANGELOG.md)** — Version history.
|
|
298
404
|
|
|
299
405
|
This project is based on [@mauron85/cordova-plugin-background-geolocation](https://github.com/mauron85/cordova-plugin-background-geolocation) and the original by [christocracy](https://github.com/christocracy). Maintained at [josuelmm/cordova-background-geolocation](https://github.com/josuelmm/cordova-background-geolocation). Issues and PRs welcome.
|
|
300
406
|
|
package/RELEASE.MD
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
In order to release a version the following actions are needed:
|
|
2
2
|
1. Update the version in the package.json, lock and plugin.xml files
|
|
3
3
|
2. Go to [releases and create a new release](https://github.com/josuelmm/cordova-background-geolocation/releases/new) in GitHub
|
|
4
|
-
3. Make sure to create a tag too with the version name (e.g. v3.
|
|
4
|
+
3. Make sure to create a tag too with the version name (e.g. v3.1.0)
|
|
5
5
|
4. Click create. Github actions will publish the package to npm
|
|
@@ -42,6 +42,18 @@ public class ConfigMapper {
|
|
|
42
42
|
if (jObject.has("notificationText")) {
|
|
43
43
|
config.setNotificationText(!jObject.isNull("notificationText") ? jObject.getString("notificationText") : Config.NullString);
|
|
44
44
|
}
|
|
45
|
+
if (jObject.has("notificationSyncTitle")) {
|
|
46
|
+
config.setNotificationSyncTitle(jObject.isNull("notificationSyncTitle") ? null : jObject.getString("notificationSyncTitle"));
|
|
47
|
+
}
|
|
48
|
+
if (jObject.has("notificationSyncText")) {
|
|
49
|
+
config.setNotificationSyncText(jObject.isNull("notificationSyncText") ? null : jObject.getString("notificationSyncText"));
|
|
50
|
+
}
|
|
51
|
+
if (jObject.has("notificationSyncCompletedText")) {
|
|
52
|
+
config.setNotificationSyncCompletedText(jObject.isNull("notificationSyncCompletedText") ? null : jObject.getString("notificationSyncCompletedText"));
|
|
53
|
+
}
|
|
54
|
+
if (jObject.has("notificationSyncFailedText")) {
|
|
55
|
+
config.setNotificationSyncFailedText(jObject.isNull("notificationSyncFailedText") ? null : jObject.getString("notificationSyncFailedText"));
|
|
56
|
+
}
|
|
45
57
|
if (jObject.has("stopOnTerminate")) {
|
|
46
58
|
config.setStopOnTerminate(jObject.getBoolean("stopOnTerminate"));
|
|
47
59
|
}
|
|
@@ -84,6 +96,9 @@ public class ConfigMapper {
|
|
|
84
96
|
if (jObject.has("syncThreshold")) {
|
|
85
97
|
config.setSyncThreshold(jObject.getInt("syncThreshold"));
|
|
86
98
|
}
|
|
99
|
+
if (jObject.has("sync")) {
|
|
100
|
+
config.setSyncEnabled(jObject.getBoolean("sync"));
|
|
101
|
+
}
|
|
87
102
|
if (jObject.has("httpHeaders")) {
|
|
88
103
|
config.setHttpHeaders(jObject.getJSONObject("httpHeaders"));
|
|
89
104
|
}
|
|
@@ -114,6 +129,10 @@ public class ConfigMapper {
|
|
|
114
129
|
json.put("notificationsEnabled", config.getNotificationsEnabled());
|
|
115
130
|
json.put("notificationTitle", config.getNotificationTitle() != Config.NullString ? config.getNotificationTitle() : JSONObject.NULL);
|
|
116
131
|
json.put("notificationText", config.getNotificationText() != Config.NullString ? config.getNotificationText() : JSONObject.NULL);
|
|
132
|
+
json.put("notificationSyncTitle", config.getNotificationSyncTitle());
|
|
133
|
+
json.put("notificationSyncText", config.getNotificationSyncText());
|
|
134
|
+
json.put("notificationSyncCompletedText", config.getNotificationSyncCompletedText());
|
|
135
|
+
json.put("notificationSyncFailedText", config.getNotificationSyncFailedText());
|
|
117
136
|
json.put("notificationIconLarge", config.getLargeNotificationIcon() != Config.NullString ? config.getLargeNotificationIcon() : JSONObject.NULL);
|
|
118
137
|
json.put("notificationIconSmall", config.getSmallNotificationIcon() != Config.NullString ? config.getSmallNotificationIcon() : JSONObject.NULL);
|
|
119
138
|
json.put("notificationIconColor", config.getNotificationIconColor() != Config.NullString ? config.getNotificationIconColor() : JSONObject.NULL);
|
|
@@ -128,6 +147,7 @@ public class ConfigMapper {
|
|
|
128
147
|
json.put("url", config.getUrl() != Config.NullString ? config.getUrl() : JSONObject.NULL);
|
|
129
148
|
json.put("syncUrl", config.getSyncUrl() != Config.NullString ? config.getSyncUrl() : JSONObject.NULL);
|
|
130
149
|
json.put("syncThreshold", config.getSyncThreshold());
|
|
150
|
+
json.put("sync", config.getSyncEnabled());
|
|
131
151
|
json.put("httpHeaders", new JSONObject(config.getHttpHeaders()));
|
|
132
152
|
json.put("maxLocations", config.getMaxLocations());
|
|
133
153
|
json.put("enableWatchdog", Boolean.TRUE.equals(config.getEnableWatchdog()));
|
|
@@ -71,10 +71,12 @@ public class BackgroundGeolocationPlugin extends CordovaPlugin implements Plugin
|
|
|
71
71
|
public static final String ACTION_END_TASK = "endTask";
|
|
72
72
|
public static final String ACTION_REGISTER_HEADLESS_TASK = "registerHeadlessTask";
|
|
73
73
|
public static final String ACTION_FORCE_SYNC = "forceSync";
|
|
74
|
+
public static final String ACTION_CLEAR_SYNC = "clearSync";
|
|
75
|
+
public static final String ACTION_GET_PENDING_SYNC_COUNT = "getPendingSyncCount";
|
|
74
76
|
public static final String ACTION_GET_PLUGIN_VERSION = "getPluginVersion";
|
|
75
77
|
|
|
76
78
|
/** Plugin version; keep in sync with plugin.xml. */
|
|
77
|
-
public static final String PLUGIN_VERSION = "3.
|
|
79
|
+
public static final String PLUGIN_VERSION = "3.1.0";
|
|
78
80
|
|
|
79
81
|
private BackgroundGeolocationFacade facade;
|
|
80
82
|
|
|
@@ -367,7 +369,35 @@ public class BackgroundGeolocationPlugin extends CordovaPlugin implements Plugin
|
|
|
367
369
|
return true;
|
|
368
370
|
} else if (ACTION_FORCE_SYNC.equals(action)) {
|
|
369
371
|
logger.debug("Forced location sync requested");
|
|
370
|
-
|
|
372
|
+
runOnWebViewThread(new Runnable() {
|
|
373
|
+
@Override
|
|
374
|
+
public void run() {
|
|
375
|
+
facade.forceSync();
|
|
376
|
+
callbackContext.success();
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
return true;
|
|
380
|
+
} else if (ACTION_CLEAR_SYNC.equals(action)) {
|
|
381
|
+
runOnWebViewThread(new Runnable() {
|
|
382
|
+
@Override
|
|
383
|
+
public void run() {
|
|
384
|
+
facade.clearSync();
|
|
385
|
+
callbackContext.success();
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
return true;
|
|
389
|
+
} else if (ACTION_GET_PENDING_SYNC_COUNT.equals(action)) {
|
|
390
|
+
runOnWebViewThread(new Runnable() {
|
|
391
|
+
@Override
|
|
392
|
+
public void run() {
|
|
393
|
+
try {
|
|
394
|
+
long count = facade.getPendingSyncCount();
|
|
395
|
+
callbackContext.success((int) Math.min(count, Integer.MAX_VALUE));
|
|
396
|
+
} catch (Exception e) {
|
|
397
|
+
callbackContext.sendPluginResult(ErrorPluginResult.from("getPendingSyncCount failed", e, PluginException.SERVICE_ERROR));
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
});
|
|
371
401
|
return true;
|
|
372
402
|
} else if (ACTION_GET_PLUGIN_VERSION.equals(action)) {
|
|
373
403
|
callbackContext.success(PLUGIN_VERSION);
|
package/android/CDVBackgroundGeolocation/src/test/java/com/marianhello/ConfigMapperTest.java
CHANGED
|
@@ -34,6 +34,10 @@ public class ConfigMapperTest {
|
|
|
34
34
|
Assert.assertEquals(config.isDebugging().booleanValue(), jConfig.getBoolean("debug"));
|
|
35
35
|
Assert.assertEquals(config.getNotificationTitle(), jConfig.getString("notificationTitle"));
|
|
36
36
|
Assert.assertEquals(config.getNotificationText(), jConfig.getString("notificationText"));
|
|
37
|
+
Assert.assertEquals(config.getNotificationSyncTitle(), jConfig.getString("notificationSyncTitle"));
|
|
38
|
+
Assert.assertEquals(config.getNotificationSyncText(), jConfig.getString("notificationSyncText"));
|
|
39
|
+
Assert.assertEquals(config.getNotificationSyncCompletedText(), jConfig.getString("notificationSyncCompletedText"));
|
|
40
|
+
Assert.assertEquals(config.getNotificationSyncFailedText(), jConfig.getString("notificationSyncFailedText"));
|
|
37
41
|
Assert.assertEquals(config.getStopOnTerminate().booleanValue(), jConfig.getBoolean("stopOnTerminate"));
|
|
38
42
|
Assert.assertEquals(config.getStartOnBoot().booleanValue(), jConfig.getBoolean("startOnBoot"));
|
|
39
43
|
Assert.assertEquals(config.getLocationProvider().intValue(), jConfig.getInt("locationProvider"));
|
|
@@ -48,6 +52,7 @@ public class ConfigMapperTest {
|
|
|
48
52
|
Assert.assertEquals(config.getUrl(), jConfig.getString("url"));
|
|
49
53
|
Assert.assertEquals(config.getSyncUrl(), jConfig.getString("syncUrl"));
|
|
50
54
|
Assert.assertEquals(config.getSyncThreshold().intValue(), jConfig.getInt("syncThreshold"));
|
|
55
|
+
Assert.assertEquals(Boolean.TRUE.equals(config.getSyncEnabled()), jConfig.getBoolean("sync"));
|
|
51
56
|
Assert.assertEquals(new JSONObject(config.getHttpHeaders()).toString(), jConfig.getJSONObject("httpHeaders").toString());
|
|
52
57
|
Assert.assertEquals(config.getMaxLocations().intValue(), jConfig.getInt("maxLocations"));
|
|
53
58
|
Assert.assertEquals(LocationTemplateFactory.getDefault().toString(), jConfig.get("postTemplate").toString());
|
|
@@ -90,6 +95,13 @@ public class ConfigMapperTest {
|
|
|
90
95
|
Assert.assertFalse(config.hasSmallNotificationIcon());
|
|
91
96
|
}
|
|
92
97
|
|
|
98
|
+
/** When "sync" is not in JSON, getSyncEnabled() must return true (default). */
|
|
99
|
+
@Test
|
|
100
|
+
public void testSyncDefaultWhenNotInJson() throws JSONException {
|
|
101
|
+
Config config = ConfigMapper.fromJSONObject(new JSONObject());
|
|
102
|
+
Assert.assertTrue("sync not in JSON should default to true", config.getSyncEnabled());
|
|
103
|
+
}
|
|
104
|
+
|
|
93
105
|
@Test
|
|
94
106
|
public void testNullablePropsToJSONObject() throws JSONException {
|
|
95
107
|
Config config = new Config();
|
|
@@ -407,9 +407,14 @@ public class BackgroundGeolocationFacade {
|
|
|
407
407
|
* Force location sync
|
|
408
408
|
*
|
|
409
409
|
* Method is ignoring syncThreshold and also user sync settings preference
|
|
410
|
-
* and sync locations to defined syncUrl
|
|
410
|
+
* and sync locations to defined syncUrl. No-op if sync is disabled in config (sync: false).
|
|
411
411
|
*/
|
|
412
412
|
public void forceSync() {
|
|
413
|
+
Config config = getConfig();
|
|
414
|
+
if (!Boolean.TRUE.equals(config.getSyncEnabled())) {
|
|
415
|
+
logger.debug("Sync disabled in config, skipping forceSync");
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
413
418
|
logger.debug("Sync locations forced");
|
|
414
419
|
ResourceResolver resolver = ResourceResolver.newInstance(getContext());
|
|
415
420
|
Account syncAccount = AccountHelper.CreateSyncAccount(getContext(), resolver.getAccountName(),
|
|
@@ -417,6 +422,24 @@ public class BackgroundGeolocationFacade {
|
|
|
417
422
|
SyncService.sync(syncAccount, resolver.getAuthority(), true);
|
|
418
423
|
}
|
|
419
424
|
|
|
425
|
+
/**
|
|
426
|
+
* Returns the number of locations pending to be synced (not yet sent to syncUrl).
|
|
427
|
+
*/
|
|
428
|
+
public long getPendingSyncCount() {
|
|
429
|
+
LocationDAO dao = DAOFactory.createLocationDAO(getContext());
|
|
430
|
+
return dao.getLocationsForSyncCount(Long.MAX_VALUE);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Clear the pending sync queue: mark all locations waiting to be synced as deleted.
|
|
435
|
+
* They will not be sent to syncUrl. Use when the user wants to discard pending locations.
|
|
436
|
+
*/
|
|
437
|
+
public void clearSync() {
|
|
438
|
+
LocationDAO dao = DAOFactory.createLocationDAO(getContext());
|
|
439
|
+
int count = dao.deletePendingSyncLocations();
|
|
440
|
+
logger.debug("Cleared {} pending sync locations", count);
|
|
441
|
+
}
|
|
442
|
+
|
|
420
443
|
public int getAuthorizationStatus() {
|
|
421
444
|
return hasPermissions() ? AUTHORIZATION_AUTHORIZED : AUTHORIZATION_DENIED;
|
|
422
445
|
}
|
|
@@ -45,6 +45,10 @@ public class Config implements Parcelable
|
|
|
45
45
|
private Boolean debug;
|
|
46
46
|
private String notificationTitle;
|
|
47
47
|
private String notificationText;
|
|
48
|
+
private String notificationSyncTitle;
|
|
49
|
+
private String notificationSyncText;
|
|
50
|
+
private String notificationSyncCompletedText;
|
|
51
|
+
private String notificationSyncFailedText;
|
|
48
52
|
private String notificationIconLarge;
|
|
49
53
|
private String notificationIconSmall;
|
|
50
54
|
private String notificationIconColor;
|
|
@@ -60,6 +64,7 @@ public class Config implements Parcelable
|
|
|
60
64
|
private String url;
|
|
61
65
|
private String syncUrl;
|
|
62
66
|
private Integer syncThreshold;
|
|
67
|
+
private Boolean syncEnabled;
|
|
63
68
|
private HashMap httpHeaders;
|
|
64
69
|
private Integer maxLocations;
|
|
65
70
|
private LocationTemplate template;
|
|
@@ -76,6 +81,10 @@ public class Config implements Parcelable
|
|
|
76
81
|
this.debug = config.debug;
|
|
77
82
|
this.notificationTitle = config.notificationTitle;
|
|
78
83
|
this.notificationText = config.notificationText;
|
|
84
|
+
this.notificationSyncTitle = config.notificationSyncTitle;
|
|
85
|
+
this.notificationSyncText = config.notificationSyncText;
|
|
86
|
+
this.notificationSyncCompletedText = config.notificationSyncCompletedText;
|
|
87
|
+
this.notificationSyncFailedText = config.notificationSyncFailedText;
|
|
79
88
|
this.notificationIconLarge = config.notificationIconLarge;
|
|
80
89
|
this.notificationIconSmall = config.notificationIconSmall;
|
|
81
90
|
this.notificationIconColor = config.notificationIconColor;
|
|
@@ -91,6 +100,7 @@ public class Config implements Parcelable
|
|
|
91
100
|
this.url = config.url;
|
|
92
101
|
this.syncUrl = config.syncUrl;
|
|
93
102
|
this.syncThreshold = config.syncThreshold;
|
|
103
|
+
this.syncEnabled = config.syncEnabled;
|
|
94
104
|
this.httpHeaders = CloneHelper.deepCopy(config.httpHeaders);
|
|
95
105
|
this.maxLocations = config.maxLocations;
|
|
96
106
|
this.enableWatchdog = config.enableWatchdog;
|
|
@@ -106,6 +116,10 @@ public class Config implements Parcelable
|
|
|
106
116
|
setDebugging((Boolean) in.readValue(null));
|
|
107
117
|
setNotificationTitle(in.readString());
|
|
108
118
|
setNotificationText(in.readString());
|
|
119
|
+
setNotificationSyncTitle(in.readString());
|
|
120
|
+
setNotificationSyncText(in.readString());
|
|
121
|
+
setNotificationSyncCompletedText(in.readString());
|
|
122
|
+
setNotificationSyncFailedText(in.readString());
|
|
109
123
|
setLargeNotificationIcon(in.readString());
|
|
110
124
|
setSmallNotificationIcon(in.readString());
|
|
111
125
|
setNotificationIconColor(in.readString());
|
|
@@ -121,6 +135,7 @@ public class Config implements Parcelable
|
|
|
121
135
|
setUrl(in.readString());
|
|
122
136
|
setSyncUrl(in.readString());
|
|
123
137
|
setSyncThreshold(in.readInt());
|
|
138
|
+
setSyncEnabled((Boolean) in.readValue(null));
|
|
124
139
|
setMaxLocations(in.readInt());
|
|
125
140
|
setEnableWatchdog((Boolean) in.readValue(null));
|
|
126
141
|
Bundle bundle = in.readBundle();
|
|
@@ -136,6 +151,10 @@ public class Config implements Parcelable
|
|
|
136
151
|
config.debug = false;
|
|
137
152
|
config.notificationTitle = "Background tracking";
|
|
138
153
|
config.notificationText = "ENABLED";
|
|
154
|
+
config.notificationSyncTitle = "Syncing locations";
|
|
155
|
+
config.notificationSyncText = "Sync in progress";
|
|
156
|
+
config.notificationSyncCompletedText = "Sync completed";
|
|
157
|
+
config.notificationSyncFailedText = "Sync failed";
|
|
139
158
|
config.notificationIconLarge = "";
|
|
140
159
|
config.notificationIconSmall = "";
|
|
141
160
|
config.notificationIconColor = "";
|
|
@@ -151,6 +170,7 @@ public class Config implements Parcelable
|
|
|
151
170
|
config.url = "";
|
|
152
171
|
config.syncUrl = "";
|
|
153
172
|
config.syncThreshold = 100;
|
|
173
|
+
config.syncEnabled = true;
|
|
154
174
|
config.httpHeaders = null;
|
|
155
175
|
config.maxLocations = 10000;
|
|
156
176
|
config.template = null;
|
|
@@ -171,6 +191,10 @@ public class Config implements Parcelable
|
|
|
171
191
|
out.writeValue(isDebugging());
|
|
172
192
|
out.writeString(getNotificationTitle());
|
|
173
193
|
out.writeString(getNotificationText());
|
|
194
|
+
out.writeString(getNotificationSyncTitle());
|
|
195
|
+
out.writeString(getNotificationSyncText());
|
|
196
|
+
out.writeString(getNotificationSyncCompletedText());
|
|
197
|
+
out.writeString(getNotificationSyncFailedText());
|
|
174
198
|
out.writeString(getLargeNotificationIcon());
|
|
175
199
|
out.writeString(getSmallNotificationIcon());
|
|
176
200
|
out.writeString(getNotificationIconColor());
|
|
@@ -186,6 +210,7 @@ public class Config implements Parcelable
|
|
|
186
210
|
out.writeString(getUrl());
|
|
187
211
|
out.writeString(getSyncUrl());
|
|
188
212
|
out.writeInt(getSyncThreshold());
|
|
213
|
+
out.writeValue(getSyncEnabled());
|
|
189
214
|
out.writeInt(getMaxLocations());
|
|
190
215
|
out.writeValue(getEnableWatchdog());
|
|
191
216
|
Bundle bundle = new Bundle();
|
|
@@ -293,6 +318,38 @@ public class Config implements Parcelable
|
|
|
293
318
|
this.notificationText = notificationText;
|
|
294
319
|
}
|
|
295
320
|
|
|
321
|
+
public String getNotificationSyncTitle() {
|
|
322
|
+
return notificationSyncTitle != null ? notificationSyncTitle : "Syncing locations";
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
public void setNotificationSyncTitle(String notificationSyncTitle) {
|
|
326
|
+
this.notificationSyncTitle = notificationSyncTitle;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
public String getNotificationSyncText() {
|
|
330
|
+
return notificationSyncText != null ? notificationSyncText : "Sync in progress";
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
public void setNotificationSyncText(String notificationSyncText) {
|
|
334
|
+
this.notificationSyncText = notificationSyncText;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
public String getNotificationSyncCompletedText() {
|
|
338
|
+
return notificationSyncCompletedText != null ? notificationSyncCompletedText : "Sync completed";
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
public void setNotificationSyncCompletedText(String notificationSyncCompletedText) {
|
|
342
|
+
this.notificationSyncCompletedText = notificationSyncCompletedText;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
public String getNotificationSyncFailedText() {
|
|
346
|
+
return notificationSyncFailedText != null ? notificationSyncFailedText : "Sync failed";
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
public void setNotificationSyncFailedText(String notificationSyncFailedText) {
|
|
350
|
+
this.notificationSyncFailedText = notificationSyncFailedText;
|
|
351
|
+
}
|
|
352
|
+
|
|
296
353
|
public boolean hasLargeNotificationIcon() {
|
|
297
354
|
return notificationIconLarge != null && !notificationIconLarge.isEmpty();
|
|
298
355
|
}
|
|
@@ -468,6 +525,20 @@ public class Config implements Parcelable
|
|
|
468
525
|
this.syncThreshold = syncThreshold;
|
|
469
526
|
}
|
|
470
527
|
|
|
528
|
+
public boolean hasSyncEnabled() {
|
|
529
|
+
return syncEnabled != null;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/** Whether synchronization to syncUrl is enabled. Default true. */
|
|
533
|
+
@Nullable
|
|
534
|
+
public Boolean getSyncEnabled() {
|
|
535
|
+
return syncEnabled != null ? syncEnabled : true;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
public void setSyncEnabled(@Nullable Boolean syncEnabled) {
|
|
539
|
+
this.syncEnabled = syncEnabled;
|
|
540
|
+
}
|
|
541
|
+
|
|
471
542
|
public boolean hasHttpHeaders() {
|
|
472
543
|
return httpHeaders != null;
|
|
473
544
|
}
|
|
@@ -562,6 +633,7 @@ public class Config implements Parcelable
|
|
|
562
633
|
.append(" url=").append(getUrl())
|
|
563
634
|
.append(" syncUrl=").append(getSyncUrl())
|
|
564
635
|
.append(" syncThreshold=").append(getSyncThreshold())
|
|
636
|
+
.append(" syncEnabled=").append(getSyncEnabled())
|
|
565
637
|
.append(" httpHeaders=").append(getHttpHeaders().toString())
|
|
566
638
|
.append(" maxLocations=").append(getMaxLocations())
|
|
567
639
|
.append(" postTemplate=").append(hasTemplate() ? getTemplate().toString() : null)
|
|
@@ -603,6 +675,18 @@ public class Config implements Parcelable
|
|
|
603
675
|
if (config2.hasNotificationText()) {
|
|
604
676
|
merger.setNotificationText(config2.getNotificationText());
|
|
605
677
|
}
|
|
678
|
+
if (config2.notificationSyncTitle != null) {
|
|
679
|
+
merger.setNotificationSyncTitle(config2.getNotificationSyncTitle());
|
|
680
|
+
}
|
|
681
|
+
if (config2.notificationSyncText != null) {
|
|
682
|
+
merger.setNotificationSyncText(config2.getNotificationSyncText());
|
|
683
|
+
}
|
|
684
|
+
if (config2.notificationSyncCompletedText != null) {
|
|
685
|
+
merger.setNotificationSyncCompletedText(config2.getNotificationSyncCompletedText());
|
|
686
|
+
}
|
|
687
|
+
if (config2.notificationSyncFailedText != null) {
|
|
688
|
+
merger.setNotificationSyncFailedText(config2.getNotificationSyncFailedText());
|
|
689
|
+
}
|
|
606
690
|
if (config2.hasStopOnTerminate()) {
|
|
607
691
|
merger.setStopOnTerminate(config2.getStopOnTerminate());
|
|
608
692
|
}
|
|
@@ -648,6 +732,9 @@ public class Config implements Parcelable
|
|
|
648
732
|
if (config2.hasSyncThreshold()) {
|
|
649
733
|
merger.setSyncThreshold(config2.getSyncThreshold());
|
|
650
734
|
}
|
|
735
|
+
if (config2.hasSyncEnabled()) {
|
|
736
|
+
merger.setSyncEnabled(config2.getSyncEnabled());
|
|
737
|
+
}
|
|
651
738
|
if (config2.hasHttpHeaders()) {
|
|
652
739
|
merger.setHttpHeaders(config2.getHttpHeaders());
|
|
653
740
|
}
|
|
@@ -203,11 +203,44 @@ public class HttpPostService {
|
|
|
203
203
|
}
|
|
204
204
|
stream.close();
|
|
205
205
|
byte[] bodyBytes = baos.toByteArray();
|
|
206
|
+
String jsonString = new String(bodyBytes, StandardCharsets.UTF_8);
|
|
207
|
+
|
|
208
|
+
// When form-urlencoded and body is a JSON array, send one POST per location (same flat
|
|
209
|
+
// format as real-time posting) so the same server endpoint accepts both.
|
|
210
|
+
if (isFormUrlEncoded) {
|
|
211
|
+
try {
|
|
212
|
+
Object parsed = new JSONTokener(jsonString).nextValue();
|
|
213
|
+
if (parsed instanceof JSONArray) {
|
|
214
|
+
JSONArray arr = (JSONArray) parsed;
|
|
215
|
+
int len = arr.length();
|
|
216
|
+
if (len == 0) {
|
|
217
|
+
if (listener != null) listener.onProgress(100);
|
|
218
|
+
return 200;
|
|
219
|
+
}
|
|
220
|
+
for (int i = 0; i < len; i++) {
|
|
221
|
+
JSONObject item = arr.getJSONObject(i);
|
|
222
|
+
HttpPostService perRequest = new HttpPostService(mUrl);
|
|
223
|
+
int code = perRequest.postJSON(item, headers);
|
|
224
|
+
if (listener != null && len > 0) {
|
|
225
|
+
listener.onProgress((i + 1) * 100 / len);
|
|
226
|
+
}
|
|
227
|
+
if (code < 200 || code >= 300) {
|
|
228
|
+
return code;
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (listener != null) {
|
|
232
|
+
listener.onProgress(100);
|
|
233
|
+
}
|
|
234
|
+
return 200;
|
|
235
|
+
}
|
|
236
|
+
} catch (Exception e) {
|
|
237
|
+
// Fall through to single-POST with jsonToUrlEncoded (e.g. array wrap)
|
|
238
|
+
}
|
|
239
|
+
}
|
|
206
240
|
|
|
207
241
|
byte[] outputBytes;
|
|
208
242
|
if (isFormUrlEncoded) {
|
|
209
243
|
try {
|
|
210
|
-
String jsonString = new String(bodyBytes, StandardCharsets.UTF_8);
|
|
211
244
|
String formBody = jsonToUrlEncoded(jsonString);
|
|
212
245
|
outputBytes = formBody.getBytes(StandardCharsets.UTF_8);
|
|
213
246
|
} catch (Exception e) {
|
|
@@ -19,4 +19,9 @@ public interface LocationDAO {
|
|
|
19
19
|
BackgroundLocation deleteFirstUnpostedLocation();
|
|
20
20
|
int deleteAllLocations();
|
|
21
21
|
int deleteUnpostedLocations();
|
|
22
|
+
/**
|
|
23
|
+
* Delete (mark as deleted) all locations that are pending sync to syncUrl.
|
|
24
|
+
* Same effect as discarding the pending sync queue without sending to server.
|
|
25
|
+
*/
|
|
26
|
+
int deletePendingSyncLocations();
|
|
22
27
|
}
|
|
@@ -392,4 +392,15 @@ public class ContentProviderLocationDAO implements LocationDAO {
|
|
|
392
392
|
|
|
393
393
|
return mResolver.update(mContentUri, values, whereClause, whereArgs);
|
|
394
394
|
}
|
|
395
|
+
|
|
396
|
+
@Override
|
|
397
|
+
public int deletePendingSyncLocations() {
|
|
398
|
+
ContentValues values = new ContentValues();
|
|
399
|
+
values.put(LocationEntry.COLUMN_NAME_STATUS, BackgroundLocation.DELETED);
|
|
400
|
+
|
|
401
|
+
String whereClause = LocationEntry.COLUMN_NAME_STATUS + " = ?";
|
|
402
|
+
String[] whereArgs = { String.valueOf(BackgroundLocation.SYNC_PENDING) };
|
|
403
|
+
|
|
404
|
+
return mResolver.update(mContentUri, values, whereClause, whereArgs);
|
|
405
|
+
}
|
|
395
406
|
}
|