@josuelmm/capacitor-background-geolocation 1.0.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.
Files changed (207) hide show
  1. package/JosuelmmCapacitorBackgroundGeolocation.podspec +34 -0
  2. package/LICENSE +17 -0
  3. package/NOTICE.md +32 -0
  4. package/Package.swift +45 -0
  5. package/README.md +402 -0
  6. package/android/build.gradle +79 -0
  7. package/android/proguard-rules.pro +1 -0
  8. package/android/src/main/AndroidManifest.xml +83 -0
  9. package/android/src/main/java/com/evgenii/jsevaluator/HandlerWrapper.java +18 -0
  10. package/android/src/main/java/com/evgenii/jsevaluator/JavaScriptInterface.java +22 -0
  11. package/android/src/main/java/com/evgenii/jsevaluator/JsEvaluator.java +133 -0
  12. package/android/src/main/java/com/evgenii/jsevaluator/JsFunctionCallFormatter.java +37 -0
  13. package/android/src/main/java/com/evgenii/jsevaluator/WebViewWrapper.java +71 -0
  14. package/android/src/main/java/com/evgenii/jsevaluator/interfaces/CallJavaResultInterface.java +8 -0
  15. package/android/src/main/java/com/evgenii/jsevaluator/interfaces/HandlerWrapperInterface.java +5 -0
  16. package/android/src/main/java/com/evgenii/jsevaluator/interfaces/JsCallback.java +10 -0
  17. package/android/src/main/java/com/evgenii/jsevaluator/interfaces/JsEvaluatorInterface.java +18 -0
  18. package/android/src/main/java/com/evgenii/jsevaluator/interfaces/WebViewWrapperInterface.java +14 -0
  19. package/android/src/main/java/com/josuelmm/capacitor/backgroundgeolocation/BackgroundGeolocationPlugin.java +898 -0
  20. package/android/src/main/java/com/josuelmm/capacitor/backgroundgeolocation/ConfigMapper.java +303 -0
  21. package/android/src/main/java/com/josuelmm/capacitor/backgroundgeolocation/HeadlessTaskRegistry.java +34 -0
  22. package/android/src/main/java/com/josuelmm/capacitor/backgroundgeolocation/JsEvaluatorTaskRunner.java +63 -0
  23. package/android/src/main/java/com/marianhello/bgloc/BackgroundGeolocationFacade.java +699 -0
  24. package/android/src/main/java/com/marianhello/bgloc/BootCompletedReceiver.java +103 -0
  25. package/android/src/main/java/com/marianhello/bgloc/Config.java +1155 -0
  26. package/android/src/main/java/com/marianhello/bgloc/ConnectivityListener.java +5 -0
  27. package/android/src/main/java/com/marianhello/bgloc/HttpPostService.java +362 -0
  28. package/android/src/main/java/com/marianhello/bgloc/LocationManager.java +138 -0
  29. package/android/src/main/java/com/marianhello/bgloc/PluginDelegate.java +45 -0
  30. package/android/src/main/java/com/marianhello/bgloc/PluginException.java +38 -0
  31. package/android/src/main/java/com/marianhello/bgloc/PostLocationTask.java +238 -0
  32. package/android/src/main/java/com/marianhello/bgloc/ResourceResolver.java +55 -0
  33. package/android/src/main/java/com/marianhello/bgloc/data/AbstractLocationTemplate.java +69 -0
  34. package/android/src/main/java/com/marianhello/bgloc/data/ArrayListLocationTemplate.java +88 -0
  35. package/android/src/main/java/com/marianhello/bgloc/data/BackgroundActivity.java +108 -0
  36. package/android/src/main/java/com/marianhello/bgloc/data/BackgroundLocation.java +1088 -0
  37. package/android/src/main/java/com/marianhello/bgloc/data/ConfigJsonMapper.java +211 -0
  38. package/android/src/main/java/com/marianhello/bgloc/data/ConfigurationDAO.java +13 -0
  39. package/android/src/main/java/com/marianhello/bgloc/data/DAOFactory.java +17 -0
  40. package/android/src/main/java/com/marianhello/bgloc/data/HashMapLocationTemplate.java +82 -0
  41. package/android/src/main/java/com/marianhello/bgloc/data/LocationDAO.java +27 -0
  42. package/android/src/main/java/com/marianhello/bgloc/data/LocationTemplate.java +12 -0
  43. package/android/src/main/java/com/marianhello/bgloc/data/LocationTemplateFactory.java +71 -0
  44. package/android/src/main/java/com/marianhello/bgloc/data/LocationTransform.java +19 -0
  45. package/android/src/main/java/com/marianhello/bgloc/data/SessionLocationDAO.java +18 -0
  46. package/android/src/main/java/com/marianhello/bgloc/data/provider/ContentProviderLocationDAO.java +406 -0
  47. package/android/src/main/java/com/marianhello/bgloc/data/provider/LocationContentProvider.java +321 -0
  48. package/android/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteConfigurationContract.java +94 -0
  49. package/android/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteConfigurationDAO.java +227 -0
  50. package/android/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteLocationContract.java +122 -0
  51. package/android/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteLocationDAO.java +550 -0
  52. package/android/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteOpenHelper.java +189 -0
  53. package/android/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteSessionContract.java +74 -0
  54. package/android/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteSessionLocationDAO.java +169 -0
  55. package/android/src/main/java/com/marianhello/bgloc/driving/DrivingEventsDetector.java +265 -0
  56. package/android/src/main/java/com/marianhello/bgloc/headless/AbstractTaskRunner.java +15 -0
  57. package/android/src/main/java/com/marianhello/bgloc/headless/ActivityTask.java +48 -0
  58. package/android/src/main/java/com/marianhello/bgloc/headless/JsCallback.java +10 -0
  59. package/android/src/main/java/com/marianhello/bgloc/headless/LocationTask.java +60 -0
  60. package/android/src/main/java/com/marianhello/bgloc/headless/StationaryTask.java +25 -0
  61. package/android/src/main/java/com/marianhello/bgloc/headless/Task.java +8 -0
  62. package/android/src/main/java/com/marianhello/bgloc/headless/TaskRunner.java +5 -0
  63. package/android/src/main/java/com/marianhello/bgloc/headless/TaskRunnerFactory.java +8 -0
  64. package/android/src/main/java/com/marianhello/bgloc/http/UrlTemplateResolver.java +115 -0
  65. package/android/src/main/java/com/marianhello/bgloc/oem/BatteryOemHelper.java +214 -0
  66. package/android/src/main/java/com/marianhello/bgloc/provider/AbstractLocationProvider.java +218 -0
  67. package/android/src/main/java/com/marianhello/bgloc/provider/ActivityRecognitionLocationProvider.java +385 -0
  68. package/android/src/main/java/com/marianhello/bgloc/provider/DistanceFilterLocationProvider.java +685 -0
  69. package/android/src/main/java/com/marianhello/bgloc/provider/LocationProvider.java +32 -0
  70. package/android/src/main/java/com/marianhello/bgloc/provider/LocationProviderFactory.java +47 -0
  71. package/android/src/main/java/com/marianhello/bgloc/provider/ProviderDelegate.java +12 -0
  72. package/android/src/main/java/com/marianhello/bgloc/provider/RawLocationProvider.java +175 -0
  73. package/android/src/main/java/com/marianhello/bgloc/sensor/SensorFusionDetector.java +199 -0
  74. package/android/src/main/java/com/marianhello/bgloc/service/LocationService.java +16 -0
  75. package/android/src/main/java/com/marianhello/bgloc/service/LocationServiceImpl.java +1531 -0
  76. package/android/src/main/java/com/marianhello/bgloc/service/LocationServiceInfo.java +6 -0
  77. package/android/src/main/java/com/marianhello/bgloc/service/LocationServiceInfoImpl.java +41 -0
  78. package/android/src/main/java/com/marianhello/bgloc/service/LocationServiceIntentBuilder.java +203 -0
  79. package/android/src/main/java/com/marianhello/bgloc/service/LocationServiceProxy.java +156 -0
  80. package/android/src/main/java/com/marianhello/bgloc/sync/AccountHelper.java +39 -0
  81. package/android/src/main/java/com/marianhello/bgloc/sync/Authenticator.java +68 -0
  82. package/android/src/main/java/com/marianhello/bgloc/sync/AuthenticatorService.java +28 -0
  83. package/android/src/main/java/com/marianhello/bgloc/sync/BatchManager.java +311 -0
  84. package/android/src/main/java/com/marianhello/bgloc/sync/NotificationHelper.java +148 -0
  85. package/android/src/main/java/com/marianhello/bgloc/sync/SyncAdapter.java +301 -0
  86. package/android/src/main/java/com/marianhello/bgloc/sync/SyncService.java +68 -0
  87. package/android/src/main/java/com/marianhello/logging/DBLogReader.java +208 -0
  88. package/android/src/main/java/com/marianhello/logging/LogEntry.java +99 -0
  89. package/android/src/main/java/com/marianhello/logging/LoggerManager.java +70 -0
  90. package/android/src/main/java/com/marianhello/logging/UncaughtExceptionLogger.java +36 -0
  91. package/android/src/main/java/com/marianhello/utils/CloneHelper.java +22 -0
  92. package/android/src/main/java/com/marianhello/utils/Convert.java +56 -0
  93. package/android/src/main/java/com/marianhello/utils/TextUtils.java +72 -0
  94. package/android/src/main/java/com/marianhello/utils/ToneGenerator.java +68 -0
  95. package/android/src/main/java/org/apache/commons/io/Charsets.java +153 -0
  96. package/android/src/main/java/org/apache/commons/io/input/ReversedLinesFileReader.java +344 -0
  97. package/android/src/main/java/org/chromium/content/browser/ThreadUtils.java +134 -0
  98. package/android/src/main/java/ru/andremoniy/sqlbuilder/SqlExpression.java +398 -0
  99. package/android/src/main/java/ru/andremoniy/sqlbuilder/SqlSelectStatement.java +671 -0
  100. package/android/src/main/java/ru/andremoniy/sqlbuilder/SqlStatement.java +29 -0
  101. package/android/src/main/java/ru/andremoniy/utils/TextUtils.java +61 -0
  102. package/android/src/main/res/mipmap-hdpi/ic_launcher.png +0 -0
  103. package/android/src/main/res/mipmap-mdpi/ic_launcher.png +0 -0
  104. package/android/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  105. package/android/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  106. package/android/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  107. package/android/src/main/res/values/strings.xml +15 -0
  108. package/android/src/main/res/xml/authenticator.xml +7 -0
  109. package/android/src/main/res/xml/syncadapter.xml +9 -0
  110. package/dist/esm/definitions.d.ts +1052 -0
  111. package/dist/esm/definitions.js +142 -0
  112. package/dist/esm/definitions.js.map +1 -0
  113. package/dist/esm/index.d.ts +8 -0
  114. package/dist/esm/index.js +23 -0
  115. package/dist/esm/index.js.map +1 -0
  116. package/dist/esm/web.d.ts +92 -0
  117. package/dist/esm/web.js +242 -0
  118. package/dist/esm/web.js.map +1 -0
  119. package/dist/plugin.cjs.js +415 -0
  120. package/dist/plugin.cjs.js.map +1 -0
  121. package/dist/plugin.js +418 -0
  122. package/dist/plugin.js.map +1 -0
  123. package/ios/Sources/BackgroundGeolocationPlugin/BackgroundGeolocationPlugin-Bridging-Header.h +18 -0
  124. package/ios/Sources/BackgroundGeolocationPlugin/BackgroundGeolocationPlugin.m +52 -0
  125. package/ios/Sources/BackgroundGeolocationPlugin/BackgroundGeolocationPlugin.swift +750 -0
  126. package/ios/Tests/BackgroundGeolocationPluginTests/BackgroundGeolocationPluginTests.swift +12 -0
  127. package/ios/common/BackgroundGeolocation/CocoaLumberjack.h +1945 -0
  128. package/ios/common/BackgroundGeolocation/CocoaLumberjack.m +5255 -0
  129. package/ios/common/BackgroundGeolocation/FMDB.h +2357 -0
  130. package/ios/common/BackgroundGeolocation/FMDB.m +2672 -0
  131. package/ios/common/BackgroundGeolocation/FMDBLogger.h +42 -0
  132. package/ios/common/BackgroundGeolocation/FMDBLogger.m +264 -0
  133. package/ios/common/BackgroundGeolocation/INTULocationManager/INTUHeadingRequest.h +41 -0
  134. package/ios/common/BackgroundGeolocation/INTULocationManager/INTUHeadingRequest.m +68 -0
  135. package/ios/common/BackgroundGeolocation/INTULocationManager/INTULocationManager+Internal.h +33 -0
  136. package/ios/common/BackgroundGeolocation/INTULocationManager/INTULocationManager.h +178 -0
  137. package/ios/common/BackgroundGeolocation/INTULocationManager/INTULocationManager.m +1025 -0
  138. package/ios/common/BackgroundGeolocation/INTULocationManager/INTULocationRequest.h +103 -0
  139. package/ios/common/BackgroundGeolocation/INTULocationManager/INTULocationRequest.m +238 -0
  140. package/ios/common/BackgroundGeolocation/INTULocationManager/INTULocationRequestDefines.h +163 -0
  141. package/ios/common/BackgroundGeolocation/INTULocationManager/INTURequestIDGenerator.h +39 -0
  142. package/ios/common/BackgroundGeolocation/INTULocationManager/INTURequestIDGenerator.m +37 -0
  143. package/ios/common/BackgroundGeolocation/MAURAbstractLocationProvider.h +51 -0
  144. package/ios/common/BackgroundGeolocation/MAURAbstractLocationProvider.m +53 -0
  145. package/ios/common/BackgroundGeolocation/MAURActivity.h +23 -0
  146. package/ios/common/BackgroundGeolocation/MAURActivity.m +52 -0
  147. package/ios/common/BackgroundGeolocation/MAURActivityLocationProvider.h +18 -0
  148. package/ios/common/BackgroundGeolocation/MAURActivityLocationProvider.m +340 -0
  149. package/ios/common/BackgroundGeolocation/MAURBackgroundGeolocationFacade.h +88 -0
  150. package/ios/common/BackgroundGeolocation/MAURBackgroundGeolocationFacade.m +1193 -0
  151. package/ios/common/BackgroundGeolocation/MAURBackgroundSync.h +46 -0
  152. package/ios/common/BackgroundGeolocation/MAURBackgroundSync.m +283 -0
  153. package/ios/common/BackgroundGeolocation/MAURBackgroundTaskManager.h +25 -0
  154. package/ios/common/BackgroundGeolocation/MAURBackgroundTaskManager.m +105 -0
  155. package/ios/common/BackgroundGeolocation/MAURConfig.h +99 -0
  156. package/ios/common/BackgroundGeolocation/MAURConfig.m +636 -0
  157. package/ios/common/BackgroundGeolocation/MAURConfigurationContract.h +53 -0
  158. package/ios/common/BackgroundGeolocation/MAURConfigurationContract.m +54 -0
  159. package/ios/common/BackgroundGeolocation/MAURDistanceFilterLocationProvider.h +20 -0
  160. package/ios/common/BackgroundGeolocation/MAURDistanceFilterLocationProvider.m +550 -0
  161. package/ios/common/BackgroundGeolocation/MAURGeolocationOpenHelper.h +17 -0
  162. package/ios/common/BackgroundGeolocation/MAURGeolocationOpenHelper.m +124 -0
  163. package/ios/common/BackgroundGeolocation/MAURLocation.h +73 -0
  164. package/ios/common/BackgroundGeolocation/MAURLocation.m +392 -0
  165. package/ios/common/BackgroundGeolocation/MAURLocationContract.h +38 -0
  166. package/ios/common/BackgroundGeolocation/MAURLocationContract.m +39 -0
  167. package/ios/common/BackgroundGeolocation/MAURLocationManager.h +53 -0
  168. package/ios/common/BackgroundGeolocation/MAURLocationManager.m +305 -0
  169. package/ios/common/BackgroundGeolocation/MAURLogReader.h +26 -0
  170. package/ios/common/BackgroundGeolocation/MAURLogReader.m +122 -0
  171. package/ios/common/BackgroundGeolocation/MAURLogging.h +19 -0
  172. package/ios/common/BackgroundGeolocation/MAURPostLocationTask.h +53 -0
  173. package/ios/common/BackgroundGeolocation/MAURPostLocationTask.m +367 -0
  174. package/ios/common/BackgroundGeolocation/MAURProviderDelegate.h +52 -0
  175. package/ios/common/BackgroundGeolocation/MAURRawLocationProvider.h +18 -0
  176. package/ios/common/BackgroundGeolocation/MAURRawLocationProvider.m +138 -0
  177. package/ios/common/BackgroundGeolocation/MAURSQLiteConfigurationDAO.h +26 -0
  178. package/ios/common/BackgroundGeolocation/MAURSQLiteConfigurationDAO.m +335 -0
  179. package/ios/common/BackgroundGeolocation/MAURSQLiteHelper.h +57 -0
  180. package/ios/common/BackgroundGeolocation/MAURSQLiteHelper.m +93 -0
  181. package/ios/common/BackgroundGeolocation/MAURSQLiteLocationDAO.h +52 -0
  182. package/ios/common/BackgroundGeolocation/MAURSQLiteLocationDAO.m +520 -0
  183. package/ios/common/BackgroundGeolocation/MAURSQLiteOpenHelper.h +32 -0
  184. package/ios/common/BackgroundGeolocation/MAURSQLiteOpenHelper.m +276 -0
  185. package/ios/common/BackgroundGeolocation/MAURSensorFusionDetector.h +41 -0
  186. package/ios/common/BackgroundGeolocation/MAURSensorFusionDetector.m +137 -0
  187. package/ios/common/BackgroundGeolocation/MAURSessionLocationContract.h +29 -0
  188. package/ios/common/BackgroundGeolocation/MAURSessionLocationContract.m +31 -0
  189. package/ios/common/BackgroundGeolocation/MAURSessionLocationDAO.h +25 -0
  190. package/ios/common/BackgroundGeolocation/MAURSessionLocationDAO.m +153 -0
  191. package/ios/common/BackgroundGeolocation/MAURUncaughtExceptionLogger.h +20 -0
  192. package/ios/common/BackgroundGeolocation/MAURUncaughtExceptionLogger.m +62 -0
  193. package/ios/common/BackgroundGeolocation/MAURUrlTemplateResolver.h +31 -0
  194. package/ios/common/BackgroundGeolocation/MAURUrlTemplateResolver.m +107 -0
  195. package/ios/common/BackgroundGeolocation/Reachability.h +102 -0
  196. package/ios/common/BackgroundGeolocation/Reachability.m +475 -0
  197. package/ios/common/BackgroundGeolocation/SQLQueryBuilder/README.md +170 -0
  198. package/ios/common/BackgroundGeolocation/SQLQueryBuilder/ext/NSString+ZIMString.h +55 -0
  199. package/ios/common/BackgroundGeolocation/SQLQueryBuilder/ext/NSString+ZIMString.m +47 -0
  200. package/ios/common/BackgroundGeolocation/SQLQueryBuilder/sql/ZIMSqlDataManipulationCommand.h +27 -0
  201. package/ios/common/BackgroundGeolocation/SQLQueryBuilder/sql/ZIMSqlExpression.h +250 -0
  202. package/ios/common/BackgroundGeolocation/SQLQueryBuilder/sql/ZIMSqlExpression.m +259 -0
  203. package/ios/common/BackgroundGeolocation/SQLQueryBuilder/sql/ZIMSqlSelectStatement.h +360 -0
  204. package/ios/common/BackgroundGeolocation/SQLQueryBuilder/sql/ZIMSqlSelectStatement.m +427 -0
  205. package/ios/common/BackgroundGeolocation/SQLQueryBuilder/sql/ZIMSqlStatement.h +37 -0
  206. package/ios/common/BackgroundGeolocation/module.modulemap +16 -0
  207. package/package.json +82 -0
@@ -0,0 +1,122 @@
1
+ package com.marianhello.bgloc.data.sqlite;
2
+
3
+ import android.net.Uri;
4
+ import android.provider.BaseColumns;
5
+
6
+ import static com.marianhello.bgloc.data.sqlite.SQLiteOpenHelper.COMMA_SEP;
7
+ import static com.marianhello.bgloc.data.sqlite.SQLiteOpenHelper.INTEGER_TYPE;
8
+ import static com.marianhello.bgloc.data.sqlite.SQLiteOpenHelper.REAL_TYPE;
9
+ import static com.marianhello.bgloc.data.sqlite.SQLiteOpenHelper.TEXT_TYPE;
10
+
11
+ public final class SQLiteLocationContract {
12
+ // To prevent someone from accidentally instantiating the contract class,
13
+ // give it an empty constructor.
14
+ public SQLiteLocationContract() {}
15
+
16
+ /* Inner class that defines the table contents */
17
+ public static abstract class LocationEntry implements BaseColumns {
18
+ public static final String TABLE_NAME = "location";
19
+ public static final String COLUMN_NAME_NULLABLE = "NULLHACK";
20
+ public static final String COLUMN_NAME_TIME = "time";
21
+ public static final String COLUMN_NAME_ACCURACY = "accuracy";
22
+ public static final String COLUMN_NAME_VERTICAL_ACCURACY = "vertical_accuracy";
23
+ public static final String COLUMN_NAME_SPEED = "speed";
24
+ public static final String COLUMN_NAME_BEARING = "bearing";
25
+ public static final String COLUMN_NAME_ALTITUDE = "altitude";
26
+ public static final String COLUMN_NAME_LATITUDE = "latitude";
27
+ public static final String COLUMN_NAME_LONGITUDE = "longitude";
28
+ public static final String COLUMN_NAME_RADIUS = "radius";
29
+ public static final String COLUMN_NAME_HAS_ACCURACY = "has_accuracy";
30
+ public static final String COLUMN_NAME_HAS_VERTICAL_ACCURACY = "has_vertical_accuracy";
31
+ public static final String COLUMN_NAME_HAS_SPEED = "has_speed";
32
+ public static final String COLUMN_NAME_HAS_BEARING = "has_bearing";
33
+ public static final String COLUMN_NAME_HAS_ALTITUDE = "has_altitude";
34
+ public static final String COLUMN_NAME_HAS_RADIUS = "has_radius";
35
+ public static final String COLUMN_NAME_PROVIDER = "provider";
36
+ public static final String COLUMN_NAME_LOCATION_PROVIDER = "service_provider";
37
+ public static final String COLUMN_NAME_STATUS = "valid";
38
+ public static final String COLUMN_NAME_BATCH_START_MILLIS = "batch_start";
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";
44
+
45
+ public static final String SQL_CREATE_LOCATION_TABLE =
46
+ "CREATE TABLE " + LocationEntry.TABLE_NAME + " (" +
47
+ LocationEntry._ID + " INTEGER PRIMARY KEY," +
48
+ LocationEntry.COLUMN_NAME_TIME + INTEGER_TYPE + COMMA_SEP +
49
+ LocationEntry.COLUMN_NAME_ACCURACY + REAL_TYPE + COMMA_SEP +
50
+ LocationEntry.COLUMN_NAME_VERTICAL_ACCURACY + REAL_TYPE + COMMA_SEP +
51
+ LocationEntry.COLUMN_NAME_SPEED + REAL_TYPE + COMMA_SEP +
52
+ LocationEntry.COLUMN_NAME_BEARING + REAL_TYPE + COMMA_SEP +
53
+ LocationEntry.COLUMN_NAME_ALTITUDE + REAL_TYPE + COMMA_SEP +
54
+ LocationEntry.COLUMN_NAME_LATITUDE + REAL_TYPE + COMMA_SEP +
55
+ LocationEntry.COLUMN_NAME_LONGITUDE + REAL_TYPE + COMMA_SEP +
56
+ LocationEntry.COLUMN_NAME_RADIUS + REAL_TYPE + COMMA_SEP +
57
+ LocationEntry.COLUMN_NAME_HAS_ACCURACY + INTEGER_TYPE + COMMA_SEP +
58
+ LocationEntry.COLUMN_NAME_HAS_VERTICAL_ACCURACY + INTEGER_TYPE + COMMA_SEP +
59
+ LocationEntry.COLUMN_NAME_HAS_SPEED + INTEGER_TYPE + COMMA_SEP +
60
+ LocationEntry.COLUMN_NAME_HAS_BEARING + INTEGER_TYPE + COMMA_SEP +
61
+ LocationEntry.COLUMN_NAME_HAS_ALTITUDE + INTEGER_TYPE + COMMA_SEP +
62
+ LocationEntry.COLUMN_NAME_HAS_RADIUS + INTEGER_TYPE + COMMA_SEP +
63
+ LocationEntry.COLUMN_NAME_PROVIDER + TEXT_TYPE + COMMA_SEP +
64
+ LocationEntry.COLUMN_NAME_LOCATION_PROVIDER + INTEGER_TYPE + COMMA_SEP +
65
+ LocationEntry.COLUMN_NAME_STATUS + INTEGER_TYPE + COMMA_SEP +
66
+ LocationEntry.COLUMN_NAME_BATCH_START_MILLIS + INTEGER_TYPE + COMMA_SEP +
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 +
71
+ " )";
72
+
73
+ public static final String SQL_DROP_LOCATION_TABLE =
74
+ "DROP TABLE IF EXISTS " + LocationEntry.TABLE_NAME;
75
+
76
+ public static final String SQL_CREATE_LOCATION_TABLE_TIME_IDX =
77
+ "CREATE INDEX time_idx ON " + LocationEntry.TABLE_NAME + " (" + LocationEntry.COLUMN_NAME_TIME + ")";
78
+
79
+ public static final String SQL_CREATE_LOCATION_TABLE_BATCH_ID_IDX =
80
+ "CREATE INDEX batch_id_idx ON " + LocationEntry.TABLE_NAME + " (" + LocationEntry.COLUMN_NAME_BATCH_START_MILLIS + ")";
81
+
82
+ /**
83
+ * The directory base-path
84
+ */
85
+ public static final String DIR_BASEPATH = "locations";
86
+
87
+ /**
88
+ * The items base-path
89
+ */
90
+ public static final String ITEM_BASEPATH = "locations/#";
91
+
92
+ /**
93
+ * A projection of all columns in the items table
94
+ */
95
+ public static final String[] PROJECTION_ALL = {
96
+ _ID,
97
+ COLUMN_NAME_TIME,
98
+ COLUMN_NAME_ACCURACY,
99
+ COLUMN_NAME_VERTICAL_ACCURACY,
100
+ COLUMN_NAME_SPEED,
101
+ COLUMN_NAME_BEARING,
102
+ COLUMN_NAME_ALTITUDE,
103
+ COLUMN_NAME_LATITUDE,
104
+ COLUMN_NAME_LONGITUDE,
105
+ COLUMN_NAME_RADIUS,
106
+ COLUMN_NAME_HAS_ACCURACY,
107
+ COLUMN_NAME_HAS_VERTICAL_ACCURACY,
108
+ COLUMN_NAME_HAS_SPEED,
109
+ COLUMN_NAME_HAS_BEARING,
110
+ COLUMN_NAME_HAS_ALTITUDE,
111
+ COLUMN_NAME_HAS_RADIUS,
112
+ COLUMN_NAME_PROVIDER,
113
+ COLUMN_NAME_LOCATION_PROVIDER,
114
+ COLUMN_NAME_STATUS,
115
+ COLUMN_NAME_BATCH_START_MILLIS,
116
+ COLUMN_NAME_MOCK_FLAGS,
117
+ COLUMN_NAME_EVENTS_JSON,
118
+ COLUMN_NAME_BATTERY_LEVEL,
119
+ COLUMN_NAME_IS_CHARGING
120
+ };
121
+ }
122
+ }
@@ -0,0 +1,550 @@
1
+ package com.marianhello.bgloc.data.sqlite;
2
+
3
+ import android.content.ContentValues;
4
+ import android.content.Context;
5
+ import android.database.Cursor;
6
+ import android.database.DatabaseUtils;
7
+ import android.database.sqlite.SQLiteDatabase;
8
+ import android.text.TextUtils;
9
+
10
+ import com.marianhello.bgloc.data.BackgroundLocation;
11
+ import com.marianhello.bgloc.data.LocationDAO;
12
+ import com.marianhello.bgloc.data.sqlite.SQLiteLocationContract.LocationEntry;
13
+ import ru.andremoniy.sqlbuilder.SqlExpression;
14
+ import ru.andremoniy.sqlbuilder.SqlSelectStatement;
15
+
16
+ import java.util.ArrayList;
17
+ import java.util.Collection;
18
+
19
+ public class SQLiteLocationDAO implements LocationDAO {
20
+ private SQLiteDatabase db;
21
+
22
+ public SQLiteLocationDAO(Context context) {
23
+ SQLiteOpenHelper helper = SQLiteOpenHelper.getHelper(context);
24
+ this.db = helper.getWritableDatabase();
25
+ }
26
+
27
+ public SQLiteLocationDAO(SQLiteDatabase db) {
28
+ this.db = db;
29
+ }
30
+
31
+ /**
32
+ * Get all locations that match whereClause
33
+ *
34
+ * @param whereClause
35
+ * @param whereArgs
36
+ * @return collection of locations
37
+ */
38
+ private Collection<BackgroundLocation> getLocations(String whereClause, String[] whereArgs) {
39
+ Collection<BackgroundLocation> locations = new ArrayList<BackgroundLocation>();
40
+
41
+ String[] columns = queryColumns();
42
+ String groupBy = null;
43
+ String having = null;
44
+ String orderBy = LocationEntry.COLUMN_NAME_TIME + " ASC";
45
+ Cursor cursor = null;
46
+
47
+ try {
48
+ cursor = db.query(
49
+ LocationEntry.TABLE_NAME, // The table to query
50
+ columns, // The columns to return
51
+ whereClause, // The columns for the WHERE clause
52
+ whereArgs, // The values for the WHERE clause
53
+ groupBy, // don't group the rows
54
+ having, // don't filter by row groups
55
+ orderBy // The sort order
56
+ );
57
+ while (cursor.moveToNext()) {
58
+ locations.add(hydrate(cursor));
59
+ }
60
+ } finally {
61
+ if (cursor != null) {
62
+ cursor.close();
63
+ }
64
+ }
65
+
66
+ return locations;
67
+ }
68
+ public Collection<BackgroundLocation> getAllLocations() {
69
+ return getLocations(null, null);
70
+ }
71
+
72
+ public Collection<BackgroundLocation> getValidLocations() {
73
+ String whereClause = LocationEntry.COLUMN_NAME_STATUS + " <> ?";
74
+ String[] whereArgs = { String.valueOf(BackgroundLocation.DELETED) };
75
+
76
+ return getLocations(whereClause, whereArgs);
77
+ }
78
+
79
+ public Collection<BackgroundLocation> getValidLocationsAndDelete() {
80
+ db.beginTransactionNonExclusive();
81
+ Collection<BackgroundLocation> locations = getValidLocations();
82
+ deleteAllLocations();
83
+ db.setTransactionSuccessful();
84
+ db.endTransaction();
85
+ return locations;
86
+ }
87
+
88
+ public BackgroundLocation getLocationById(long id) {
89
+ String[] columns = queryColumns();
90
+ String whereClause = LocationEntry._ID + " = ?";
91
+ String[] whereArgs = { String.valueOf(id) };
92
+
93
+ BackgroundLocation location = null;
94
+ Cursor cursor = null;
95
+ try {
96
+ cursor = db.query(
97
+ LocationEntry.TABLE_NAME, // The table to query
98
+ columns, // The columns to return
99
+ whereClause, // The columns for the WHERE clause
100
+ whereArgs, // The values for the WHERE clause
101
+ null, // don't group the rows
102
+ null, // don't filter by row groups
103
+ null // The sort order
104
+ );
105
+ while (cursor.moveToNext()) {
106
+ location = hydrate(cursor);
107
+ if (!cursor.isLast()) {
108
+ throw new RuntimeException("Location " + id + " is not unique");
109
+ }
110
+ }
111
+ } finally {
112
+ if (cursor != null) {
113
+ cursor.close();
114
+ }
115
+ }
116
+
117
+ return location;
118
+ }
119
+
120
+ public BackgroundLocation getFirstUnpostedLocation() {
121
+ SqlSelectStatement subsql = new SqlSelectStatement();
122
+ subsql.column(new SqlExpression(String.format("MIN(%s)", LocationEntry._ID)), LocationEntry._ID);
123
+ subsql.from(LocationEntry.TABLE_NAME);
124
+ subsql.where(LocationEntry.COLUMN_NAME_STATUS, SqlExpression.SqlOperatorEqualTo, BackgroundLocation.POST_PENDING);
125
+ subsql.orderBy(LocationEntry.COLUMN_NAME_TIME);
126
+
127
+ SqlSelectStatement sql = new SqlSelectStatement();
128
+ sql.columns(queryColumns());
129
+ sql.from(LocationEntry.TABLE_NAME);
130
+ sql.where(LocationEntry._ID, SqlExpression.SqlOperatorEqualTo, subsql);
131
+
132
+ BackgroundLocation location = null;
133
+ Cursor cursor = null;
134
+ try {
135
+ cursor = db.rawQuery(sql.statement(), new String[]{});
136
+ while (cursor.moveToNext()) {
137
+ location = hydrate(cursor);
138
+ if (!cursor.isLast()) {
139
+ throw new RuntimeException("Expected single location");
140
+ }
141
+ }
142
+ } finally {
143
+ if (cursor != null) {
144
+ cursor.close();
145
+ }
146
+ }
147
+
148
+ return location;
149
+ }
150
+
151
+ public BackgroundLocation getNextUnpostedLocation(long fromId) {
152
+ SqlSelectStatement subsql = new SqlSelectStatement();
153
+ subsql.column(new SqlExpression(String.format("MIN(%s)", LocationEntry._ID)), LocationEntry._ID);
154
+ subsql.from(LocationEntry.TABLE_NAME);
155
+ subsql.where(LocationEntry.COLUMN_NAME_STATUS, SqlExpression.SqlOperatorEqualTo, BackgroundLocation.POST_PENDING);
156
+ subsql.where(LocationEntry._ID, SqlExpression.SqlOperatorNotEqualTo, fromId);
157
+ subsql.orderBy(LocationEntry.COLUMN_NAME_TIME);
158
+
159
+ SqlSelectStatement sql = new SqlSelectStatement();
160
+ sql.columns(queryColumns());
161
+ sql.from(LocationEntry.TABLE_NAME);
162
+ sql.where(LocationEntry._ID, SqlExpression.SqlOperatorEqualTo, subsql);
163
+
164
+ BackgroundLocation location = null;
165
+ Cursor cursor = null;
166
+ try {
167
+ cursor = db.rawQuery(sql.statement(), new String[]{});
168
+ while (cursor.moveToNext()) {
169
+ location = hydrate(cursor);
170
+ if (!cursor.isLast()) {
171
+ throw new RuntimeException("Expected single location");
172
+ }
173
+ }
174
+ } finally {
175
+ if (cursor != null) {
176
+ cursor.close();
177
+ }
178
+ }
179
+
180
+ return location;
181
+ }
182
+
183
+ public long getUnpostedLocationsCount() {
184
+ String whereClause = SQLiteLocationContract.LocationEntry.COLUMN_NAME_STATUS + " = ?";
185
+ String[] whereArgs = { String.valueOf(BackgroundLocation.POST_PENDING) };
186
+
187
+ return DatabaseUtils.queryNumEntries(db, LocationEntry.TABLE_NAME, whereClause, whereArgs);
188
+ }
189
+
190
+ public long getLocationsForSyncCount(long millisSinceLastBatch) {
191
+ String whereClause = TextUtils.join("", new String[]{
192
+ SQLiteLocationContract.LocationEntry.COLUMN_NAME_STATUS + " = ? AND ( ",
193
+ SQLiteLocationContract.LocationEntry.COLUMN_NAME_BATCH_START_MILLIS + " IS NULL OR ",
194
+ SQLiteLocationContract.LocationEntry.COLUMN_NAME_BATCH_START_MILLIS + " < ? )",
195
+ });
196
+ String[] whereArgs = {
197
+ String.valueOf(BackgroundLocation.SYNC_PENDING),
198
+ String.valueOf(millisSinceLastBatch)
199
+ };
200
+
201
+ return DatabaseUtils.queryNumEntries(db, LocationEntry.TABLE_NAME, whereClause, whereArgs);
202
+ }
203
+
204
+ /**
205
+ * Persist location into database
206
+ *
207
+ * @param location
208
+ * @return rowId or -1 when error occured
209
+ */
210
+ public long persistLocation(BackgroundLocation location) {
211
+ ContentValues values = getContentValues(location);
212
+ long rowId = db.insertOrThrow(LocationEntry.TABLE_NAME, LocationEntry.COLUMN_NAME_NULLABLE, values);
213
+
214
+ return rowId;
215
+ }
216
+
217
+ /**
218
+ * Persist location into database with maximum row limit
219
+ *
220
+ * Method will ensure that there will be no more records than maxRows.
221
+ * Instead old records will be replaced with newer ones.
222
+ * If maxRows will change in time, method will delete excess records and vacuum table.
223
+ *
224
+ * @param location
225
+ * @param maxRows
226
+ * @return rowId or -1 when error occured
227
+ */
228
+ public long persistLocation(BackgroundLocation location, int maxRows) {
229
+ if (maxRows == 0) {
230
+ return -1;
231
+ }
232
+
233
+ String sql = null;
234
+ Boolean shouldVacuum = false;
235
+
236
+ long rowCount = DatabaseUtils.queryNumEntries(db, LocationEntry.TABLE_NAME);
237
+
238
+ if (rowCount < maxRows) {
239
+ ContentValues values = getContentValues(location);
240
+ return db.insertOrThrow(LocationEntry.TABLE_NAME, LocationEntry.COLUMN_NAME_NULLABLE, values);
241
+ }
242
+
243
+ db.beginTransactionNonExclusive();
244
+
245
+ if (rowCount > maxRows) {
246
+ sql = new StringBuilder("DELETE FROM ")
247
+ .append(LocationEntry.TABLE_NAME)
248
+ .append(" WHERE ").append(LocationEntry._ID)
249
+ .append(" IN (SELECT ").append(LocationEntry._ID)
250
+ .append(" FROM ").append(LocationEntry.TABLE_NAME)
251
+ .append(" ORDER BY ").append(LocationEntry.COLUMN_NAME_TIME)
252
+ .append(" LIMIT ?)")
253
+ .toString();
254
+ db.execSQL(sql, new Object[] {(rowCount - maxRows)});
255
+ shouldVacuum = true;
256
+ }
257
+
258
+ // get oldest location id to be overwritten
259
+ Cursor cursor = null;
260
+ long locationId;
261
+ try {
262
+ cursor = db.query(
263
+ LocationEntry.TABLE_NAME,
264
+ new String[] { "min(" + LocationEntry._ID + ")" },
265
+ TextUtils.join("", new String[]{
266
+ LocationEntry.COLUMN_NAME_TIME,
267
+ "= (SELECT min(",
268
+ LocationEntry.COLUMN_NAME_TIME,
269
+ ") FROM ",
270
+ LocationEntry.TABLE_NAME,
271
+ ")"
272
+ }),
273
+ null, null, null, null);
274
+ cursor.moveToFirst();
275
+ locationId = cursor.getLong(0);
276
+ } finally {
277
+ if (cursor != null) {
278
+ cursor.close();
279
+ }
280
+ }
281
+
282
+ sql = new StringBuilder("UPDATE ")
283
+ .append(LocationEntry.TABLE_NAME).append(" SET ")
284
+ .append(LocationEntry.COLUMN_NAME_PROVIDER).append("= ?,")
285
+ .append(LocationEntry.COLUMN_NAME_TIME).append("= ?,")
286
+ .append(LocationEntry.COLUMN_NAME_ACCURACY).append("= ?,")
287
+ .append(LocationEntry.COLUMN_NAME_VERTICAL_ACCURACY).append("= ?,")
288
+ .append(LocationEntry.COLUMN_NAME_SPEED).append("= ?,")
289
+ .append(LocationEntry.COLUMN_NAME_BEARING).append("= ?,")
290
+ .append(LocationEntry.COLUMN_NAME_ALTITUDE).append("= ?,")
291
+ .append(LocationEntry.COLUMN_NAME_RADIUS).append("= ?,")
292
+ .append(LocationEntry.COLUMN_NAME_LATITUDE).append("= ?,")
293
+ .append(LocationEntry.COLUMN_NAME_LONGITUDE).append("= ?,")
294
+ .append(LocationEntry.COLUMN_NAME_HAS_ACCURACY).append("= ?,")
295
+ .append(LocationEntry.COLUMN_NAME_HAS_VERTICAL_ACCURACY).append("= ?,")
296
+ .append(LocationEntry.COLUMN_NAME_HAS_SPEED).append("= ?,")
297
+ .append(LocationEntry.COLUMN_NAME_HAS_BEARING).append("= ?,")
298
+ .append(LocationEntry.COLUMN_NAME_HAS_ALTITUDE).append("= ?,")
299
+ .append(LocationEntry.COLUMN_NAME_HAS_RADIUS).append("= ?,")
300
+ .append(LocationEntry.COLUMN_NAME_LOCATION_PROVIDER).append("= ?,")
301
+ .append(LocationEntry.COLUMN_NAME_BATCH_START_MILLIS).append("= ?,")
302
+ .append(LocationEntry.COLUMN_NAME_STATUS).append("= ?,")
303
+ .append(LocationEntry.COLUMN_NAME_MOCK_FLAGS).append("= ?,")
304
+ .append(LocationEntry.COLUMN_NAME_EVENTS_JSON).append("= ?,")
305
+ .append(LocationEntry.COLUMN_NAME_BATTERY_LEVEL).append("= ?,")
306
+ .append(LocationEntry.COLUMN_NAME_IS_CHARGING).append("= ?")
307
+ .append(" WHERE ").append(LocationEntry._ID)
308
+ .append("= ?")
309
+ .toString();
310
+ db.execSQL(sql, new Object[] {
311
+ location.getProvider(),
312
+ location.getTime(),
313
+ location.getAccuracy(),
314
+ location.getVerticalAccuracy(),
315
+ location.getSpeed(),
316
+ location.getBearing(),
317
+ location.getAltitude(),
318
+ location.getRadius(),
319
+ location.getLatitude(),
320
+ location.getLongitude(),
321
+ location.hasAccuracy() ? 1 : 0,
322
+ location.hasVerticalAccuracy() ? 1 : 0,
323
+ location.hasSpeed() ? 1 : 0,
324
+ location.hasBearing() ? 1 : 0,
325
+ location.hasAltitude() ? 1 : 0,
326
+ location.hasRadius() ? 1 : 0,
327
+ location.getLocationProvider(),
328
+ location.getBatchStartMillis(),
329
+ location.getStatus(),
330
+ location.getMockFlags(),
331
+ location.hasDrivingEvents() ? location.getDrivingEvents().toString() : null,
332
+ location.getBatteryLevel(),
333
+ location.isCharging() != null ? (location.isCharging() ? 1 : 0) : null,
334
+ locationId
335
+ });
336
+
337
+ db.setTransactionSuccessful();
338
+ db.endTransaction();
339
+
340
+ if (shouldVacuum) { db.execSQL("VACUUM"); }
341
+
342
+ return locationId;
343
+ }
344
+
345
+ /**
346
+ * Delete location by given locationId
347
+ *
348
+ * Note: location is not actually deleted only flagged as non valid
349
+ * @param locationId
350
+ */
351
+ public void deleteLocationById(long locationId) {
352
+ if (locationId < 0) {
353
+ return;
354
+ }
355
+
356
+ ContentValues values = new ContentValues();
357
+ values.put(LocationEntry.COLUMN_NAME_STATUS, BackgroundLocation.DELETED);
358
+
359
+ String whereClause = LocationEntry._ID + " = ?";
360
+ String[] whereArgs = { String.valueOf(locationId) };
361
+
362
+ db.update(LocationEntry.TABLE_NAME, values, whereClause, whereArgs);
363
+ }
364
+
365
+ public BackgroundLocation deleteFirstUnpostedLocation() {
366
+ BackgroundLocation location = getFirstUnpostedLocation();
367
+ deleteLocationById(location.getLocationId());
368
+
369
+ return location;
370
+ }
371
+
372
+ public long persistLocationForSync(BackgroundLocation location, int maxRows) {
373
+ Long locationId = location.getLocationId();
374
+
375
+ if (locationId == null) {
376
+ location.setStatus(BackgroundLocation.SYNC_PENDING);
377
+ return persistLocation(location, maxRows);
378
+ } else {
379
+ ContentValues values = new ContentValues();
380
+ values.put(LocationEntry.COLUMN_NAME_STATUS, BackgroundLocation.SYNC_PENDING);
381
+
382
+ String whereClause = LocationEntry._ID + " = ?";
383
+ String[] whereArgs = { String.valueOf(locationId) };
384
+
385
+ db.update(LocationEntry.TABLE_NAME, values, whereClause, whereArgs);
386
+ return locationId;
387
+ }
388
+ }
389
+
390
+ public void updateLocationForSync(long locationId) {
391
+ ContentValues values = new ContentValues();
392
+ values.put(LocationEntry.COLUMN_NAME_STATUS, BackgroundLocation.SYNC_PENDING);
393
+
394
+ String whereClause = LocationEntry._ID + " = ?";
395
+ String[] whereArgs = { String.valueOf(locationId) };
396
+
397
+ db.update(LocationEntry.TABLE_NAME, values, whereClause, whereArgs);
398
+ }
399
+
400
+ /**
401
+ * Delete all locations
402
+ *
403
+ * Note: location are not actually deleted only flagged as non valid
404
+ */
405
+ public int deleteAllLocations() {
406
+ ContentValues values = new ContentValues();
407
+ values.put(LocationEntry.COLUMN_NAME_STATUS, BackgroundLocation.DELETED);
408
+
409
+ return db.update(LocationEntry.TABLE_NAME, values, null, null);
410
+ }
411
+
412
+ /**
413
+ * Delete all locations that are in post location queue
414
+ *
415
+ * Note: Instead of deleting, location status is changed so they can be still synced
416
+ */
417
+ public int deleteUnpostedLocations() {
418
+ ContentValues values = new ContentValues();
419
+ values.put(LocationEntry.COLUMN_NAME_STATUS, BackgroundLocation.SYNC_PENDING);
420
+
421
+ String whereClause = LocationEntry.COLUMN_NAME_STATUS + " = ?";
422
+ String[] whereArgs = { String.valueOf(BackgroundLocation.POST_PENDING) };
423
+
424
+ return db.update(LocationEntry.TABLE_NAME, values, whereClause, whereArgs);
425
+ }
426
+
427
+ /**
428
+ * Mark all locations pending sync (SYNC_PENDING) as deleted. Clears the sync queue without sending.
429
+ */
430
+ public int deletePendingSyncLocations() {
431
+ ContentValues values = new ContentValues();
432
+ values.put(LocationEntry.COLUMN_NAME_STATUS, BackgroundLocation.DELETED);
433
+
434
+ String whereClause = LocationEntry.COLUMN_NAME_STATUS + " = ?";
435
+ String[] whereArgs = { String.valueOf(BackgroundLocation.SYNC_PENDING) };
436
+
437
+ return db.update(LocationEntry.TABLE_NAME, values, whereClause, whereArgs);
438
+ }
439
+
440
+ private BackgroundLocation hydrate(Cursor c) {
441
+ BackgroundLocation l = new BackgroundLocation(c.getString(c.getColumnIndex(LocationEntry.COLUMN_NAME_PROVIDER)));
442
+ l.setTime(c.getLong(c.getColumnIndex(LocationEntry.COLUMN_NAME_TIME)));
443
+ if (c.getInt(c.getColumnIndex(LocationEntry.COLUMN_NAME_HAS_ACCURACY)) == 1) {
444
+ l.setAccuracy(c.getFloat(c.getColumnIndex(LocationEntry.COLUMN_NAME_ACCURACY)));
445
+ }
446
+ if (c.getInt(c.getColumnIndex(LocationEntry.COLUMN_NAME_HAS_VERTICAL_ACCURACY)) == 1) {
447
+ l.setVerticalAccuracy(c.getFloat(c.getColumnIndex(LocationEntry.COLUMN_NAME_VERTICAL_ACCURACY)));
448
+ }
449
+ if (c.getInt(c.getColumnIndex(LocationEntry.COLUMN_NAME_HAS_SPEED)) == 1) {
450
+ l.setSpeed(c.getFloat(c.getColumnIndex(LocationEntry.COLUMN_NAME_SPEED)));
451
+ }
452
+ if (c.getInt(c.getColumnIndex(LocationEntry.COLUMN_NAME_HAS_BEARING)) == 1) {
453
+ l.setBearing(c.getFloat(c.getColumnIndex(LocationEntry.COLUMN_NAME_BEARING)));
454
+ }
455
+ if (c.getInt(c.getColumnIndex(LocationEntry.COLUMN_NAME_HAS_ALTITUDE)) == 1) {
456
+ l.setAltitude(c.getDouble(c.getColumnIndex(LocationEntry.COLUMN_NAME_ALTITUDE)));
457
+ }
458
+ if (c.getInt(c.getColumnIndex(LocationEntry.COLUMN_NAME_HAS_RADIUS)) == 1) {
459
+ l.setRadius(c.getFloat(c.getColumnIndex(LocationEntry.COLUMN_NAME_RADIUS)));
460
+ }
461
+ l.setLatitude(c.getDouble(c.getColumnIndex(LocationEntry.COLUMN_NAME_LATITUDE)));
462
+ l.setLongitude(c.getDouble(c.getColumnIndex(LocationEntry.COLUMN_NAME_LONGITUDE)));
463
+ l.setLocationProvider(c.getInt(c.getColumnIndex(LocationEntry.COLUMN_NAME_LOCATION_PROVIDER)));
464
+ l.setBatchStartMillis(c.getLong(c.getColumnIndex(LocationEntry.COLUMN_NAME_BATCH_START_MILLIS)));
465
+ l.setStatus(c.getInt(c.getColumnIndex(LocationEntry.COLUMN_NAME_STATUS)));
466
+ l.setLocationId(c.getLong(c.getColumnIndex(LocationEntry._ID)));
467
+ l.setMockFlags(c.getInt((c.getColumnIndex(LocationEntry.COLUMN_NAME_MOCK_FLAGS))));
468
+ // v4.5: events / battery / charging
469
+ int idxEv = c.getColumnIndex(LocationEntry.COLUMN_NAME_EVENTS_JSON);
470
+ if (idxEv >= 0 && !c.isNull(idxEv)) {
471
+ String s = c.getString(idxEv);
472
+ if (s != null && !s.isEmpty()) {
473
+ try { l.setDrivingEvents(new org.json.JSONArray(s)); } catch (org.json.JSONException ignored) {}
474
+ }
475
+ }
476
+ int idxBat = c.getColumnIndex(LocationEntry.COLUMN_NAME_BATTERY_LEVEL);
477
+ if (idxBat >= 0 && !c.isNull(idxBat)) l.setBatteryLevel(c.getInt(idxBat));
478
+ int idxChg = c.getColumnIndex(LocationEntry.COLUMN_NAME_IS_CHARGING);
479
+ if (idxChg >= 0 && !c.isNull(idxChg)) l.setCharging(c.getInt(idxChg) == 1);
480
+
481
+ return l;
482
+ }
483
+
484
+ private ContentValues getContentValues(BackgroundLocation l) {
485
+ ContentValues values = new ContentValues();
486
+ values.put(LocationEntry.COLUMN_NAME_PROVIDER, l.getProvider());
487
+ values.put(LocationEntry.COLUMN_NAME_TIME, l.getTime());
488
+ values.put(LocationEntry.COLUMN_NAME_ACCURACY, l.getAccuracy());
489
+ values.put(LocationEntry.COLUMN_NAME_VERTICAL_ACCURACY, l.getVerticalAccuracy());
490
+ values.put(LocationEntry.COLUMN_NAME_SPEED, l.getSpeed());
491
+ values.put(LocationEntry.COLUMN_NAME_BEARING, l.getBearing());
492
+ values.put(LocationEntry.COLUMN_NAME_ALTITUDE, l.getAltitude());
493
+ values.put(LocationEntry.COLUMN_NAME_RADIUS, l.getRadius());
494
+ values.put(LocationEntry.COLUMN_NAME_LATITUDE, l.getLatitude());
495
+ values.put(LocationEntry.COLUMN_NAME_LONGITUDE, l.getLongitude());
496
+ values.put(LocationEntry.COLUMN_NAME_HAS_ACCURACY, l.hasAccuracy() ? 1 : 0);
497
+ values.put(LocationEntry.COLUMN_NAME_HAS_VERTICAL_ACCURACY, l.hasVerticalAccuracy() ? 1 : 0);
498
+ values.put(LocationEntry.COLUMN_NAME_HAS_SPEED, l.hasSpeed() ? 1 : 0);
499
+ values.put(LocationEntry.COLUMN_NAME_HAS_BEARING, l.hasBearing() ? 1 : 0);
500
+ values.put(LocationEntry.COLUMN_NAME_HAS_ALTITUDE, l.hasAltitude() ? 1 : 0);
501
+ values.put(LocationEntry.COLUMN_NAME_HAS_RADIUS, l.hasRadius() ? 1 : 0);
502
+ values.put(LocationEntry.COLUMN_NAME_LOCATION_PROVIDER, l.getLocationProvider());
503
+ values.put(LocationEntry.COLUMN_NAME_STATUS, l.getStatus());
504
+ values.put(LocationEntry.COLUMN_NAME_BATCH_START_MILLIS, l.getBatchStartMillis());
505
+ values.put(LocationEntry.COLUMN_NAME_MOCK_FLAGS, l.getMockFlags());
506
+ // v4.5.1: always write — NULL when absent — to clear stale values on maxRows recycle.
507
+ if (l.hasDrivingEvents()) {
508
+ values.put(LocationEntry.COLUMN_NAME_EVENTS_JSON, l.getDrivingEvents().toString());
509
+ } else {
510
+ values.putNull(LocationEntry.COLUMN_NAME_EVENTS_JSON);
511
+ }
512
+ if (l.getBatteryLevel() != null) values.put(LocationEntry.COLUMN_NAME_BATTERY_LEVEL, l.getBatteryLevel());
513
+ else values.putNull(LocationEntry.COLUMN_NAME_BATTERY_LEVEL);
514
+ if (l.isCharging() != null) values.put(LocationEntry.COLUMN_NAME_IS_CHARGING, l.isCharging() ? 1 : 0);
515
+ else values.putNull(LocationEntry.COLUMN_NAME_IS_CHARGING);
516
+
517
+ return values;
518
+ }
519
+
520
+ private String[] queryColumns() {
521
+ String[] columns = {
522
+ LocationEntry._ID,
523
+ LocationEntry.COLUMN_NAME_PROVIDER,
524
+ LocationEntry.COLUMN_NAME_TIME,
525
+ LocationEntry.COLUMN_NAME_ACCURACY,
526
+ LocationEntry.COLUMN_NAME_VERTICAL_ACCURACY,
527
+ LocationEntry.COLUMN_NAME_SPEED,
528
+ LocationEntry.COLUMN_NAME_BEARING,
529
+ LocationEntry.COLUMN_NAME_ALTITUDE,
530
+ LocationEntry.COLUMN_NAME_RADIUS,
531
+ LocationEntry.COLUMN_NAME_LATITUDE,
532
+ LocationEntry.COLUMN_NAME_LONGITUDE,
533
+ LocationEntry.COLUMN_NAME_HAS_ACCURACY,
534
+ LocationEntry.COLUMN_NAME_HAS_VERTICAL_ACCURACY,
535
+ LocationEntry.COLUMN_NAME_HAS_SPEED,
536
+ LocationEntry.COLUMN_NAME_HAS_BEARING,
537
+ LocationEntry.COLUMN_NAME_HAS_ALTITUDE,
538
+ LocationEntry.COLUMN_NAME_HAS_RADIUS,
539
+ LocationEntry.COLUMN_NAME_LOCATION_PROVIDER,
540
+ LocationEntry.COLUMN_NAME_STATUS,
541
+ LocationEntry.COLUMN_NAME_BATCH_START_MILLIS,
542
+ LocationEntry.COLUMN_NAME_MOCK_FLAGS,
543
+ LocationEntry.COLUMN_NAME_EVENTS_JSON,
544
+ LocationEntry.COLUMN_NAME_BATTERY_LEVEL,
545
+ LocationEntry.COLUMN_NAME_IS_CHARGING
546
+ };
547
+
548
+ return columns;
549
+ }
550
+ }