@josuelmm/cordova-background-geolocation 4.2.2 → 4.5.1

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.
Files changed (86) hide show
  1. package/.npmignore +11 -0
  2. package/CHANGELOG.md +213 -0
  3. package/HISTORY.md +73 -0
  4. package/README.md +45 -74
  5. package/android/CDVBackgroundGeolocation/src/main/java/com/marianhello/bgloc/cordova/ConfigMapper.java +24 -0
  6. package/android/CDVBackgroundGeolocation/src/main/java/com/tenforwardconsulting/bgloc/cordova/BackgroundGeolocationPlugin.java +61 -1
  7. package/android/common/src/main/AndroidManifest.xml +1 -1
  8. package/android/common/src/main/java/com/marianhello/bgloc/BootCompletedReceiver.java +6 -3
  9. package/android/common/src/main/java/com/marianhello/bgloc/Config.java +65 -1
  10. package/android/common/src/main/java/com/marianhello/bgloc/PostLocationTask.java +1 -1
  11. package/android/common/src/main/java/com/marianhello/bgloc/data/BackgroundLocation.java +94 -0
  12. package/android/common/src/main/java/com/marianhello/bgloc/data/ConfigJsonMapper.java +205 -0
  13. package/android/common/src/main/java/com/marianhello/bgloc/data/LocationTemplateFactory.java +6 -0
  14. package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteConfigurationContract.java +5 -1
  15. package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteConfigurationDAO.java +32 -1
  16. package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteLocationContract.java +12 -2
  17. package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteLocationDAO.java +33 -2
  18. package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteOpenHelper.java +15 -1
  19. package/android/common/src/main/java/com/marianhello/bgloc/provider/DistanceFilterLocationProvider.java +23 -8
  20. package/android/common/src/main/java/com/marianhello/bgloc/service/LocationServiceImpl.java +246 -21
  21. package/android/common/src/main/java/com/marianhello/bgloc/service/LocationServiceProxy.java +5 -2
  22. package/android/common/src/main/java/com/marianhello/bgloc/sync/BatchManager.java +46 -13
  23. package/ios/CDVBackgroundGeolocation/CDVBackgroundGeolocation.m +23 -1
  24. package/ios/common/BackgroundGeolocation/MAURBackgroundGeolocationFacade.m +111 -5
  25. package/ios/common/BackgroundGeolocation/MAURBackgroundSync.m +20 -0
  26. package/ios/common/BackgroundGeolocation/MAURConfig.h +2 -0
  27. package/ios/common/BackgroundGeolocation/MAURConfig.m +16 -2
  28. package/ios/common/BackgroundGeolocation/MAURConfigurationContract.h +3 -0
  29. package/ios/common/BackgroundGeolocation/MAURConfigurationContract.m +3 -1
  30. package/ios/common/BackgroundGeolocation/MAURGeolocationOpenHelper.m +15 -1
  31. package/ios/common/BackgroundGeolocation/MAURLocation.h +12 -0
  32. package/ios/common/BackgroundGeolocation/MAURLocation.m +33 -4
  33. package/ios/common/BackgroundGeolocation/MAURLocationContract.h +4 -0
  34. package/ios/common/BackgroundGeolocation/MAURLocationContract.m +5 -1
  35. package/ios/common/BackgroundGeolocation/MAURPostLocationTask.h +9 -0
  36. package/ios/common/BackgroundGeolocation/MAURPostLocationTask.m +59 -1
  37. package/ios/common/BackgroundGeolocation/MAURSQLiteConfigurationDAO.m +54 -4
  38. package/ios/common/BackgroundGeolocation/MAURSQLiteLocationDAO.h +12 -0
  39. package/ios/common/BackgroundGeolocation/MAURSQLiteLocationDAO.m +125 -5
  40. package/package.json +36 -1
  41. package/plugin.xml +3 -2
  42. package/www/BackgroundGeolocation.d.ts +114 -3
  43. package/www/BackgroundGeolocation.js +11 -4
  44. package/CLAUDE.md +0 -56
  45. package/android/CDVBackgroundGeolocation/src/test/java/com/marianhello/ConfigMapperTest.java +0 -220
  46. package/android/common/src/androidTest/java/com/marianhello/bgloc/BackgroundGeolocationFacadeTest.java +0 -45
  47. package/android/common/src/androidTest/java/com/marianhello/bgloc/BatchManagerTest.java +0 -570
  48. package/android/common/src/androidTest/java/com/marianhello/bgloc/ConfigTest.java +0 -76
  49. package/android/common/src/androidTest/java/com/marianhello/bgloc/ContentProviderLocationDAOTest.java +0 -437
  50. package/android/common/src/androidTest/java/com/marianhello/bgloc/DBLogReaderTest.java +0 -95
  51. package/android/common/src/androidTest/java/com/marianhello/bgloc/LocationContentProviderTest.java +0 -159
  52. package/android/common/src/androidTest/java/com/marianhello/bgloc/LocationServiceProxyTest.java +0 -161
  53. package/android/common/src/androidTest/java/com/marianhello/bgloc/LocationServiceTest.java +0 -247
  54. package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteConfigurationDAOTest.java +0 -200
  55. package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteLocationDAOTest.java +0 -457
  56. package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteLocationDAOThreadTest.java +0 -96
  57. package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteOpenHelperTest.java +0 -225
  58. package/android/common/src/androidTest/java/com/marianhello/bgloc/TestPluginDelegate.java +0 -46
  59. package/android/common/src/androidTest/java/com/marianhello/bgloc/TestResourceResolver.java +0 -14
  60. package/android/common/src/androidTest/java/com/marianhello/bgloc/provider/MockLocationProvider.java +0 -50
  61. package/android/common/src/androidTest/java/com/marianhello/bgloc/provider/TestLocationProviderFactory.java +0 -17
  62. package/android/common/src/androidTest/java/com/marianhello/bgloc/sqlite/SQLiteOpenHelper10.java +0 -92
  63. package/android/common/src/androidTest/java/com/marianhello/bgloc/test/LocationProviderTestCase.java +0 -107
  64. package/android/common/src/androidTest/java/com/marianhello/bgloc/test/TestConstants.java +0 -5
  65. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/ArrayListLocationTemplateTest.java +0 -82
  66. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/BackgroundLocationTest.java +0 -128
  67. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/ConfigTest.java +0 -191
  68. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/DBLogReaderTest.java +0 -37
  69. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/HashMapLocationTemplateTest.java +0 -216
  70. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/HttpPostServiceTest.java +0 -223
  71. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/LocationTemplateFactoryTest.java +0 -50
  72. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/PostLocationTaskTest.java +0 -180
  73. package/android/common/src/test/java/com/marianhello/backgroundgeolocation/TestHelper.java +0 -16
  74. package/ios/common/BackgroundGeolocationTests/Info.plist +0 -24
  75. package/ios/common/BackgroundGeolocationTests/MAURBackgroundLocationTest.m +0 -185
  76. package/ios/common/BackgroundGeolocationTests/MAURConfigTest.m +0 -161
  77. package/ios/common/BackgroundGeolocationTests/MAURGeolocationOpenHelperTest.m +0 -102
  78. package/ios/common/BackgroundGeolocationTests/MAURLocationTest.m +0 -216
  79. package/ios/common/BackgroundGeolocationTests/MAURLocationUploaderTest.m +0 -55
  80. package/ios/common/BackgroundGeolocationTests/MAURLogReaderTest.m +0 -43
  81. package/ios/common/BackgroundGeolocationTests/MAURSQLiteConfigurationDAOTest.m +0 -102
  82. package/ios/common/BackgroundGeolocationTests/MAURSQLiteHelperTest.m +0 -41
  83. package/ios/common/BackgroundGeolocationTests/MAURSQLiteLocationDAOTests.m +0 -240
  84. package/ios/common/BackgroundGeolocationTests/MAURSQLiteLocationDAOThreadTest.m +0 -84
  85. package/ios/common/BackgroundGeolocationTests/MAURSQLiteOpenHelperTest.m +0 -144
  86. package/ios/common/scripts/xcode-refactor.js +0 -184
@@ -83,6 +83,17 @@ public class Config implements Parcelable
83
83
  private String mockLocationPolicy; // allow | flag | drop (default allow)
84
84
  // v4.0 (Phase 6): driver insights
85
85
  private DrivingEventsOptions drivingEvents;
86
+ // v4.4: include device battery in every location payload (default true).
87
+ private Boolean includeBattery;
88
+ // v4.5.1: battery-saving knobs.
89
+ /** WakeLock policy: 'none' | 'posting' | 'always'. Default 'posting'. */
90
+ private String wakeLockMode;
91
+ /** ms before declaring stationary. DistanceFilterLocationProvider default 5*60_000. */
92
+ private Integer stationaryTimeout;
93
+ /** Lazy poll interval while stationary (ms). Default 3*60_000. */
94
+ private Integer stationaryPollInterval;
95
+ /** Aggressive poll interval while stationary (ms). Default 60_000. */
96
+ private Integer stationaryPollFast;
86
97
 
87
98
  /** v4.0 Phase 6 + v4.1: driver-insights configuration. Plain holder; no Parcelable to keep this class diff small. */
88
99
  public static class DrivingEventsOptions {
@@ -149,6 +160,11 @@ public class Config implements Parcelable
149
160
  this.queryParams = CloneHelper.deepCopy(config.queryParams);
150
161
  this.heartbeatInterval = config.heartbeatInterval;
151
162
  this.mockLocationPolicy = config.mockLocationPolicy;
163
+ this.includeBattery = config.includeBattery;
164
+ this.wakeLockMode = config.wakeLockMode;
165
+ this.stationaryTimeout = config.stationaryTimeout;
166
+ this.stationaryPollInterval = config.stationaryPollInterval;
167
+ this.stationaryPollFast = config.stationaryPollFast;
152
168
  if (config.drivingEvents != null) {
153
169
  DrivingEventsOptions de = new DrivingEventsOptions();
154
170
  de.enabled = config.drivingEvents.enabled;
@@ -251,7 +267,16 @@ public class Config implements Parcelable
251
267
  de.phoneUsageCooldownMs = dePhoneUsageCooldown;
252
268
  this.drivingEvents = de;
253
269
  }
254
- Bundle bundle = in.readBundle();
270
+ // v4.4: includeBattery
271
+ setIncludeBattery((Boolean) in.readValue(null));
272
+ // v4.5.1: battery-saving knobs
273
+ setWakeLockMode(in.readString());
274
+ setStationaryTimeout((Integer) in.readValue(null));
275
+ setStationaryPollInterval((Integer) in.readValue(null));
276
+ setStationaryPollFast((Integer) in.readValue(null));
277
+ // v4.5.1 — pass the plugin's classloader so getSerializable() can deserialize
278
+ // LocationTemplate / HashMap subclasses across IPC boundaries (e.g. SyncService :sync process).
279
+ Bundle bundle = in.readBundle(Config.class.getClassLoader());
255
280
  setHttpHeaders((HashMap<String, String>) bundle.getSerializable("httpHeaders"));
256
281
  setQueryParams((HashMap<String, String>) bundle.getSerializable("queryParams"));
257
282
  setTemplate((LocationTemplate) bundle.getSerializable(AbstractLocationTemplate.BUNDLE_KEY));
@@ -298,6 +323,11 @@ public class Config implements Parcelable
298
323
  config.queryParams = null;
299
324
  config.heartbeatInterval = 0;
300
325
  config.mockLocationPolicy = "allow";
326
+ config.includeBattery = true; // v4.4: on by default
327
+ config.wakeLockMode = "posting"; // v4.5.1: hold wake lock only while posting/syncing
328
+ config.stationaryTimeout = 5 * 60 * 1000;
329
+ config.stationaryPollInterval = 3 * 60 * 1000;
330
+ config.stationaryPollFast = 60 * 1000;
301
331
 
302
332
  return config;
303
333
  }
@@ -365,6 +395,13 @@ public class Config implements Parcelable
365
395
  out.writeLong (de != null ? de.phoneUsageWindowMs : 4_000L);
366
396
  out.writeLong (de != null ? de.phoneUsageCooldownMs : 60_000L);
367
397
  out.writeInt (de != null ? 1 : 0);
398
+ // v4.4: includeBattery
399
+ out.writeValue(getIncludeBattery());
400
+ // v4.5.1
401
+ out.writeString(getWakeLockMode());
402
+ out.writeValue(getStationaryTimeout());
403
+ out.writeValue(getStationaryPollInterval());
404
+ out.writeValue(getStationaryPollFast());
368
405
  Bundle bundle = new Bundle();
369
406
  bundle.putSerializable("httpHeaders", getHttpHeaders());
370
407
  bundle.putSerializable("queryParams", getQueryParams());
@@ -762,6 +799,24 @@ public class Config implements Parcelable
762
799
  this.enableWatchdog = enableWatchdog;
763
800
  }
764
801
 
802
+ @Nullable
803
+ public Boolean getIncludeBattery() {
804
+ return includeBattery;
805
+ }
806
+
807
+ public void setIncludeBattery(Boolean includeBattery) {
808
+ this.includeBattery = includeBattery;
809
+ }
810
+
811
+ @Nullable public String getWakeLockMode() { return wakeLockMode; }
812
+ public void setWakeLockMode(String mode) { this.wakeLockMode = mode; }
813
+ @Nullable public Integer getStationaryTimeout() { return stationaryTimeout; }
814
+ public void setStationaryTimeout(Integer ms) { this.stationaryTimeout = ms; }
815
+ @Nullable public Integer getStationaryPollInterval() { return stationaryPollInterval; }
816
+ public void setStationaryPollInterval(Integer ms) { this.stationaryPollInterval = ms; }
817
+ @Nullable public Integer getStationaryPollFast() { return stationaryPollFast; }
818
+ public void setStationaryPollFast(Integer ms) { this.stationaryPollFast = ms; }
819
+
765
820
  public boolean hasShowTime() {
766
821
  return showTime != null;
767
822
  }
@@ -1056,6 +1111,15 @@ public class Config implements Parcelable
1056
1111
  if (config2.drivingEvents != null) {
1057
1112
  merger.setDrivingEvents(config2.drivingEvents);
1058
1113
  }
1114
+ // v4.4.1 — was missing: configure({includeBattery: false}) was being ignored.
1115
+ if (config2.includeBattery != null) {
1116
+ merger.setIncludeBattery(config2.getIncludeBattery());
1117
+ }
1118
+ // v4.5.1 — battery-saving knobs.
1119
+ if (config2.wakeLockMode != null) merger.setWakeLockMode(config2.wakeLockMode);
1120
+ if (config2.stationaryTimeout != null) merger.setStationaryTimeout(config2.stationaryTimeout);
1121
+ if (config2.stationaryPollInterval != null) merger.setStationaryPollInterval(config2.stationaryPollInterval);
1122
+ if (config2.stationaryPollFast != null) merger.setStationaryPollFast(config2.stationaryPollFast);
1059
1123
 
1060
1124
  return merger;
1061
1125
  }
@@ -189,7 +189,7 @@ public class PostLocationTask {
189
189
  String method = mConfig.getHttpMethod();
190
190
  String mode = mConfig.getHttpMode();
191
191
  logger.debug("Posting to url: {} method: {} mode: {} headers: {}",
192
- resolvedUrl, method, mConfig.getHttpHeaders());
192
+ resolvedUrl, method, mode, mConfig.getHttpHeaders());
193
193
  int responseCode;
194
194
 
195
195
  try {
@@ -11,6 +11,7 @@ import androidx.core.util.TimeUtils;
11
11
 
12
12
  import com.marianhello.bgloc.data.sqlite.SQLiteLocationContract.LocationEntry;
13
13
 
14
+ import org.json.JSONArray;
14
15
  import org.json.JSONException;
15
16
  import org.json.JSONObject;
16
17
 
@@ -43,6 +44,20 @@ public class BackgroundLocation implements Parcelable {
43
44
  private int status = POST_PENDING;
44
45
  private Bundle extras = null;
45
46
 
47
+ /**
48
+ * v4.3 — Driving events anexados al fix actual.
49
+ * v4.5: ahora se persiste en SQLite (events_json TEXT) y se propaga vía Parcel para
50
+ * sobrevivir a la cola de sync. Si el POST en real-time falla, los eventos llegan al
51
+ * backend cuando la location se sincroniza más tarde.
52
+ */
53
+ private JSONArray drivingEvents;
54
+
55
+ /** v4.4 — Device battery percentage (0-100) at the time of this fix, or null if unknown
56
+ * or {@code includeBattery} is disabled. v4.5: persisted in SQLite + Parcel. */
57
+ private Integer batteryLevel;
58
+ /** v4.4 — Whether the device is charging at the time of this fix. v4.5: persisted. */
59
+ private Boolean isCharging;
60
+
46
61
  private static final long TWO_MINUTES_IN_NANOS = 1000000000L * 60 * 2;
47
62
 
48
63
  public BackgroundLocation() {}
@@ -106,6 +121,12 @@ public class BackgroundLocation implements Parcelable {
106
121
  mockFlags = l.mockFlags;
107
122
  status = l.status;
108
123
  extras = (l.extras == null) ? null : new Bundle(l.extras);
124
+ // v4.5: copy v4.3+ persisted fields
125
+ if (l.drivingEvents != null) {
126
+ try { drivingEvents = new JSONArray(l.drivingEvents.toString()); } catch (JSONException ignored) {}
127
+ }
128
+ batteryLevel = l.batteryLevel;
129
+ isCharging = l.isCharging;
109
130
  }
110
131
 
111
132
  private static BackgroundLocation fromParcel(Parcel in) {
@@ -134,6 +155,13 @@ public class BackgroundLocation implements Parcelable {
134
155
  l.mockFlags = in.readInt();
135
156
  l.status = in.readInt();
136
157
  l.extras = in.readBundle();
158
+ // v4.5: read driving events / battery / charging
159
+ String evJson = in.readString();
160
+ if (evJson != null) {
161
+ try { l.drivingEvents = new JSONArray(evJson); } catch (JSONException ignored) {}
162
+ }
163
+ l.batteryLevel = (Integer) in.readValue(null);
164
+ l.isCharging = (Boolean) in.readValue(null);
137
165
 
138
166
  return l;
139
167
  }
@@ -205,6 +233,18 @@ public class BackgroundLocation implements Parcelable {
205
233
  l.setStatus(c.getInt(c.getColumnIndex(LocationEntry.COLUMN_NAME_STATUS)));
206
234
  l.setLocationId(c.getLong(c.getColumnIndex(LocationEntry._ID)));
207
235
  l.setMockFlags(c.getInt((c.getColumnIndex(LocationEntry.COLUMN_NAME_MOCK_FLAGS))));
236
+ // v4.5: events / battery / charging — guarded for DBs that may have NULL after migration.
237
+ int idxEv = c.getColumnIndex(LocationEntry.COLUMN_NAME_EVENTS_JSON);
238
+ if (idxEv >= 0 && !c.isNull(idxEv)) {
239
+ String s = c.getString(idxEv);
240
+ if (s != null && !s.isEmpty()) {
241
+ try { l.drivingEvents = new JSONArray(s); } catch (JSONException ignored) {}
242
+ }
243
+ }
244
+ int idxBat = c.getColumnIndex(LocationEntry.COLUMN_NAME_BATTERY_LEVEL);
245
+ if (idxBat >= 0 && !c.isNull(idxBat)) l.batteryLevel = c.getInt(idxBat);
246
+ int idxChg = c.getColumnIndex(LocationEntry.COLUMN_NAME_IS_CHARGING);
247
+ if (idxChg >= 0 && !c.isNull(idxChg)) l.isCharging = (c.getInt(idxChg) == 1);
208
248
 
209
249
  return l;
210
250
  }
@@ -239,6 +279,10 @@ public class BackgroundLocation implements Parcelable {
239
279
  dest.writeInt(mockFlags);
240
280
  dest.writeInt(status);
241
281
  dest.writeBundle(extras);
282
+ // v4.5: persist driving events / battery / charging through Parcel.
283
+ dest.writeString(drivingEvents != null ? drivingEvents.toString() : null);
284
+ dest.writeValue(batteryLevel);
285
+ dest.writeValue(isCharging);
242
286
  }
243
287
 
244
288
  public static final Parcelable.Creator<BackgroundLocation> CREATOR
@@ -899,10 +943,37 @@ public class BackgroundLocation implements Parcelable {
899
943
  if (hasRadius) json.put("radius", radius);
900
944
  if (hasIsFromMockProvider()) json.put("isFromMockProvider", isFromMockProvider());
901
945
  if (hasMockLocationsEnabled()) json.put("mockLocationsEnabled", areMockLocationsEnabled());
946
+ // v4.3: driving events anexados a este fix (si los hay).
947
+ if (drivingEvents != null && drivingEvents.length() > 0) {
948
+ json.put("events", drivingEvents);
949
+ }
950
+ // v4.4: device battery snapshot.
951
+ if (batteryLevel != null) json.put("battery", batteryLevel);
952
+ if (isCharging != null) json.put("isCharging", isCharging);
902
953
 
903
954
  return json;
904
955
  }
905
956
 
957
+ // v4.3 — driving event helpers
958
+ /** Append a driving event to this location. The event survives only until the next
959
+ * serialization in real-time POST. NOT persisted in SQLite. */
960
+ public void addDrivingEvent(JSONObject event) {
961
+ if (event == null) return;
962
+ if (drivingEvents == null) drivingEvents = new JSONArray();
963
+ drivingEvents.put(event);
964
+ }
965
+ public JSONArray getDrivingEvents() { return drivingEvents; }
966
+ public boolean hasDrivingEvents() { return drivingEvents != null && drivingEvents.length() > 0; }
967
+ public void clearDrivingEvents() { drivingEvents = null; }
968
+ /** v4.5: bulk setter used by SQLite hydration to restore the persisted events array. */
969
+ public void setDrivingEvents(JSONArray events) { this.drivingEvents = events; }
970
+
971
+ // v4.4 — battery helpers
972
+ public void setBatteryLevel(Integer level) { this.batteryLevel = level; }
973
+ public Integer getBatteryLevel() { return batteryLevel; }
974
+ public void setCharging(Boolean charging) { this.isCharging = charging; }
975
+ public Boolean isCharging() { return isCharging; }
976
+
906
977
  /**
907
978
  * Returns location as JSON object containing location id
908
979
  * Note: Location id is not unique and is usually being recycled when
@@ -942,6 +1013,18 @@ public class BackgroundLocation implements Parcelable {
942
1013
  values.put(LocationEntry.COLUMN_NAME_STATUS, status);
943
1014
  values.put(LocationEntry.COLUMN_NAME_BATCH_START_MILLIS, batchStartMillis);
944
1015
  values.put(LocationEntry.COLUMN_NAME_MOCK_FLAGS, mockFlags);
1016
+ // v4.5.1 — always write these columns (with NULL when absent) so that recycled rows
1017
+ // in ContentProviderLocationDAO's max-rows UPDATE path do not inherit stale events,
1018
+ // battery or charging state from the location previously stored at that _id.
1019
+ if (drivingEvents != null && drivingEvents.length() > 0) {
1020
+ values.put(LocationEntry.COLUMN_NAME_EVENTS_JSON, drivingEvents.toString());
1021
+ } else {
1022
+ values.putNull(LocationEntry.COLUMN_NAME_EVENTS_JSON);
1023
+ }
1024
+ if (batteryLevel != null) values.put(LocationEntry.COLUMN_NAME_BATTERY_LEVEL, batteryLevel);
1025
+ else values.putNull(LocationEntry.COLUMN_NAME_BATTERY_LEVEL);
1026
+ if (isCharging != null) values.put(LocationEntry.COLUMN_NAME_IS_CHARGING, isCharging ? 1 : 0);
1027
+ else values.putNull(LocationEntry.COLUMN_NAME_IS_CHARGING);
945
1028
  return values;
946
1029
  }
947
1030
 
@@ -988,6 +1071,17 @@ public class BackgroundLocation implements Parcelable {
988
1071
  if ("@mockLocationsEnabled".equals(key)) {
989
1072
  return hasMockLocationsEnabled() ? areMockLocationsEnabled() : JSONObject.NULL;
990
1073
  }
1074
+ // v4.3 — driving events array (only present if events were attached during this fix).
1075
+ if ("@events".equals(key)) {
1076
+ return drivingEvents != null ? drivingEvents : JSONObject.NULL;
1077
+ }
1078
+ // v4.4 — battery snapshot
1079
+ if ("@battery".equals(key)) {
1080
+ return batteryLevel != null ? batteryLevel : JSONObject.NULL;
1081
+ }
1082
+ if ("@isCharging".equals(key)) {
1083
+ return isCharging != null ? isCharging : JSONObject.NULL;
1084
+ }
991
1085
 
992
1086
  return null;
993
1087
  }
@@ -0,0 +1,205 @@
1
+ package com.marianhello.bgloc.data;
2
+
3
+ import com.marianhello.bgloc.Config;
4
+
5
+ import org.json.JSONException;
6
+ import org.json.JSONObject;
7
+
8
+ import java.util.HashMap;
9
+ import java.util.Iterator;
10
+
11
+ /**
12
+ * v4.4.1 — JSON serializer/deserializer for the full {@link Config} state.
13
+ *
14
+ * Lives in {@code common} so both the SQLite DAO (also common) and the Cordova
15
+ * {@code ConfigMapper} (cordova) can reuse it without creating a common→cordova
16
+ * dependency. Used to persist a single {@code config_json} TEXT column instead of
17
+ * adding one schema column per new field on every release.
18
+ *
19
+ * Round-trip: every JS-configurable key the plugin understands is preserved.
20
+ * Anything not present in the input JSON keeps the {@link Config} default.
21
+ */
22
+ public final class ConfigJsonMapper {
23
+
24
+ private ConfigJsonMapper() {}
25
+
26
+ /** Serialize the current Config state to a JSONObject suitable for storage.
27
+ * String fields use {@link JSONObject#NULL} when the user explicitly cleared them
28
+ * (i.e. equals {@link Config#NullString}) so the sentinel survives the round-trip. */
29
+ public static JSONObject toJSONObject(Config c) throws JSONException {
30
+ JSONObject j = new JSONObject();
31
+ if (c == null) return j;
32
+ j.put("stationaryRadius", c.getStationaryRadius());
33
+ j.put("distanceFilter", c.getDistanceFilter());
34
+ j.put("desiredAccuracy", c.getDesiredAccuracy());
35
+ j.put("debug", c.isDebugging());
36
+ j.put("notificationTitle", nullable(c.getNotificationTitle()));
37
+ j.put("notificationText", nullable(c.getNotificationText()));
38
+ j.put("notificationSyncTitle", nullable(c.getNotificationSyncTitle()));
39
+ j.put("notificationSyncText", nullable(c.getNotificationSyncText()));
40
+ j.put("notificationSyncCompletedText", nullable(c.getNotificationSyncCompletedText()));
41
+ j.put("notificationSyncFailedText", nullable(c.getNotificationSyncFailedText()));
42
+ j.put("notificationIconLarge", nullable(c.getLargeNotificationIcon()));
43
+ j.put("notificationIconSmall", nullable(c.getSmallNotificationIcon()));
44
+ j.put("notificationIconColor", nullable(c.getNotificationIconColor()));
45
+ j.put("locationProvider", c.getLocationProvider());
46
+ j.put("interval", c.getInterval());
47
+ j.put("fastestInterval", c.getFastestInterval());
48
+ j.put("activitiesInterval", c.getActivitiesInterval());
49
+ j.put("stopOnTerminate", c.getStopOnTerminate());
50
+ j.put("startOnBoot", c.getStartOnBoot());
51
+ j.put("startForeground", c.getStartForeground());
52
+ j.put("notificationsEnabled", c.getNotificationsEnabled());
53
+ j.put("stopOnStillActivity", c.getStopOnStillActivity());
54
+ j.put("url", nullable(c.getUrl()));
55
+ j.put("syncUrl", nullable(c.getSyncUrl()));
56
+ j.put("syncThreshold", c.getSyncThreshold());
57
+ j.put("syncEnabled", c.getSyncEnabled());
58
+ j.put("maxLocations", c.getMaxLocations());
59
+ j.put("enableWatchdog", c.getEnableWatchdog());
60
+ j.put("showTime", c.getShowTime());
61
+ j.put("showDistance", c.getShowDistance());
62
+ j.put("httpMethod", c.getHttpMethod());
63
+ j.put("syncHttpMethod", c.getSyncHttpMethod());
64
+ j.put("httpMode", c.getHttpMode());
65
+ j.put("syncMode", c.getSyncMode());
66
+ j.put("heartbeatInterval", c.getHeartbeatInterval());
67
+ j.put("mockLocationPolicy", c.getMockLocationPolicy());
68
+ j.put("includeBattery", c.getIncludeBattery());
69
+ // v4.5.1: battery knobs
70
+ j.put("wakeLockMode", c.getWakeLockMode());
71
+ j.put("stationaryTimeout", c.getStationaryTimeout());
72
+ j.put("stationaryPollInterval", c.getStationaryPollInterval());
73
+ j.put("stationaryPollFast", c.getStationaryPollFast());
74
+
75
+ if (c.getHttpHeaders() != null) {
76
+ j.put("httpHeaders", new JSONObject(c.getHttpHeaders()));
77
+ }
78
+ if (c.getQueryParams() != null) {
79
+ j.put("queryParams", new JSONObject(c.getQueryParams()));
80
+ }
81
+
82
+ Config.DrivingEventsOptions de = c.getDrivingEvents();
83
+ if (de != null) {
84
+ JSONObject deJson = new JSONObject();
85
+ deJson.put("enabled", de.enabled);
86
+ deJson.put("speedLimit", de.speedLimitKmh);
87
+ deJson.put("minMovingSpeed", de.minMovingSpeedMps);
88
+ deJson.put("stoppedDuration", de.stoppedDurationMs);
89
+ deJson.put("minTripSpeed", de.minTripSpeedMps);
90
+ deJson.put("minTripDuration", de.minTripDurationMs);
91
+ deJson.put("hardBrakeMps2", de.hardBrakeMps2);
92
+ deJson.put("rapidAccelMps2", de.rapidAccelMps2);
93
+ deJson.put("sharpTurnDegPerSec", de.sharpTurnDegPerSec);
94
+ deJson.put("crashImpactKmh", de.crashImpactKmh);
95
+ deJson.put("crashWindowMs", de.crashWindowMs);
96
+ deJson.put("sensorFusion", de.sensorFusion);
97
+ deJson.put("crashImpactG", de.crashImpactG);
98
+ deJson.put("sensorCrashCooldownMs", de.sensorCrashCooldownMs);
99
+ deJson.put("phoneUsageWindowMs", de.phoneUsageWindowMs);
100
+ deJson.put("phoneUsageCooldownMs", de.phoneUsageCooldownMs);
101
+ j.put("drivingEvents", deJson);
102
+ }
103
+ return j;
104
+ }
105
+
106
+ /** Deserialize a previously serialized config JSON. Missing keys are skipped (defaults preserved). */
107
+ public static Config fromJSONObject(JSONObject j) throws JSONException {
108
+ Config c = Config.getDefault();
109
+ if (j == null) return c;
110
+ if (j.has("stationaryRadius")) c.setStationaryRadius((float) j.getDouble("stationaryRadius"));
111
+ if (j.has("distanceFilter")) c.setDistanceFilter(j.getInt("distanceFilter"));
112
+ if (j.has("desiredAccuracy")) c.setDesiredAccuracy(j.getInt("desiredAccuracy"));
113
+ if (j.has("debug")) c.setDebugging(j.getBoolean("debug"));
114
+ if (j.has("notificationTitle")) c.setNotificationTitle(readNullable(j, "notificationTitle"));
115
+ if (j.has("notificationText")) c.setNotificationText(readNullable(j, "notificationText"));
116
+ if (j.has("notificationSyncTitle")) c.setNotificationSyncTitle(readNullable(j, "notificationSyncTitle"));
117
+ if (j.has("notificationSyncText")) c.setNotificationSyncText(readNullable(j, "notificationSyncText"));
118
+ if (j.has("notificationSyncCompletedText")) c.setNotificationSyncCompletedText(readNullable(j, "notificationSyncCompletedText"));
119
+ if (j.has("notificationSyncFailedText")) c.setNotificationSyncFailedText(readNullable(j, "notificationSyncFailedText"));
120
+ if (j.has("notificationIconLarge")) c.setLargeNotificationIcon(readNullable(j, "notificationIconLarge"));
121
+ if (j.has("notificationIconSmall")) c.setSmallNotificationIcon(readNullable(j, "notificationIconSmall"));
122
+ if (j.has("notificationIconColor")) c.setNotificationIconColor(readNullable(j, "notificationIconColor"));
123
+ if (j.has("locationProvider")) c.setLocationProvider(j.getInt("locationProvider"));
124
+ if (j.has("interval")) c.setInterval(j.getInt("interval"));
125
+ if (j.has("fastestInterval")) c.setFastestInterval(j.getInt("fastestInterval"));
126
+ if (j.has("activitiesInterval")) c.setActivitiesInterval(j.getInt("activitiesInterval"));
127
+ if (j.has("stopOnTerminate")) c.setStopOnTerminate(j.getBoolean("stopOnTerminate"));
128
+ if (j.has("startOnBoot")) c.setStartOnBoot(j.getBoolean("startOnBoot"));
129
+ if (j.has("startForeground")) c.setStartForeground(j.getBoolean("startForeground"));
130
+ if (j.has("notificationsEnabled")) c.setNotificationsEnabled(j.getBoolean("notificationsEnabled"));
131
+ if (j.has("stopOnStillActivity")) c.setStopOnStillActivity(j.getBoolean("stopOnStillActivity"));
132
+ if (j.has("url")) c.setUrl(readNullable(j, "url"));
133
+ if (j.has("syncUrl")) c.setSyncUrl(readNullable(j, "syncUrl"));
134
+ if (j.has("syncThreshold")) c.setSyncThreshold(j.getInt("syncThreshold"));
135
+ if (j.has("syncEnabled")) c.setSyncEnabled(j.getBoolean("syncEnabled"));
136
+ if (j.has("maxLocations")) c.setMaxLocations(j.getInt("maxLocations"));
137
+ if (j.has("enableWatchdog")) c.setEnableWatchdog(j.getBoolean("enableWatchdog"));
138
+ if (j.has("showTime")) c.setShowTime(j.getBoolean("showTime"));
139
+ if (j.has("showDistance")) c.setShowDistance(j.getBoolean("showDistance"));
140
+ if (has(j, "httpMethod")) c.setHttpMethod(j.getString("httpMethod"));
141
+ if (has(j, "syncHttpMethod")) c.setSyncHttpMethod(j.getString("syncHttpMethod"));
142
+ if (has(j, "httpMode")) c.setHttpMode(j.getString("httpMode"));
143
+ if (has(j, "syncMode")) c.setSyncMode(j.getString("syncMode"));
144
+ if (j.has("heartbeatInterval")) c.setHeartbeatInterval(j.getInt("heartbeatInterval"));
145
+ if (has(j, "mockLocationPolicy")) c.setMockLocationPolicy(j.getString("mockLocationPolicy"));
146
+ if (j.has("includeBattery")) c.setIncludeBattery(j.getBoolean("includeBattery"));
147
+ // v4.5.1: battery knobs
148
+ if (has(j, "wakeLockMode")) c.setWakeLockMode(j.getString("wakeLockMode"));
149
+ if (j.has("stationaryTimeout") && !j.isNull("stationaryTimeout")) c.setStationaryTimeout(j.getInt("stationaryTimeout"));
150
+ if (j.has("stationaryPollInterval") && !j.isNull("stationaryPollInterval")) c.setStationaryPollInterval(j.getInt("stationaryPollInterval"));
151
+ if (j.has("stationaryPollFast") && !j.isNull("stationaryPollFast")) c.setStationaryPollFast(j.getInt("stationaryPollFast"));
152
+
153
+ if (has(j, "httpHeaders")) c.setHttpHeaders(jsonToHashMap(j.getJSONObject("httpHeaders")));
154
+ if (has(j, "queryParams")) c.setQueryParams(jsonToHashMap(j.getJSONObject("queryParams")));
155
+
156
+ if (has(j, "drivingEvents")) {
157
+ JSONObject de = j.getJSONObject("drivingEvents");
158
+ Config.DrivingEventsOptions o = new Config.DrivingEventsOptions();
159
+ if (de.has("enabled")) o.enabled = de.getBoolean("enabled");
160
+ if (de.has("speedLimit")) o.speedLimitKmh = de.getDouble("speedLimit");
161
+ if (de.has("minMovingSpeed")) o.minMovingSpeedMps = de.getDouble("minMovingSpeed");
162
+ if (de.has("stoppedDuration")) o.stoppedDurationMs = de.getLong("stoppedDuration");
163
+ if (de.has("minTripSpeed")) o.minTripSpeedMps = de.getDouble("minTripSpeed");
164
+ if (de.has("minTripDuration")) o.minTripDurationMs = de.getLong("minTripDuration");
165
+ if (de.has("hardBrakeMps2")) o.hardBrakeMps2 = de.getDouble("hardBrakeMps2");
166
+ if (de.has("rapidAccelMps2")) o.rapidAccelMps2 = de.getDouble("rapidAccelMps2");
167
+ if (de.has("sharpTurnDegPerSec")) o.sharpTurnDegPerSec = de.getDouble("sharpTurnDegPerSec");
168
+ if (de.has("crashImpactKmh")) o.crashImpactKmh = de.getDouble("crashImpactKmh");
169
+ if (de.has("crashWindowMs")) o.crashWindowMs = de.getLong("crashWindowMs");
170
+ if (de.has("sensorFusion")) o.sensorFusion = de.getBoolean("sensorFusion");
171
+ if (de.has("crashImpactG")) o.crashImpactG = de.getDouble("crashImpactG");
172
+ if (de.has("sensorCrashCooldownMs")) o.sensorCrashCooldownMs = de.getLong("sensorCrashCooldownMs");
173
+ if (de.has("phoneUsageWindowMs")) o.phoneUsageWindowMs = de.getLong("phoneUsageWindowMs");
174
+ if (de.has("phoneUsageCooldownMs")) o.phoneUsageCooldownMs = de.getLong("phoneUsageCooldownMs");
175
+ c.setDrivingEvents(o);
176
+ }
177
+ return c;
178
+ }
179
+
180
+ private static HashMap<String, String> jsonToHashMap(JSONObject obj) throws JSONException {
181
+ HashMap<String, String> map = new HashMap<>();
182
+ Iterator<String> keys = obj.keys();
183
+ while (keys.hasNext()) {
184
+ String k = keys.next();
185
+ map.put(k, String.valueOf(obj.get(k)));
186
+ }
187
+ return map;
188
+ }
189
+
190
+ private static boolean has(JSONObject j, String key) {
191
+ return j.has(key) && !j.isNull(key);
192
+ }
193
+
194
+ /** Map {@link Config#NullString} or null to JSONObject.NULL so the sentinel survives. */
195
+ private static Object nullable(String s) {
196
+ if (s == null || s == Config.NullString) return JSONObject.NULL;
197
+ return s;
198
+ }
199
+
200
+ /** Inverse of {@link #nullable(String)}. JSON null → {@link Config#NullString}. */
201
+ private static String readNullable(JSONObject j, String key) throws JSONException {
202
+ if (j.isNull(key)) return Config.NullString;
203
+ return j.getString(key);
204
+ }
205
+ }
@@ -60,6 +60,12 @@ public class LocationTemplateFactory {
60
60
  attrs.put("altitude", "@altitude");
61
61
  attrs.put("bearing", "@bearing");
62
62
  attrs.put("radius", "@radius");
63
+ // v4.5.1 — README/CHANGELOG promete que el payload default incluye events/battery/isCharging.
64
+ // Como Config.getTemplate() siempre cae a este default si no hay postTemplate custom, hay
65
+ // que añadirlos aquí para que PostLocationTask + BatchManager los serialicen al backend.
66
+ attrs.put("events", "@events");
67
+ attrs.put("battery", "@battery");
68
+ attrs.put("isCharging", "@isCharging");
63
69
  return new HashMapLocationTemplate(attrs);
64
70
  }
65
71
  }
@@ -47,6 +47,9 @@ public final class SQLiteConfigurationContract {
47
47
  public static final String COLUMN_NAME_TEMPLATE = "template";
48
48
  public static final String COLUMN_NAME_SHOW_TIME = "show_time";
49
49
  public static final String COLUMN_NAME_SHOW_DISTANCE = "show_distance";
50
+ // v4.4.1 — single JSON blob holding the full config (replaces per-field columns
51
+ // for new keys). Old columns are kept for backward compat with v20 databases.
52
+ public static final String COLUMN_NAME_CONFIG_JSON = "config_json";
50
53
 
51
54
  public static final String SQL_CREATE_CONFIG_TABLE =
52
55
  "CREATE TABLE " + ConfigurationEntry.TABLE_NAME + " (" +
@@ -81,7 +84,8 @@ public final class SQLiteConfigurationContract {
81
84
  ConfigurationEntry.COLUMN_NAME_MAX_LOCATIONS + INTEGER_TYPE + COMMA_SEP +
82
85
  ConfigurationEntry.COLUMN_NAME_TEMPLATE + TEXT_TYPE + COMMA_SEP +
83
86
  ConfigurationEntry.COLUMN_NAME_SHOW_TIME + INTEGER_TYPE + COMMA_SEP +
84
- ConfigurationEntry.COLUMN_NAME_SHOW_DISTANCE + INTEGER_TYPE +
87
+ ConfigurationEntry.COLUMN_NAME_SHOW_DISTANCE + INTEGER_TYPE + COMMA_SEP +
88
+ ConfigurationEntry.COLUMN_NAME_CONFIG_JSON + TEXT_TYPE +
85
89
  " )";
86
90
 
87
91
  public static final String SQL_DROP_CONFIG_TABLE =
@@ -10,6 +10,7 @@ import org.json.JSONObject;
10
10
  import org.json.JSONException;
11
11
 
12
12
  import com.marianhello.bgloc.Config;
13
+ import com.marianhello.bgloc.data.ConfigJsonMapper;
13
14
  import com.marianhello.bgloc.data.ConfigurationDAO;
14
15
  import com.marianhello.bgloc.data.LocationTemplateFactory;
15
16
  import com.marianhello.bgloc.data.sqlite.SQLiteConfigurationContract.ConfigurationEntry;
@@ -63,7 +64,8 @@ public class SQLiteConfigurationDAO implements ConfigurationDAO {
63
64
  ConfigurationEntry.COLUMN_NAME_MAX_LOCATIONS,
64
65
  ConfigurationEntry.COLUMN_NAME_TEMPLATE,
65
66
  ConfigurationEntry.COLUMN_NAME_SHOW_TIME,
66
- ConfigurationEntry.COLUMN_NAME_SHOW_DISTANCE
67
+ ConfigurationEntry.COLUMN_NAME_SHOW_DISTANCE,
68
+ ConfigurationEntry.COLUMN_NAME_CONFIG_JSON
67
69
  };
68
70
 
69
71
  String whereClause = null;
@@ -105,6 +107,26 @@ public class SQLiteConfigurationDAO implements ConfigurationDAO {
105
107
  }
106
108
 
107
109
  private Config hydrate(Cursor c) throws JSONException {
110
+ // v4.4.1: prefer the full JSON blob if present (covers all keys, including post-3.2 ones).
111
+ // Note: `template` (postTemplate) lives in its dedicated column — restore it after the
112
+ // JSON deserialization so it's not lost when the config arrived via config_json only.
113
+ int idxJson = c.getColumnIndex(ConfigurationEntry.COLUMN_NAME_CONFIG_JSON);
114
+ if (idxJson >= 0 && !c.isNull(idxJson)) {
115
+ String json = c.getString(idxJson);
116
+ if (json != null && !json.isEmpty()) {
117
+ try {
118
+ Config restored = ConfigJsonMapper.fromJSONObject(new JSONObject(json));
119
+ int idxTpl = c.getColumnIndex(ConfigurationEntry.COLUMN_NAME_TEMPLATE);
120
+ if (idxTpl >= 0 && !c.isNull(idxTpl)) {
121
+ restored.setTemplate(LocationTemplateFactory.fromJSONString(c.getString(idxTpl)));
122
+ }
123
+ return restored;
124
+ } catch (JSONException ex) {
125
+ Log.w(TAG, "config_json parse failed; falling back to legacy columns: " + ex.getMessage());
126
+ }
127
+ }
128
+ }
129
+ // Legacy hydration (DBs upgraded from v20 or earlier where config_json is still NULL).
108
130
  Config config = Config.getDefault();
109
131
  config.setStationaryRadius(c.getFloat(c.getColumnIndex(ConfigurationEntry.COLUMN_NAME_RADIUS)));
110
132
  config.setDistanceFilter(c.getInt(c.getColumnIndex(ConfigurationEntry.COLUMN_NAME_DISTANCE_FILTER)));
@@ -190,6 +212,15 @@ public class SQLiteConfigurationDAO implements ConfigurationDAO {
190
212
  values.put(ConfigurationEntry.COLUMN_NAME_TEMPLATE, config.hasTemplate() ? config.getTemplate().toString() : null);
191
213
  values.put(ConfigurationEntry.COLUMN_NAME_SHOW_TIME, Boolean.TRUE.equals(config.getShowTime()) ? 1 : 0);
192
214
  values.put(ConfigurationEntry.COLUMN_NAME_SHOW_DISTANCE, Boolean.TRUE.equals(config.getShowDistance()) ? 1 : 0);
215
+ // v4.4.1: persist the full Config as JSON so post-3.2 fields (httpMethod, queryParams,
216
+ // drivingEvents, includeBattery, mockLocationPolicy, heartbeatInterval, ...) survive
217
+ // a reboot / startOnBoot. Legacy columns are kept populated above for backward compat.
218
+ try {
219
+ values.put(ConfigurationEntry.COLUMN_NAME_CONFIG_JSON,
220
+ ConfigJsonMapper.toJSONObject(config).toString());
221
+ } catch (JSONException e) {
222
+ Log.w(TAG, "config_json serialize failed: " + e.getMessage());
223
+ }
193
224
 
194
225
  return values;
195
226
  }
@@ -37,6 +37,10 @@ public final class SQLiteLocationContract {
37
37
  public static final String COLUMN_NAME_STATUS = "valid";
38
38
  public static final String COLUMN_NAME_BATCH_START_MILLIS = "batch_start";
39
39
  public static final String COLUMN_NAME_MOCK_FLAGS = "mock_flags";
40
+ // v4.5 — survive sync queue: events JSON, battery percentage and charging state.
41
+ public static final String COLUMN_NAME_EVENTS_JSON = "events_json";
42
+ public static final String COLUMN_NAME_BATTERY_LEVEL = "battery_level";
43
+ public static final String COLUMN_NAME_IS_CHARGING = "is_charging";
40
44
 
41
45
  public static final String SQL_CREATE_LOCATION_TABLE =
42
46
  "CREATE TABLE " + LocationEntry.TABLE_NAME + " (" +
@@ -60,7 +64,10 @@ public final class SQLiteLocationContract {
60
64
  LocationEntry.COLUMN_NAME_LOCATION_PROVIDER + INTEGER_TYPE + COMMA_SEP +
61
65
  LocationEntry.COLUMN_NAME_STATUS + INTEGER_TYPE + COMMA_SEP +
62
66
  LocationEntry.COLUMN_NAME_BATCH_START_MILLIS + INTEGER_TYPE + COMMA_SEP +
63
- LocationEntry.COLUMN_NAME_MOCK_FLAGS + INTEGER_TYPE +
67
+ LocationEntry.COLUMN_NAME_MOCK_FLAGS + INTEGER_TYPE + COMMA_SEP +
68
+ LocationEntry.COLUMN_NAME_EVENTS_JSON + TEXT_TYPE + COMMA_SEP +
69
+ LocationEntry.COLUMN_NAME_BATTERY_LEVEL + INTEGER_TYPE + COMMA_SEP +
70
+ LocationEntry.COLUMN_NAME_IS_CHARGING + INTEGER_TYPE +
64
71
  " )";
65
72
 
66
73
  public static final String SQL_DROP_LOCATION_TABLE =
@@ -106,7 +113,10 @@ public final class SQLiteLocationContract {
106
113
  COLUMN_NAME_LOCATION_PROVIDER,
107
114
  COLUMN_NAME_STATUS,
108
115
  COLUMN_NAME_BATCH_START_MILLIS,
109
- COLUMN_NAME_MOCK_FLAGS
116
+ COLUMN_NAME_MOCK_FLAGS,
117
+ COLUMN_NAME_EVENTS_JSON,
118
+ COLUMN_NAME_BATTERY_LEVEL,
119
+ COLUMN_NAME_IS_CHARGING
110
120
  };
111
121
  }
112
122
  }