@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,311 @@
1
+ package com.marianhello.bgloc.sync;
2
+
3
+ import android.content.ContentProviderOperation;
4
+ import android.content.ContentResolver;
5
+ import android.content.ContentValues;
6
+ import android.content.Context;
7
+ import android.database.Cursor;
8
+ import android.database.sqlite.SQLiteDatabase;
9
+ import android.net.Uri;
10
+ import android.text.TextUtils;
11
+ import android.util.JsonWriter;
12
+
13
+ import com.marianhello.bgloc.ResourceResolver;
14
+ import com.marianhello.bgloc.data.AbstractLocationTemplate;
15
+ import com.marianhello.bgloc.data.ArrayListLocationTemplate;
16
+ import com.marianhello.bgloc.data.BackgroundLocation;
17
+ import com.marianhello.bgloc.data.HashMapLocationTemplate;
18
+ import com.marianhello.bgloc.data.LocationTemplate;
19
+ import com.marianhello.bgloc.data.LocationTemplateFactory;
20
+ import com.marianhello.bgloc.data.provider.LocationContentProvider;
21
+ import com.marianhello.bgloc.data.sqlite.SQLiteLocationContract;
22
+ import com.marianhello.bgloc.data.sqlite.SQLiteLocationContract.LocationEntry;
23
+ import com.marianhello.bgloc.data.sqlite.SQLiteOpenHelper;
24
+ import com.marianhello.logging.LoggerManager;
25
+
26
+ import org.json.JSONException;
27
+ import org.json.JSONObject;
28
+
29
+ import java.io.File;
30
+ import java.io.FileOutputStream;
31
+ import java.io.IOException;
32
+ import java.io.OutputStreamWriter;
33
+ import java.io.UnsupportedEncodingException;
34
+ import java.util.ArrayList;
35
+ import java.util.Iterator;
36
+ import java.util.List;
37
+ import java.util.Map;
38
+
39
+ /**
40
+ * Created by finch on 20/07/16.
41
+ */
42
+ public class BatchManager {
43
+ private Context context;
44
+ private org.slf4j.Logger logger;
45
+
46
+ public BatchManager(Context context) {
47
+ logger = LoggerManager.getLogger(BatchManager.class);
48
+ this.context = context;
49
+ }
50
+
51
+ private Uri getLocationContentUri() {
52
+ ResourceResolver resourceResolver = ResourceResolver.newInstance(context);
53
+ String authority = resourceResolver.getAuthority();
54
+ return LocationContentProvider.getContentUri(authority);
55
+ }
56
+
57
+ private File createBatchFromTemplate(Long batchStartMillis, Integer syncThreshold, LocationTemplate template) throws IOException {
58
+ logger.info("Creating batch {}", batchStartMillis);
59
+
60
+ ContentResolver resolver = context.getContentResolver();
61
+ Uri contentUri = getLocationContentUri();
62
+
63
+ String whereClause = TextUtils.join("", new String[]{
64
+ LocationEntry.COLUMN_NAME_STATUS + " = ? AND ( ",
65
+ LocationEntry.COLUMN_NAME_BATCH_START_MILLIS + " IS NULL OR ",
66
+ LocationEntry.COLUMN_NAME_BATCH_START_MILLIS + " < ? )",
67
+ });
68
+ String[] whereArgs = {
69
+ String.valueOf(BackgroundLocation.SYNC_PENDING),
70
+ String.valueOf(batchStartMillis)
71
+ };
72
+
73
+ Cursor cursor = null;
74
+ LocationWriter writer = null;
75
+ FileOutputStream fs = null;
76
+ File file = null;
77
+ boolean batchReturned = false;
78
+
79
+ try {
80
+ cursor = resolver.query(
81
+ contentUri,
82
+ null,
83
+ whereClause,
84
+ whereArgs,
85
+ LocationEntry.COLUMN_NAME_TIME + " ASC"
86
+
87
+ );
88
+
89
+ if (cursor == null) {
90
+ logger.warn("ContentResolver.query returned null, cannot create batch");
91
+ return null;
92
+ }
93
+
94
+ int threshold = (syncThreshold != null && syncThreshold >= 0) ? syncThreshold : 1;
95
+ if (cursor.getCount() < threshold) {
96
+ return null;
97
+ }
98
+ // Never create or send an empty batch (e.g. forceSync with 0 pending locations)
99
+ if (cursor.getCount() == 0) {
100
+ logger.info("No pending locations to sync, skipping batch creation");
101
+ return null;
102
+ }
103
+
104
+ file = File.createTempFile("locations", ".json");
105
+ fs = new FileOutputStream(file);
106
+ writer = new LocationWriter(fs, template);
107
+
108
+ writer.beginArray();
109
+ while (cursor.moveToNext()) {
110
+ BackgroundLocation location = BackgroundLocation.fromCursor(cursor);
111
+ writer.write(location);
112
+ }
113
+
114
+ writer.endArray();
115
+ writer.close();
116
+ writer = null;
117
+ fs.close();
118
+ fs = null;
119
+
120
+ // set batchStartMillis for all synced locations
121
+ ContentValues values = new ContentValues();
122
+ values.put(LocationEntry.COLUMN_NAME_BATCH_START_MILLIS, batchStartMillis);
123
+ resolver.update(contentUri, values, whereClause, whereArgs);
124
+
125
+ logger.info("Batch file: {} created successfully", file.getName());
126
+
127
+ batchReturned = true;
128
+ return file;
129
+ } finally {
130
+ if (cursor != null) {
131
+ cursor.close();
132
+ }
133
+ if (writer != null) {
134
+ try {
135
+ writer.close();
136
+ } catch (IOException e) {
137
+ logger.debug("Error closing LocationWriter: {}", e.getMessage());
138
+ }
139
+ }
140
+ if (fs != null) {
141
+ try {
142
+ fs.close();
143
+ } catch (IOException e) {
144
+ logger.debug("Error closing FileOutputStream: {}", e.getMessage());
145
+ }
146
+ }
147
+ // if we threw before returning the file, delete temp file to avoid leaving garbage
148
+ if (!batchReturned && file != null && file.exists() && !file.delete()) {
149
+ logger.warn("Could not delete temp batch file: {}", file.getAbsolutePath());
150
+ }
151
+ }
152
+ }
153
+
154
+ public File createBatch(Long batchStartMillis, Integer syncThreshold, LocationTemplate template) throws IOException {
155
+ LocationTemplate tpl;
156
+ if (template != null) {
157
+ tpl = template;
158
+ } else {
159
+ tpl = LocationTemplateFactory.getDefault();
160
+ }
161
+ return createBatchFromTemplate(batchStartMillis, syncThreshold, tpl);
162
+ }
163
+
164
+ public File createBatch(Long batchStartMillis, Integer syncThreshold) throws IOException {
165
+ return createBatch(batchStartMillis, syncThreshold, null);
166
+ }
167
+
168
+
169
+ public void setBatchCompleted(Long batchId) {
170
+ ContentResolver resolver = context.getApplicationContext().getContentResolver();
171
+ Uri contentUri = getLocationContentUri();
172
+
173
+ String whereClause = LocationEntry.COLUMN_NAME_BATCH_START_MILLIS + " = ?";
174
+ String[] whereArgs = { String.valueOf(batchId) };
175
+
176
+ ContentValues values = new ContentValues();
177
+ values.put(LocationEntry.COLUMN_NAME_STATUS, BackgroundLocation.DELETED);
178
+ resolver.update(contentUri, values, whereClause, whereArgs);
179
+ }
180
+
181
+ private static class LocationTemplateWriter {
182
+ private BackgroundLocation location;
183
+ private JsonWriter writer;
184
+
185
+ public LocationTemplateWriter(JsonWriter writer, BackgroundLocation location) {
186
+ this.writer = writer;
187
+ this.location = location;
188
+ }
189
+
190
+ private void writeValue(Object value) throws IOException {
191
+ if (value == null || value == JSONObject.NULL) {
192
+ writer.nullValue();
193
+ } else if (value instanceof String ) {
194
+ writer.value((String) value);
195
+ } else if (value instanceof Map) {
196
+ writeMap((Map) value);
197
+ } else if (value instanceof List) {
198
+ writeList((List) value);
199
+ // v4.5.1 — handle JSONArray / JSONObject so that placeholders that resolve to
200
+ // structured data (@events → JSONArray of events) are written as real JSON arrays /
201
+ // objects, not as escaped strings. Without this, a fix coming out of the sync queue
202
+ // serialised "events" as "[{\"type\":\"hardBrake\"}]" literal.
203
+ } else if (value instanceof org.json.JSONArray) {
204
+ writeJsonArray((org.json.JSONArray) value);
205
+ } else if (value instanceof org.json.JSONObject) {
206
+ writeJsonObject((org.json.JSONObject) value);
207
+ } else if (Integer.class.isInstance(value)) {
208
+ writer.value((Integer) value);
209
+ } else if (Double.class.isInstance(value)) {
210
+ writer.value((Double) value);
211
+ } else if (Float.class.isInstance(value)) {
212
+ writer.value((Float) value);
213
+ } else if (Long.class.isInstance(value)) {
214
+ writer.value((Long) value);
215
+ } else if (Boolean.class.isInstance(value)) {
216
+ writer.value((Boolean) value);
217
+ } else {
218
+ writer.value(String.valueOf(value));
219
+ }
220
+ }
221
+
222
+ private void writeJsonArray(org.json.JSONArray arr) throws IOException {
223
+ writer.beginArray();
224
+ for (int i = 0; i < arr.length(); i++) {
225
+ Object v = arr.opt(i);
226
+ writeValue(v == null ? JSONObject.NULL : v);
227
+ }
228
+ writer.endArray();
229
+ }
230
+
231
+ private void writeJsonObject(org.json.JSONObject obj) throws IOException {
232
+ writer.beginObject();
233
+ Iterator<String> keys = obj.keys();
234
+ while (keys.hasNext()) {
235
+ String k = keys.next();
236
+ writer.name(k);
237
+ writeValue(obj.opt(k));
238
+ }
239
+ writer.endObject();
240
+ }
241
+
242
+ /** v4.5.1 — resolve a template string. If it is a placeholder ("@foo") and the location
243
+ * has no value, return JSONObject.NULL so the writer emits `null` instead of the literal
244
+ * "@foo" string. */
245
+ private Object resolveTemplateValue(Object value) {
246
+ if (value instanceof String) {
247
+ String s = (String) value;
248
+ Object resolved = location.getValueForKey(s);
249
+ if (resolved != null) return resolved;
250
+ if (s.startsWith("@")) return JSONObject.NULL;
251
+ }
252
+ return value;
253
+ }
254
+
255
+ public void writeMap(Map values) throws IOException {
256
+ writer.beginObject();
257
+ Iterator<?> it = values.entrySet().iterator();
258
+ while (it.hasNext()) {
259
+ Map.Entry<String, Object> pair = (Map.Entry) it.next();
260
+ String key = pair.getKey();
261
+ Object value = pair.getValue();
262
+ writer.name(key);
263
+ writeValue(resolveTemplateValue(value));
264
+ }
265
+ writer.endObject();
266
+ }
267
+
268
+ public void writeList(List values) throws IOException {
269
+ writer.beginArray();
270
+ Iterator<?> it = values.iterator();
271
+ while (it.hasNext()) {
272
+ Object value = it.next();
273
+ writeValue(resolveTemplateValue(value));
274
+ }
275
+ writer.endArray();
276
+ }
277
+ }
278
+
279
+ private static class LocationWriter {
280
+ private JsonWriter writer = null;
281
+ private LocationTemplate template;
282
+
283
+ public LocationWriter(FileOutputStream fos, LocationTemplate template) throws IOException {
284
+ writer = new JsonWriter(new OutputStreamWriter(fos, "UTF-8"));
285
+ this.template = template;
286
+ }
287
+
288
+ public void beginArray() throws IOException {
289
+ writer.beginArray();
290
+ }
291
+
292
+ public void endArray() throws IOException {
293
+ writer.endArray();
294
+ }
295
+
296
+ public void close() throws IOException {
297
+ writer.close();
298
+ }
299
+
300
+ public void write(BackgroundLocation location) throws IOException {
301
+ LocationTemplateWriter writer = new LocationTemplateWriter(this.writer, location);
302
+ if (template instanceof HashMapLocationTemplate) {
303
+ HashMapLocationTemplate hashTemplate = (HashMapLocationTemplate) template;
304
+ writer.writeMap(hashTemplate.toMap());
305
+ } else if (template instanceof ArrayListLocationTemplate) {
306
+ ArrayListLocationTemplate listTemplate = (ArrayListLocationTemplate) template;
307
+ writer.writeList(listTemplate.toList());
308
+ }
309
+ }
310
+ }
311
+ }
@@ -0,0 +1,148 @@
1
+ package com.marianhello.bgloc.sync;
2
+
3
+ import android.app.Notification;
4
+ import android.app.NotificationChannel;
5
+ import android.app.NotificationManager;
6
+ import android.app.PendingIntent;
7
+ import android.content.Context;
8
+ import android.content.Intent;
9
+ import android.graphics.BitmapFactory;
10
+ import android.graphics.Color;
11
+ import android.os.Build;
12
+ import androidx.annotation.RequiresApi;
13
+ import androidx.core.app.NotificationCompat;
14
+
15
+ import com.marianhello.bgloc.ResourceResolver;
16
+ import com.marianhello.logging.LoggerManager;
17
+
18
+ public class NotificationHelper {
19
+ public static final String SERVICE_CHANNEL_ID = "bglocservice";
20
+ // https://github.com/nishkarsh/android-permissions/blob/master/src/main/java/com/intentfilter/androidpermissions/services/NotificationService.java#L15
21
+ public static final String ANDROID_PERMISSIONS_CHANNEL_ID = "android-permissions";
22
+
23
+ public static final String SYNC_CHANNEL_ID = "syncservice";
24
+ public static final String SYNC_CHANNEL_NAME = "Sync Service";
25
+ public static final String SYNC_CHANNEL_DESCRIPTION = "Shows sync progress";
26
+
27
+ public static class NotificationFactory {
28
+ private Context mContext;
29
+ private ResourceResolver mResolver;
30
+
31
+ private org.slf4j.Logger logger;
32
+
33
+ public NotificationFactory(Context context) {
34
+ mContext = context;
35
+ mResolver = ResourceResolver.newInstance(context);
36
+ logger = LoggerManager.getLogger(NotificationFactory.class);
37
+ }
38
+
39
+ private Integer parseNotificationIconColor(String color) {
40
+ int iconColor = 0;
41
+ if (color != null) {
42
+ try {
43
+ iconColor = Color.parseColor(color);
44
+ } catch (IllegalArgumentException e) {
45
+ logger.error("Couldn't parse color from android options");
46
+ }
47
+ }
48
+ return iconColor;
49
+ }
50
+
51
+ public Notification getNotification(String title, String text, String largeIcon, String smallIcon, String color) {
52
+ Context appContext = mContext.getApplicationContext();
53
+
54
+ // Build a Notification required for running service in foreground.
55
+ NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext, NotificationHelper.SERVICE_CHANNEL_ID);
56
+
57
+ builder.setContentTitle(title);
58
+ builder.setContentText(text);
59
+ builder.setOngoing(true);
60
+ if (smallIcon != null && !smallIcon.isEmpty()) {
61
+ builder.setSmallIcon(mResolver.getDrawable(smallIcon));
62
+ } else {
63
+ builder.setSmallIcon(android.R.drawable.ic_menu_mylocation);
64
+ }
65
+ if (largeIcon != null && !largeIcon.isEmpty()) {
66
+ int largeIconId = mResolver.getDrawable(largeIcon);
67
+ if (largeIconId == 0) {
68
+ logger.warn("The resource " + largeIcon + " was not found in the drawable folder. Please include it when building the app.");
69
+ }
70
+ builder.setLargeIcon(BitmapFactory.decodeResource(appContext.getResources(), largeIconId));
71
+ }
72
+ if (color != null && !color.isEmpty()) {
73
+ builder.setColor(this.parseNotificationIconColor(color));
74
+ }
75
+
76
+ // Add an onclick handler to the notification
77
+ String packageName = appContext.getPackageName();
78
+ Intent launchIntent = appContext.getPackageManager().getLaunchIntentForPackage(packageName);
79
+ if (launchIntent != null) {
80
+ // NOTICE: testing apps might not have registered launch intent
81
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
82
+ int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
83
+ ? PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE
84
+ : PendingIntent.FLAG_CANCEL_CURRENT;
85
+ PendingIntent contentIntent = PendingIntent.getActivity(appContext, 0, launchIntent, flags);
86
+ builder.setContentIntent(contentIntent);
87
+ }
88
+
89
+ Notification notification = builder.build();
90
+ notification.flags |= Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE | Notification.FLAG_NO_CLEAR;
91
+
92
+ return notification;
93
+ }
94
+ }
95
+
96
+ public static void registerAllChannels(Context context) {
97
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
98
+ String appName = ResourceResolver.newInstance(context).getString(("app_name"));
99
+ // Create the NotificationChannel, but only on API 26+ because
100
+ // the NotificationChannel class is new and not in the support library
101
+ android.app.NotificationManager notificationManager = (android.app.NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
102
+ notificationManager.createNotificationChannel(createServiceChannel(appName));
103
+ notificationManager.createNotificationChannel(createSyncChannel());
104
+ notificationManager.createNotificationChannel(createAndroidPermissionsChannel(appName));
105
+ }
106
+ }
107
+
108
+ public static void registerServiceChannel(Context context) {
109
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
110
+ String appName = ResourceResolver.newInstance(context).getString(("app_name"));
111
+ // Create the NotificationChannel, but only on API 26+ because
112
+ // the NotificationChannel class is new and not in the support library
113
+ android.app.NotificationManager notificationManager = (android.app.NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
114
+ notificationManager.createNotificationChannel(createServiceChannel(appName));
115
+ }
116
+ }
117
+
118
+ public static void registerSyncChannel(Context context) {
119
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
120
+ // Create the NotificationChannel, but only on API 26+ because
121
+ // the NotificationChannel class is new and not in the support library
122
+ android.app.NotificationManager notificationManager = (android.app.NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
123
+ notificationManager.createNotificationChannel(createSyncChannel());
124
+ }
125
+ }
126
+
127
+ @RequiresApi(api = Build.VERSION_CODES.O)
128
+ public static NotificationChannel createServiceChannel(CharSequence name) {
129
+ NotificationChannel channel = new NotificationChannel(SERVICE_CHANNEL_ID, name, android.app.NotificationManager.IMPORTANCE_LOW);
130
+ channel.enableVibration(false);
131
+ return channel;
132
+ }
133
+
134
+ @RequiresApi(api = Build.VERSION_CODES.O)
135
+ public static NotificationChannel createSyncChannel(){
136
+ NotificationChannel channel = new NotificationChannel(SYNC_CHANNEL_ID, SYNC_CHANNEL_NAME, NotificationManager.IMPORTANCE_LOW);
137
+ channel.setDescription(SYNC_CHANNEL_DESCRIPTION);
138
+ channel.enableVibration(false);
139
+ return channel;
140
+ }
141
+
142
+ @RequiresApi(api = Build.VERSION_CODES.O)
143
+ public static NotificationChannel createAndroidPermissionsChannel(CharSequence name ){
144
+ NotificationChannel channel = new NotificationChannel(ANDROID_PERMISSIONS_CHANNEL_ID, name, NotificationManager.IMPORTANCE_HIGH);
145
+ channel.enableVibration(false);
146
+ return channel;
147
+ }
148
+ }