@josuelmm/cordova-background-geolocation 4.2.3 → 4.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.npmignore +11 -0
- package/CHANGELOG.md +261 -0
- package/README.md +306 -115
- package/android/CDVBackgroundGeolocation/src/main/java/com/marianhello/bgloc/cordova/ConfigMapper.java +34 -0
- package/android/CDVBackgroundGeolocation/src/main/java/com/tenforwardconsulting/bgloc/cordova/BackgroundGeolocationPlugin.java +61 -1
- package/android/common/src/main/AndroidManifest.xml +1 -1
- package/android/common/src/main/java/com/marianhello/bgloc/BootCompletedReceiver.java +20 -3
- package/android/common/src/main/java/com/marianhello/bgloc/Config.java +87 -1
- package/android/common/src/main/java/com/marianhello/bgloc/data/BackgroundLocation.java +94 -0
- package/android/common/src/main/java/com/marianhello/bgloc/data/ConfigJsonMapper.java +211 -0
- package/android/common/src/main/java/com/marianhello/bgloc/data/LocationTemplateFactory.java +6 -0
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteConfigurationContract.java +5 -1
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteConfigurationDAO.java +32 -1
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteLocationContract.java +12 -2
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteLocationDAO.java +33 -2
- package/android/common/src/main/java/com/marianhello/bgloc/data/sqlite/SQLiteOpenHelper.java +15 -1
- package/android/common/src/main/java/com/marianhello/bgloc/provider/AbstractLocationProvider.java +48 -1
- package/android/common/src/main/java/com/marianhello/bgloc/provider/ActivityRecognitionLocationProvider.java +105 -6
- package/android/common/src/main/java/com/marianhello/bgloc/provider/DistanceFilterLocationProvider.java +336 -250
- package/android/common/src/main/java/com/marianhello/bgloc/provider/RawLocationProvider.java +69 -19
- package/android/common/src/main/java/com/marianhello/bgloc/service/LocationServiceImpl.java +246 -21
- package/android/common/src/main/java/com/marianhello/bgloc/service/LocationServiceProxy.java +5 -2
- package/android/common/src/main/java/com/marianhello/bgloc/sync/BatchManager.java +46 -13
- package/ios/CDVBackgroundGeolocation/CDVBackgroundGeolocation.m +23 -1
- package/ios/common/BackgroundGeolocation/MAURActivityLocationProvider.m +208 -70
- package/ios/common/BackgroundGeolocation/MAURBackgroundGeolocationFacade.m +132 -5
- package/ios/common/BackgroundGeolocation/MAURBackgroundSync.m +20 -0
- package/ios/common/BackgroundGeolocation/MAURConfig.h +7 -0
- package/ios/common/BackgroundGeolocation/MAURConfig.m +37 -2
- package/ios/common/BackgroundGeolocation/MAURConfigurationContract.h +3 -0
- package/ios/common/BackgroundGeolocation/MAURConfigurationContract.m +3 -1
- package/ios/common/BackgroundGeolocation/MAURDistanceFilterLocationProvider.m +10 -1
- package/ios/common/BackgroundGeolocation/MAURGeolocationOpenHelper.m +15 -1
- package/ios/common/BackgroundGeolocation/MAURLocation.h +12 -0
- package/ios/common/BackgroundGeolocation/MAURLocation.m +33 -4
- package/ios/common/BackgroundGeolocation/MAURLocationContract.h +4 -0
- package/ios/common/BackgroundGeolocation/MAURLocationContract.m +5 -1
- package/ios/common/BackgroundGeolocation/MAURLocationManager.m +19 -1
- package/ios/common/BackgroundGeolocation/MAURPostLocationTask.h +9 -0
- package/ios/common/BackgroundGeolocation/MAURPostLocationTask.m +59 -1
- package/ios/common/BackgroundGeolocation/MAURRawLocationProvider.m +10 -1
- package/ios/common/BackgroundGeolocation/MAURSQLiteConfigurationDAO.m +54 -4
- package/ios/common/BackgroundGeolocation/MAURSQLiteLocationDAO.h +12 -0
- package/ios/common/BackgroundGeolocation/MAURSQLiteLocationDAO.m +125 -5
- package/package.json +31 -1
- package/plugin.xml +3 -10
- package/www/BackgroundGeolocation.d.ts +143 -3
- package/www/BackgroundGeolocation.js +11 -4
- package/CLAUDE.md +0 -56
- package/HISTORY.md +0 -871
- package/android/CDVBackgroundGeolocation/src/test/java/com/marianhello/ConfigMapperTest.java +0 -220
- package/android/common/src/androidTest/java/com/marianhello/bgloc/BackgroundGeolocationFacadeTest.java +0 -45
- package/android/common/src/androidTest/java/com/marianhello/bgloc/BatchManagerTest.java +0 -570
- package/android/common/src/androidTest/java/com/marianhello/bgloc/ConfigTest.java +0 -76
- package/android/common/src/androidTest/java/com/marianhello/bgloc/ContentProviderLocationDAOTest.java +0 -437
- package/android/common/src/androidTest/java/com/marianhello/bgloc/DBLogReaderTest.java +0 -95
- package/android/common/src/androidTest/java/com/marianhello/bgloc/LocationContentProviderTest.java +0 -159
- package/android/common/src/androidTest/java/com/marianhello/bgloc/LocationServiceProxyTest.java +0 -161
- package/android/common/src/androidTest/java/com/marianhello/bgloc/LocationServiceTest.java +0 -247
- package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteConfigurationDAOTest.java +0 -200
- package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteLocationDAOTest.java +0 -457
- package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteLocationDAOThreadTest.java +0 -96
- package/android/common/src/androidTest/java/com/marianhello/bgloc/SQLiteOpenHelperTest.java +0 -225
- package/android/common/src/androidTest/java/com/marianhello/bgloc/TestPluginDelegate.java +0 -46
- package/android/common/src/androidTest/java/com/marianhello/bgloc/TestResourceResolver.java +0 -14
- package/android/common/src/androidTest/java/com/marianhello/bgloc/provider/MockLocationProvider.java +0 -50
- package/android/common/src/androidTest/java/com/marianhello/bgloc/provider/TestLocationProviderFactory.java +0 -17
- package/android/common/src/androidTest/java/com/marianhello/bgloc/sqlite/SQLiteOpenHelper10.java +0 -92
- package/android/common/src/androidTest/java/com/marianhello/bgloc/test/LocationProviderTestCase.java +0 -107
- package/android/common/src/androidTest/java/com/marianhello/bgloc/test/TestConstants.java +0 -5
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/ArrayListLocationTemplateTest.java +0 -82
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/BackgroundLocationTest.java +0 -128
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/ConfigTest.java +0 -191
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/DBLogReaderTest.java +0 -37
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/HashMapLocationTemplateTest.java +0 -216
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/HttpPostServiceTest.java +0 -223
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/LocationTemplateFactoryTest.java +0 -50
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/PostLocationTaskTest.java +0 -180
- package/android/common/src/test/java/com/marianhello/backgroundgeolocation/TestHelper.java +0 -16
- package/ios/common/BackgroundGeolocation/SOMotionDetector/CHANGELOG.md +0 -2
- package/ios/common/BackgroundGeolocation/SOMotionDetector/LICENSE +0 -21
- package/ios/common/BackgroundGeolocation/SOMotionDetector/README.md +0 -135
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOLocationManager.h +0 -80
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOLocationManager.m +0 -147
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionActivity.h +0 -30
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionActivity.m +0 -42
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionDetector.h +0 -99
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOMotionDetector.m +0 -327
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOStepDetector.h +0 -44
- package/ios/common/BackgroundGeolocation/SOMotionDetector/SOStepDetector.m +0 -94
- package/ios/common/BackgroundGeolocationTests/Info.plist +0 -24
- package/ios/common/BackgroundGeolocationTests/MAURBackgroundLocationTest.m +0 -185
- package/ios/common/BackgroundGeolocationTests/MAURConfigTest.m +0 -161
- package/ios/common/BackgroundGeolocationTests/MAURGeolocationOpenHelperTest.m +0 -102
- package/ios/common/BackgroundGeolocationTests/MAURLocationTest.m +0 -216
- package/ios/common/BackgroundGeolocationTests/MAURLocationUploaderTest.m +0 -55
- package/ios/common/BackgroundGeolocationTests/MAURLogReaderTest.m +0 -43
- package/ios/common/BackgroundGeolocationTests/MAURSQLiteConfigurationDAOTest.m +0 -102
- package/ios/common/BackgroundGeolocationTests/MAURSQLiteHelperTest.m +0 -41
- package/ios/common/BackgroundGeolocationTests/MAURSQLiteLocationDAOTests.m +0 -240
- package/ios/common/BackgroundGeolocationTests/MAURSQLiteLocationDAOThreadTest.m +0 -84
- package/ios/common/BackgroundGeolocationTests/MAURSQLiteOpenHelperTest.m +0 -144
- package/ios/common/scripts/xcode-refactor.js +0 -184
|
@@ -11,9 +11,18 @@ import android.location.LocationListener;
|
|
|
11
11
|
import android.location.LocationManager;
|
|
12
12
|
import android.os.Build;
|
|
13
13
|
import android.os.Bundle;
|
|
14
|
+
import android.os.Looper;
|
|
15
|
+
|
|
16
|
+
import com.google.android.gms.common.ConnectionResult;
|
|
17
|
+
import com.google.android.gms.common.GoogleApiAvailability;
|
|
18
|
+
import com.google.android.gms.location.FusedLocationProviderClient;
|
|
19
|
+
import com.google.android.gms.location.LocationCallback;
|
|
20
|
+
import com.google.android.gms.location.LocationRequest;
|
|
21
|
+
import com.google.android.gms.location.LocationResult;
|
|
22
|
+
import com.google.android.gms.location.LocationServices;
|
|
23
|
+
import com.google.android.gms.location.Priority;
|
|
14
24
|
|
|
15
25
|
import com.marianhello.bgloc.Config;
|
|
16
|
-
import com.marianhello.bgloc.provider.AbstractLocationProvider;
|
|
17
26
|
import com.marianhello.utils.ToneGenerator.Tone;
|
|
18
27
|
|
|
19
28
|
import java.util.List;
|
|
@@ -23,22 +32,38 @@ import static java.lang.Math.pow;
|
|
|
23
32
|
import static java.lang.Math.round;
|
|
24
33
|
|
|
25
34
|
|
|
35
|
+
/**
|
|
36
|
+
* v4.5.2 — Distance-filter provider with a runtime-chosen backend:
|
|
37
|
+
* <ul>
|
|
38
|
+
* <li><b>Fused path</b> (Play Services available): {@link FusedLocationProviderClient}
|
|
39
|
+
* + {@link LocationCallback}. Better fused GPS+Network blending and battery.</li>
|
|
40
|
+
* <li><b>Legacy path</b> (Play Services missing — Huawei/HMS, AOSP, China ROMs):
|
|
41
|
+
* {@link android.location.LocationManager} + {@link LocationListener}. Preserves the
|
|
42
|
+
* original DISTANCE_FILTER behavior so the plugin works on every Android device.</li>
|
|
43
|
+
* </ul>
|
|
44
|
+
*
|
|
45
|
+
* Stationary detection in both paths relies on the existing alarm-driven polling
|
|
46
|
+
* (no geofencing / proximity alerts), per product decision.
|
|
47
|
+
*/
|
|
26
48
|
public class DistanceFilterLocationProvider extends AbstractLocationProvider implements LocationListener {
|
|
27
49
|
|
|
28
50
|
private static final String TAG = DistanceFilterLocationProvider.class.getSimpleName();
|
|
29
51
|
private static final String P_NAME = "com.marianhello.bgloc";
|
|
30
52
|
|
|
31
|
-
private static final String
|
|
32
|
-
private static final String
|
|
33
|
-
private static final String
|
|
34
|
-
private static final String STATIONARY_LOCATION_MONITOR_ACTION = P_NAME + ".STATIONARY_LOCATION_MONITOR_ACTION";
|
|
53
|
+
private static final String STATIONARY_ALARM_ACTION = P_NAME + ".STATIONARY_ALARM_ACTION";
|
|
54
|
+
private static final String SINGLE_LOCATION_UPDATE_ACTION = P_NAME + ".SINGLE_LOCATION_UPDATE_ACTION";
|
|
55
|
+
private static final String STATIONARY_LOCATION_MONITOR_ACTION = P_NAME + ".STATIONARY_LOCATION_MONITOR_ACTION";
|
|
35
56
|
|
|
36
|
-
|
|
37
|
-
private static final long
|
|
38
|
-
private static final long
|
|
57
|
+
// v4.5.1: defaults — overridable per-config via config.stationaryTimeout / stationaryPollInterval / stationaryPollFast
|
|
58
|
+
private static final long DEFAULT_STATIONARY_TIMEOUT = 5 * 1000 * 60;
|
|
59
|
+
private static final long DEFAULT_STATIONARY_LOCATION_POLLING_INTERVAL_LAZY = 3 * 1000 * 60;
|
|
60
|
+
private static final long DEFAULT_STATIONARY_LOCATION_POLLING_INTERVAL_AGGRESSIVE = 1 * 1000 * 60;
|
|
39
61
|
private static final int MAX_STATIONARY_ACQUISITION_ATTEMPTS = 5;
|
|
40
62
|
private static final int MAX_SPEED_ACQUISITION_ATTEMPTS = 3;
|
|
41
63
|
|
|
64
|
+
// v4.5.2 — Aggressive interval used while acquiring stationary location or speed (FLP path).
|
|
65
|
+
private static final long ACQUISITION_INTERVAL_MS = 1000L;
|
|
66
|
+
|
|
42
67
|
private Boolean isMoving = false;
|
|
43
68
|
private Boolean isAcquiringStationaryLocation = false;
|
|
44
69
|
private Boolean isAcquiringSpeed = false;
|
|
@@ -49,21 +74,69 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
49
74
|
private float stationaryRadius;
|
|
50
75
|
private PendingIntent stationaryAlarmPI;
|
|
51
76
|
private PendingIntent stationaryLocationPollingPI;
|
|
77
|
+
private PendingIntent singleUpdatePI; // legacy path only
|
|
52
78
|
private long stationaryLocationPollingInterval;
|
|
53
|
-
|
|
54
|
-
private PendingIntent singleUpdatePI;
|
|
79
|
+
|
|
55
80
|
private Integer scaledDistanceFilter;
|
|
56
81
|
|
|
57
|
-
private
|
|
82
|
+
private FusedLocationProviderClient fusedClient; // null on the legacy path
|
|
83
|
+
private LocationManager locationManager; // always non-null after onCreate
|
|
58
84
|
private AlarmManager alarmManager;
|
|
85
|
+
private boolean usingFused = false;
|
|
59
86
|
|
|
60
87
|
private boolean isStarted = false;
|
|
61
88
|
|
|
89
|
+
/** v4.5.1: read overrides from {@link com.marianhello.bgloc.Config}; fall back to defaults. */
|
|
90
|
+
private long getStationaryTimeout() {
|
|
91
|
+
Integer v = mConfig != null ? mConfig.getStationaryTimeout() : null;
|
|
92
|
+
return v != null ? v.longValue() : DEFAULT_STATIONARY_TIMEOUT;
|
|
93
|
+
}
|
|
94
|
+
private long getStationaryPollLazy() {
|
|
95
|
+
Integer v = mConfig != null ? mConfig.getStationaryPollInterval() : null;
|
|
96
|
+
return v != null ? v.longValue() : DEFAULT_STATIONARY_LOCATION_POLLING_INTERVAL_LAZY;
|
|
97
|
+
}
|
|
98
|
+
private long getStationaryPollFast() {
|
|
99
|
+
Integer v = mConfig != null ? mConfig.getStationaryPollFast() : null;
|
|
100
|
+
return v != null ? v.longValue() : DEFAULT_STATIONARY_LOCATION_POLLING_INTERVAL_AGGRESSIVE;
|
|
101
|
+
}
|
|
102
|
+
|
|
62
103
|
public DistanceFilterLocationProvider(Context context) {
|
|
63
104
|
super(context);
|
|
64
105
|
PROVIDER_ID = Config.DISTANCE_FILTER_PROVIDER;
|
|
65
106
|
}
|
|
66
107
|
|
|
108
|
+
// ====== FLP path callbacks ======
|
|
109
|
+
|
|
110
|
+
private final LocationCallback fusedCallback = new LocationCallback() {
|
|
111
|
+
@Override
|
|
112
|
+
public void onLocationResult(LocationResult result) {
|
|
113
|
+
if (result == null) return;
|
|
114
|
+
List<Location> locations = result.getLocations();
|
|
115
|
+
if (locations == null) return;
|
|
116
|
+
for (Location location : locations) {
|
|
117
|
+
handleNewLocation(location);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
/** FLP one-shot callback used by the stationary polling alarm. */
|
|
123
|
+
private final LocationCallback fusedPollCallback = new LocationCallback() {
|
|
124
|
+
@Override
|
|
125
|
+
public void onLocationResult(LocationResult result) {
|
|
126
|
+
if (result == null || fusedClient == null) return;
|
|
127
|
+
try {
|
|
128
|
+
fusedClient.removeLocationUpdates(this);
|
|
129
|
+
} catch (Exception ignored) { /* fire-and-forget */ }
|
|
130
|
+
Location loc = result.getLastLocation();
|
|
131
|
+
if (loc != null) {
|
|
132
|
+
logger.debug("Stationary monitor single update: {}", loc);
|
|
133
|
+
onPollStationaryLocation(loc);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
// ====== Lifecycle ======
|
|
139
|
+
|
|
67
140
|
@Override
|
|
68
141
|
public void onCreate() {
|
|
69
142
|
super.onCreate();
|
|
@@ -71,56 +144,46 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
71
144
|
locationManager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
|
|
72
145
|
alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
|
|
73
146
|
|
|
147
|
+
// v4.5.2 — pick the location backend at runtime. Play Services missing
|
|
148
|
+
// (Huawei/HMS, AOSP, China ROMs) → use the OS LocationManager so the
|
|
149
|
+
// provider still works.
|
|
150
|
+
int gps = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(mContext);
|
|
151
|
+
usingFused = (gps == ConnectionResult.SUCCESS);
|
|
152
|
+
if (usingFused) {
|
|
153
|
+
fusedClient = LocationServices.getFusedLocationProviderClient(mContext);
|
|
154
|
+
logger.info("DISTANCE_FILTER_PROVIDER using FusedLocationProviderClient (Play Services available).");
|
|
155
|
+
} else {
|
|
156
|
+
logger.info("DISTANCE_FILTER_PROVIDER falling back to LocationManager (Play Services unavailable, code={}).", gps);
|
|
157
|
+
}
|
|
158
|
+
|
|
74
159
|
int updateCurrentFlag = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
|
75
160
|
? PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE
|
|
76
161
|
: PendingIntent.FLAG_UPDATE_CURRENT;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
162
|
+
// v4.5.2: singleUpdatePI must be MUTABLE on API 31+ because
|
|
163
|
+
// LocationManager.requestSingleUpdate() fills the resulting Location
|
|
164
|
+
// into the intent's extras at delivery time. FLAG_IMMUTABLE blocks that
|
|
165
|
+
// population, so the receiver would never see the fix.
|
|
166
|
+
int singleUpdateFlag = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
|
|
167
|
+
? PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE
|
|
80
168
|
: PendingIntent.FLAG_CANCEL_CURRENT;
|
|
81
169
|
|
|
82
170
|
Intent stationaryAlarmIntent = new Intent(mContext, StationaryAlarmReceiver.class);
|
|
83
171
|
stationaryAlarmIntent.setAction(STATIONARY_ALARM_ACTION);
|
|
84
|
-
|
|
85
|
-
// Stop-detection PI (requestCode 9000)
|
|
86
172
|
stationaryAlarmPI = PendingIntent.getBroadcast(mContext, 9000, stationaryAlarmIntent, updateCurrentFlag);
|
|
87
173
|
registerReceiver(stationaryAlarmReceiver, new IntentFilter(STATIONARY_ALARM_ACTION));
|
|
88
174
|
|
|
89
|
-
Intent stationaryRegionIntent = new Intent(mContext, StationaryRegionReceiver.class);
|
|
90
|
-
stationaryRegionIntent.setAction(STATIONARY_REGION_ACTION);
|
|
91
|
-
|
|
92
|
-
// Stationary region PI (requestCode 9001)
|
|
93
|
-
stationaryRegionPI = PendingIntent.getBroadcast(mContext, 9001, stationaryRegionIntent, cancelCurrentFlag);
|
|
94
|
-
registerReceiver(stationaryRegionReceiver, new IntentFilter(STATIONARY_REGION_ACTION));
|
|
95
|
-
|
|
96
175
|
Intent stationaryLocationMonitorIntent = new Intent(mContext, StationaryLocationMonitorReceiver.class);
|
|
97
176
|
stationaryLocationMonitorIntent.setAction(STATIONARY_LOCATION_MONITOR_ACTION);
|
|
98
|
-
|
|
99
|
-
// Stationary location monitor PI (requestCode 9002)
|
|
100
177
|
stationaryLocationPollingPI = PendingIntent.getBroadcast(mContext, 9002, stationaryLocationMonitorIntent, updateCurrentFlag);
|
|
101
178
|
registerReceiver(stationaryLocationMonitorReceiver, new IntentFilter(STATIONARY_LOCATION_MONITOR_ACTION));
|
|
102
179
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
// v3.4 Phase 3: Criteria API removed (deprecated since Android 12 / API 31).
|
|
111
|
-
// Provider selection is now explicit (GPS-first / Network-fallback) via pickProvider().
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/** v3.4 Phase 3: replaces getBestProvider(criteria, true). */
|
|
115
|
-
private String pickProvider() {
|
|
116
|
-
if (locationManager == null) return null;
|
|
117
|
-
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
|
|
118
|
-
return LocationManager.GPS_PROVIDER;
|
|
119
|
-
}
|
|
120
|
-
if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
|
|
121
|
-
return LocationManager.NETWORK_PROVIDER;
|
|
180
|
+
// Legacy single-update PI + receiver (only used when usingFused == false).
|
|
181
|
+
if (!usingFused) {
|
|
182
|
+
Intent singleLocationUpdateIntent = new Intent(mContext, SingleUpdateReceiver.class);
|
|
183
|
+
singleLocationUpdateIntent.setAction(SINGLE_LOCATION_UPDATE_ACTION);
|
|
184
|
+
singleUpdatePI = PendingIntent.getBroadcast(mContext, 9003, singleLocationUpdateIntent, singleUpdateFlag);
|
|
185
|
+
registerReceiver(singleUpdateReceiver, new IntentFilter(SINGLE_LOCATION_UPDATE_ACTION));
|
|
122
186
|
}
|
|
123
|
-
return null;
|
|
124
187
|
}
|
|
125
188
|
|
|
126
189
|
@Override
|
|
@@ -141,7 +204,7 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
141
204
|
return;
|
|
142
205
|
}
|
|
143
206
|
|
|
144
|
-
logger.info("Start recording");
|
|
207
|
+
logger.info("Start recording (path={})", usingFused ? "fused" : "legacy");
|
|
145
208
|
scaledDistanceFilter = mConfig.getDistanceFilter();
|
|
146
209
|
isStarted = true;
|
|
147
210
|
setPace(false);
|
|
@@ -153,12 +216,7 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
153
216
|
return;
|
|
154
217
|
}
|
|
155
218
|
try {
|
|
156
|
-
|
|
157
|
-
locationManager.removeUpdates(this);
|
|
158
|
-
if (stationaryRegionPI != null) {
|
|
159
|
-
locationManager.removeProximityAlert(stationaryRegionPI);
|
|
160
|
-
}
|
|
161
|
-
}
|
|
219
|
+
unsubscribeLocationUpdates();
|
|
162
220
|
if (alarmManager != null) {
|
|
163
221
|
if (stationaryAlarmPI != null) alarmManager.cancel(stationaryAlarmPI);
|
|
164
222
|
if (stationaryLocationPollingPI != null) alarmManager.cancel(stationaryLocationPollingPI);
|
|
@@ -192,31 +250,82 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
192
250
|
return isStarted;
|
|
193
251
|
}
|
|
194
252
|
|
|
253
|
+
/** GPS first, fall back to Network — used only by the legacy LocationManager path. */
|
|
254
|
+
private String pickProvider() {
|
|
255
|
+
if (locationManager == null) return null;
|
|
256
|
+
if (locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)) {
|
|
257
|
+
return LocationManager.GPS_PROVIDER;
|
|
258
|
+
}
|
|
259
|
+
if (locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)) {
|
|
260
|
+
return LocationManager.NETWORK_PROVIDER;
|
|
261
|
+
}
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** Cheap check used to decide whether to emit SERVICE_ERROR when subscribing. */
|
|
266
|
+
private boolean anyProviderEnabled() {
|
|
267
|
+
if (locationManager == null) return true;
|
|
268
|
+
boolean gpsOn = false, netOn = false;
|
|
269
|
+
try { gpsOn = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); }
|
|
270
|
+
catch (Exception ignored) { /* may throw on devices with no GPS hardware */ }
|
|
271
|
+
try { netOn = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); }
|
|
272
|
+
catch (Exception ignored) { }
|
|
273
|
+
return gpsOn || netOn;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** Translate the plugin's desiredAccuracy buckets into FLP priorities (FLP path only). */
|
|
277
|
+
private int translatePriority(Integer accuracy) {
|
|
278
|
+
if (accuracy == null) {
|
|
279
|
+
return Priority.PRIORITY_BALANCED_POWER_ACCURACY;
|
|
280
|
+
}
|
|
281
|
+
if (accuracy >= 10000) {
|
|
282
|
+
return Priority.PRIORITY_PASSIVE;
|
|
283
|
+
}
|
|
284
|
+
if (accuracy >= 1000) {
|
|
285
|
+
return Priority.PRIORITY_LOW_POWER;
|
|
286
|
+
}
|
|
287
|
+
if (accuracy >= 100) {
|
|
288
|
+
return Priority.PRIORITY_BALANCED_POWER_ACCURACY;
|
|
289
|
+
}
|
|
290
|
+
return Priority.PRIORITY_HIGH_ACCURACY;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
private void unsubscribeLocationUpdates() {
|
|
294
|
+
try {
|
|
295
|
+
if (usingFused && fusedClient != null) {
|
|
296
|
+
fusedClient.removeLocationUpdates(fusedCallback);
|
|
297
|
+
fusedClient.removeLocationUpdates(fusedPollCallback);
|
|
298
|
+
}
|
|
299
|
+
if (locationManager != null) {
|
|
300
|
+
locationManager.removeUpdates(this);
|
|
301
|
+
}
|
|
302
|
+
} catch (SecurityException ignored) {
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
195
306
|
/**
|
|
196
|
-
*
|
|
197
|
-
* @param value set true to engage "aggressive", battery-consuming tracking, false for stationary-region tracking
|
|
307
|
+
* @param value true → aggressive moving tracking, false → stationary monitoring
|
|
198
308
|
*/
|
|
199
309
|
private void setPace(Boolean value) {
|
|
200
310
|
if (!isStarted) {
|
|
201
311
|
return;
|
|
202
312
|
}
|
|
203
|
-
if (mConfig == null
|
|
313
|
+
if (mConfig == null) {
|
|
204
314
|
return;
|
|
205
315
|
}
|
|
206
316
|
|
|
207
317
|
logger.info("Setting pace: {}", value);
|
|
208
318
|
|
|
209
|
-
Boolean wasMoving
|
|
210
|
-
isMoving
|
|
211
|
-
isAcquiringStationaryLocation
|
|
212
|
-
isAcquiringSpeed
|
|
213
|
-
stationaryLocation
|
|
319
|
+
Boolean wasMoving = isMoving;
|
|
320
|
+
isMoving = value;
|
|
321
|
+
isAcquiringStationaryLocation = false;
|
|
322
|
+
isAcquiringSpeed = false;
|
|
323
|
+
stationaryLocation = null;
|
|
214
324
|
|
|
215
325
|
try {
|
|
216
|
-
|
|
326
|
+
unsubscribeLocationUpdates();
|
|
217
327
|
|
|
218
328
|
if (isMoving) {
|
|
219
|
-
// setPace can be called while moving, after distanceFilter has been recalculated. We don't want to re-acquire velocity in this case.
|
|
220
329
|
if (!wasMoving) {
|
|
221
330
|
isAcquiringSpeed = true;
|
|
222
331
|
}
|
|
@@ -224,95 +333,134 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
224
333
|
isAcquiringStationaryLocation = true;
|
|
225
334
|
}
|
|
226
335
|
|
|
227
|
-
|
|
336
|
+
if (!anyProviderEnabled()) {
|
|
337
|
+
handleServiceError("No location provider available (GPS and Network disabled).");
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (usingFused) {
|
|
341
|
+
subscribeFused();
|
|
342
|
+
} else {
|
|
343
|
+
subscribeLegacy();
|
|
344
|
+
}
|
|
345
|
+
} catch (SecurityException e) {
|
|
346
|
+
logger.error("Security exception: {}", e.getMessage());
|
|
347
|
+
this.handleSecurityException(e);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
private void subscribeFused() {
|
|
352
|
+
if (fusedClient == null) return;
|
|
353
|
+
LocationRequest request;
|
|
354
|
+
if (isAcquiringSpeed || isAcquiringStationaryLocation) {
|
|
355
|
+
locationAcquisitionAttempts = 0;
|
|
356
|
+
request = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, ACQUISITION_INTERVAL_MS)
|
|
357
|
+
.setMinUpdateIntervalMillis(ACQUISITION_INTERVAL_MS)
|
|
358
|
+
.setWaitForAccurateLocation(false)
|
|
359
|
+
.build();
|
|
360
|
+
} else {
|
|
361
|
+
int priority = translatePriority(mConfig.getDesiredAccuracy());
|
|
362
|
+
long interval = mConfig.getInterval();
|
|
363
|
+
LocationRequest.Builder b = new LocationRequest.Builder(priority, interval)
|
|
364
|
+
.setMinUpdateIntervalMillis(Math.min(interval, 1000L))
|
|
365
|
+
.setWaitForAccurateLocation(false);
|
|
366
|
+
if (scaledDistanceFilter != null && scaledDistanceFilter > 0) {
|
|
367
|
+
b.setMinUpdateDistanceMeters(scaledDistanceFilter.floatValue());
|
|
368
|
+
}
|
|
369
|
+
request = b.build();
|
|
370
|
+
}
|
|
371
|
+
try {
|
|
372
|
+
fusedClient.requestLocationUpdates(request, fusedCallback, Looper.getMainLooper());
|
|
373
|
+
} catch (SecurityException e) {
|
|
374
|
+
this.handleSecurityException(e);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
private void subscribeLegacy() {
|
|
379
|
+
if (locationManager == null) return;
|
|
380
|
+
try {
|
|
228
381
|
if (isAcquiringSpeed || isAcquiringStationaryLocation) {
|
|
229
382
|
locationAcquisitionAttempts = 0;
|
|
230
|
-
//
|
|
383
|
+
// Burst: subscribe to every non-passive provider for fastest lock.
|
|
231
384
|
List<String> matchingProviders = locationManager.getAllProviders();
|
|
232
|
-
for (String provider: matchingProviders) {
|
|
385
|
+
for (String provider : matchingProviders) {
|
|
233
386
|
if (!LocationManager.PASSIVE_PROVIDER.equals(provider)) {
|
|
234
387
|
logger.info("Requesting location updates from provider {}", provider);
|
|
235
388
|
locationManager.requestLocationUpdates(provider, 0, 0, this);
|
|
236
389
|
}
|
|
237
390
|
}
|
|
238
391
|
} else {
|
|
239
|
-
|
|
240
|
-
|
|
392
|
+
// v4.5.2 — subscribe to GPS AND Network simultaneously when both
|
|
393
|
+
// are available. The previous version only used GPS-or-Network
|
|
394
|
+
// (excluyente), which on cheap/vehicular Androids could leave the
|
|
395
|
+
// app waiting for a GPS fix while a quick Network fix was available.
|
|
396
|
+
boolean gpsOn = false, netOn = false;
|
|
397
|
+
try { gpsOn = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER); }
|
|
398
|
+
catch (Exception ignored) { }
|
|
399
|
+
try { netOn = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER); }
|
|
400
|
+
catch (Exception ignored) { }
|
|
401
|
+
if (!gpsOn && !netOn) {
|
|
241
402
|
logger.warn("No location provider available (GPS and Network disabled)");
|
|
242
403
|
return;
|
|
243
404
|
}
|
|
244
|
-
|
|
245
|
-
|
|
405
|
+
long interval = mConfig.getInterval();
|
|
406
|
+
int distance = scaledDistanceFilter != null ? scaledDistanceFilter : 0;
|
|
407
|
+
if (gpsOn) {
|
|
408
|
+
logger.info("Requesting location updates from GPS");
|
|
409
|
+
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval, distance, this);
|
|
410
|
+
}
|
|
411
|
+
if (netOn) {
|
|
412
|
+
logger.info("Requesting location updates from Network");
|
|
413
|
+
locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, interval, distance, this);
|
|
414
|
+
}
|
|
246
415
|
}
|
|
247
416
|
} catch (SecurityException e) {
|
|
248
|
-
logger.error("Security exception: {}", e.getMessage());
|
|
249
417
|
this.handleSecurityException(e);
|
|
250
418
|
}
|
|
251
419
|
}
|
|
252
420
|
|
|
253
|
-
//
|
|
254
|
-
// Provider selection no longer depends on Criteria; pickProvider() chooses GPS-first.
|
|
421
|
+
// ====== LocationListener (legacy path) ======
|
|
255
422
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
* specified in {@link setChangedLocationListener}.
|
|
261
|
-
* @param minTime Minimum time required between location updates.
|
|
262
|
-
* @return The most accurate and / or timely previously detected location.
|
|
263
|
-
*/
|
|
264
|
-
public Location getLastBestLocation() {
|
|
265
|
-
if (mConfig == null || locationManager == null) {
|
|
266
|
-
return null;
|
|
267
|
-
}
|
|
268
|
-
Location bestResult = null;
|
|
269
|
-
String bestProvider = null;
|
|
270
|
-
float bestAccuracy = Float.MAX_VALUE;
|
|
271
|
-
long bestTime = Long.MIN_VALUE;
|
|
272
|
-
long minTime = System.currentTimeMillis() - mConfig.getInterval();
|
|
423
|
+
@Override
|
|
424
|
+
public void onLocationChanged(Location location) {
|
|
425
|
+
handleNewLocation(location);
|
|
426
|
+
}
|
|
273
427
|
|
|
274
|
-
|
|
428
|
+
@Override
|
|
429
|
+
public void onStatusChanged(String provider, int status, Bundle extras) {
|
|
430
|
+
logger.debug("Provider {} status changed: {}", provider, status);
|
|
431
|
+
}
|
|
275
432
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
List<String> matchingProviders = locationManager.getAllProviders();
|
|
281
|
-
for (String provider: matchingProviders) {
|
|
282
|
-
Location location = locationManager.getLastKnownLocation(provider);
|
|
283
|
-
if (location != null) {
|
|
284
|
-
logger.debug("Test provider={} lat={} lon={} acy={} v={}m/s time={}", provider, location.getLatitude(), location.getLongitude(), location.getAccuracy(), location.getSpeed(), location.getTime());
|
|
285
|
-
float accuracy = location.getAccuracy();
|
|
286
|
-
long time = location.getTime();
|
|
287
|
-
if ((time > minTime && accuracy < bestAccuracy)) {
|
|
288
|
-
bestProvider = provider;
|
|
289
|
-
bestResult = location;
|
|
290
|
-
bestAccuracy = accuracy;
|
|
291
|
-
bestTime = time;
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
433
|
+
@Override
|
|
434
|
+
public void onProviderEnabled(String provider) {
|
|
435
|
+
logger.debug("Provider {} was enabled", provider);
|
|
436
|
+
}
|
|
295
437
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
438
|
+
@Override
|
|
439
|
+
public void onProviderDisabled(String provider) {
|
|
440
|
+
logger.warn("Provider {} was disabled", provider);
|
|
441
|
+
// v4.5.2: surface as an error so JS layer can prompt the user to enable
|
|
442
|
+
// location services. Only when no fallback provider is left.
|
|
443
|
+
if (locationManager != null && pickProvider() == null) {
|
|
444
|
+
handleServiceError("Location provider '" + provider + "' disabled and no fallback available.");
|
|
302
445
|
}
|
|
303
|
-
|
|
304
|
-
return bestResult;
|
|
305
446
|
}
|
|
306
447
|
|
|
307
|
-
|
|
448
|
+
// ====== State machine (path-agnostic) ======
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Same logic as the legacy {@code onLocationChanged}: handles the moving / stationary /
|
|
452
|
+
* acquisition state machine. Called from both the FLP callback and the LocationListener.
|
|
453
|
+
*/
|
|
454
|
+
private void handleNewLocation(Location location) {
|
|
455
|
+
if (location == null) return;
|
|
308
456
|
logger.debug("Location change: {} isMoving={}", location.toString(), isMoving);
|
|
309
457
|
|
|
310
458
|
if (!isMoving && !isAcquiringStationaryLocation && stationaryLocation==null) {
|
|
311
|
-
// Perhaps our GPS signal was
|
|
459
|
+
// Perhaps our GPS signal was interrupted, re-acquire a stationary location now.
|
|
312
460
|
setPace(false);
|
|
313
461
|
}
|
|
314
462
|
|
|
315
|
-
showDebugToast(
|
|
463
|
+
showDebugToast("mv:" + isMoving + ",acy:" + location.getAccuracy() + ",v:" + location.getSpeed() + ",df:" + scaledDistanceFilter);
|
|
316
464
|
|
|
317
465
|
if (isAcquiringStationaryLocation) {
|
|
318
466
|
if (stationaryLocation == null || stationaryLocation.getAccuracy() > location.getAccuracy()) {
|
|
@@ -320,17 +468,15 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
320
468
|
}
|
|
321
469
|
if (++locationAcquisitionAttempts == MAX_STATIONARY_ACQUISITION_ATTEMPTS) {
|
|
322
470
|
isAcquiringStationaryLocation = false;
|
|
323
|
-
|
|
471
|
+
enterStationary(stationaryLocation);
|
|
324
472
|
handleStationary(stationaryLocation, stationaryRadius);
|
|
325
473
|
return;
|
|
326
474
|
} else {
|
|
327
|
-
// Unacceptable stationary-location: bail-out and wait for another.
|
|
328
475
|
playDebugTone(Tone.BEEP);
|
|
329
476
|
return;
|
|
330
477
|
}
|
|
331
478
|
} else if (isAcquiringSpeed) {
|
|
332
479
|
if (++locationAcquisitionAttempts == MAX_SPEED_ACQUISITION_ATTEMPTS) {
|
|
333
|
-
// Got enough samples, assume we're confident in reported speed now. Play "woohoo" sound.
|
|
334
480
|
playDebugTone(Tone.DOODLY_DOO);
|
|
335
481
|
isAcquiringSpeed = false;
|
|
336
482
|
scaledDistanceFilter = calculateDistanceFilter(location.getSpeed());
|
|
@@ -342,11 +488,9 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
342
488
|
} else if (isMoving) {
|
|
343
489
|
playDebugTone(Tone.BEEP);
|
|
344
490
|
|
|
345
|
-
|
|
346
|
-
if ( (location.getSpeed() >= 1) && (location.getAccuracy() <= mConfig.getStationaryRadius()) ) {
|
|
491
|
+
if ((location.getSpeed() >= 1) && (location.getAccuracy() <= mConfig.getStationaryRadius())) {
|
|
347
492
|
resetStationaryAlarm();
|
|
348
493
|
}
|
|
349
|
-
// Calculate latest distanceFilter, if it changed by 5 m/s, we'll reconfigure our pace.
|
|
350
494
|
Integer newDistanceFilter = calculateDistanceFilter(location.getSpeed());
|
|
351
495
|
if (newDistanceFilter != scaledDistanceFilter.intValue()) {
|
|
352
496
|
logger.info("Updating distanceFilter: new={} old={}", newDistanceFilter, scaledDistanceFilter);
|
|
@@ -359,7 +503,6 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
359
503
|
} else if (stationaryLocation != null) {
|
|
360
504
|
return;
|
|
361
505
|
}
|
|
362
|
-
// Go ahead and cache, push to server
|
|
363
506
|
lastLocation = location;
|
|
364
507
|
handleLocation(location);
|
|
365
508
|
}
|
|
@@ -367,7 +510,7 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
367
510
|
public void resetStationaryAlarm() {
|
|
368
511
|
if (alarmManager == null || stationaryAlarmPI == null) return;
|
|
369
512
|
alarmManager.cancel(stationaryAlarmPI);
|
|
370
|
-
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() +
|
|
513
|
+
alarmManager.set(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + getStationaryTimeout(), stationaryAlarmPI);
|
|
371
514
|
}
|
|
372
515
|
|
|
373
516
|
private Integer calculateDistanceFilter(Float speed) {
|
|
@@ -379,52 +522,40 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
379
522
|
return (newDistanceFilter.intValue() < 1000) ? newDistanceFilter.intValue() : 1000;
|
|
380
523
|
}
|
|
381
524
|
|
|
382
|
-
|
|
383
|
-
|
|
525
|
+
/**
|
|
526
|
+
* v4.5.2 — Stop active updates and start the polling-based stationary monitor.
|
|
527
|
+
* The previous version also called {@code addProximityAlert} (geofence); that
|
|
528
|
+
* path has been removed per product decision (no geofencing).
|
|
529
|
+
*/
|
|
530
|
+
private void enterStationary(Location location) {
|
|
531
|
+
if (location == null || mConfig == null) return;
|
|
384
532
|
try {
|
|
385
|
-
|
|
533
|
+
unsubscribeLocationUpdates();
|
|
386
534
|
|
|
387
|
-
float
|
|
388
|
-
float proximityRadius = (location.getAccuracy() <
|
|
535
|
+
float radius = mConfig.getStationaryRadius();
|
|
536
|
+
float proximityRadius = (location.getAccuracy() < radius) ? radius : location.getAccuracy();
|
|
389
537
|
stationaryLocation = location;
|
|
390
|
-
|
|
391
|
-
logger.info("startMonitoringStationaryRegion: lat={} lon={} acy={}", location.getLatitude(), location.getLongitude(), proximityRadius);
|
|
392
|
-
|
|
393
|
-
// Here be the execution of the stationary region monitor
|
|
394
|
-
locationManager.addProximityAlert(
|
|
395
|
-
location.getLatitude(),
|
|
396
|
-
location.getLongitude(),
|
|
397
|
-
proximityRadius,
|
|
398
|
-
(long)-1,
|
|
399
|
-
stationaryRegionPI
|
|
400
|
-
);
|
|
401
|
-
|
|
402
538
|
this.stationaryRadius = proximityRadius;
|
|
403
539
|
|
|
404
|
-
|
|
540
|
+
logger.info("enterStationary: lat={} lon={} acy={} radius={}", location.getLatitude(), location.getLongitude(), location.getAccuracy(), proximityRadius);
|
|
541
|
+
|
|
542
|
+
startPollingStationaryLocation(getStationaryPollLazy());
|
|
405
543
|
} catch (SecurityException e) {
|
|
406
544
|
logger.error("Security exception: {}", e.getMessage());
|
|
407
545
|
this.handleSecurityException(e);
|
|
408
546
|
}
|
|
409
547
|
}
|
|
410
548
|
|
|
411
|
-
/**
|
|
412
|
-
* User has exit his stationary region! Initiate aggressive geolocation!
|
|
413
|
-
*/
|
|
549
|
+
/** Engage aggressive geolocation after stationary exit. */
|
|
414
550
|
public void onExitStationaryRegion(Location location) {
|
|
415
|
-
if (location == null || alarmManager == null
|
|
551
|
+
if (location == null || alarmManager == null) return;
|
|
416
552
|
|
|
417
553
|
playDebugTone(Tone.BEEP_BEEP_BEEP);
|
|
418
554
|
|
|
419
|
-
logger.info("Exited stationary: lat={} long={} acy={}
|
|
420
|
-
location.getLatitude(), location.getLongitude(), location.getAccuracy());
|
|
555
|
+
logger.info("Exited stationary: lat={} long={} acy={}", location.getLatitude(), location.getLongitude(), location.getAccuracy());
|
|
421
556
|
|
|
422
557
|
try {
|
|
423
|
-
// Cancel the periodic stationary location monitor alarm.
|
|
424
558
|
alarmManager.cancel(stationaryLocationPollingPI);
|
|
425
|
-
// Kill the current region-monitor we just walked out of.
|
|
426
|
-
locationManager.removeProximityAlert(stationaryRegionPI);
|
|
427
|
-
// Engage aggressive tracking.
|
|
428
559
|
this.setPace(true);
|
|
429
560
|
} catch (SecurityException e) {
|
|
430
561
|
logger.error("Security exception: {}", e.getMessage());
|
|
@@ -434,8 +565,6 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
434
565
|
|
|
435
566
|
public void startPollingStationaryLocation(long interval) {
|
|
436
567
|
if (alarmManager == null || stationaryLocationPollingPI == null) return;
|
|
437
|
-
// proximity-alerts don't seem to work while suspended in latest Android 4.42 (works in 4.03). Have to use AlarmManager to sample
|
|
438
|
-
// location at regular intervals with a one-shot.
|
|
439
568
|
stationaryLocationPollingInterval = interval;
|
|
440
569
|
alarmManager.cancel(stationaryLocationPollingPI);
|
|
441
570
|
long start = System.currentTimeMillis() + 60_000;
|
|
@@ -445,7 +574,7 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
445
574
|
public void onPollStationaryLocation(Location location) {
|
|
446
575
|
if (location == null || mConfig == null) return;
|
|
447
576
|
|
|
448
|
-
float
|
|
577
|
+
float radius = mConfig.getStationaryRadius();
|
|
449
578
|
if (isMoving) {
|
|
450
579
|
return;
|
|
451
580
|
}
|
|
@@ -456,128 +585,84 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
456
585
|
distance = abs(location.distanceTo(stationaryLocation) - stationaryLocation.getAccuracy() - location.getAccuracy());
|
|
457
586
|
}
|
|
458
587
|
|
|
459
|
-
showDebugToast("Stationary exit in " + (
|
|
588
|
+
showDebugToast("Stationary exit in " + (radius - distance) + "m");
|
|
460
589
|
|
|
461
|
-
// TODO http://www.cse.buffalo.edu/~demirbas/publications/proximity.pdf
|
|
462
|
-
// determine if we're almost out of stationary-distance and increase monitoring-rate.
|
|
463
590
|
logger.info("Distance from stationary location: {}", distance);
|
|
464
|
-
if (distance >
|
|
591
|
+
if (distance > radius) {
|
|
465
592
|
onExitStationaryRegion(location);
|
|
466
593
|
} else if (distance > 0) {
|
|
467
|
-
startPollingStationaryLocation(
|
|
468
|
-
} else if (stationaryLocationPollingInterval !=
|
|
469
|
-
startPollingStationaryLocation(
|
|
594
|
+
startPollingStationaryLocation(getStationaryPollFast());
|
|
595
|
+
} else if (stationaryLocationPollingInterval != getStationaryPollLazy()) {
|
|
596
|
+
startPollingStationaryLocation(getStationaryPollLazy());
|
|
470
597
|
}
|
|
471
598
|
}
|
|
472
599
|
|
|
473
|
-
|
|
474
|
-
* Broadcast receiver for receiving a single-update from LocationManager.
|
|
475
|
-
*/
|
|
476
|
-
private class SingleUpdateReceiver extends BroadcastReceiver {
|
|
477
|
-
@Override
|
|
478
|
-
public void onReceive(Context context, Intent intent) {
|
|
479
|
-
Bundle extras = intent.getExtras();
|
|
480
|
-
if (extras == null) return;
|
|
481
|
-
String key = LocationManager.KEY_LOCATION_CHANGED;
|
|
482
|
-
Location location = extras.getParcelable(key);
|
|
483
|
-
if (location != null) {
|
|
484
|
-
logger.debug("Single location update: " + location.toString());
|
|
485
|
-
onPollStationaryLocation(location);
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
}
|
|
600
|
+
// ====== Receivers ======
|
|
489
601
|
|
|
490
|
-
private BroadcastReceiver singleUpdateReceiver = new SingleUpdateReceiver();
|
|
491
|
-
|
|
492
|
-
/**
|
|
493
|
-
* Broadcast receiver which detects a user has stopped for a long enough time to be determined as STOPPED
|
|
494
|
-
*/
|
|
495
602
|
private class StationaryAlarmReceiver extends BroadcastReceiver {
|
|
496
603
|
@Override
|
|
497
|
-
public void onReceive(Context context, Intent intent)
|
|
498
|
-
{
|
|
604
|
+
public void onReceive(Context context, Intent intent) {
|
|
499
605
|
logger.info("stationaryAlarm fired");
|
|
500
606
|
setPace(false);
|
|
501
607
|
}
|
|
502
608
|
}
|
|
503
|
-
|
|
504
609
|
private BroadcastReceiver stationaryAlarmReceiver = new StationaryAlarmReceiver();
|
|
505
610
|
|
|
506
611
|
/**
|
|
507
|
-
*
|
|
508
|
-
*
|
|
509
|
-
*
|
|
612
|
+
* Triggered by the inexact repeating alarm to poll a single fresh location while
|
|
613
|
+
* inside the stationary region. Uses FLP one-shot when available, otherwise falls
|
|
614
|
+
* back to {@link LocationManager#requestSingleUpdate(String, PendingIntent)}.
|
|
510
615
|
*/
|
|
511
616
|
private class StationaryLocationMonitorReceiver extends BroadcastReceiver {
|
|
512
617
|
@Override
|
|
513
|
-
public void onReceive(Context context, Intent intent)
|
|
514
|
-
{
|
|
515
|
-
if (locationManager == null || singleUpdatePI == null) return;
|
|
516
|
-
|
|
618
|
+
public void onReceive(Context context, Intent intent) {
|
|
517
619
|
logger.info("Stationary location monitor fired");
|
|
518
620
|
playDebugTone(Tone.DIALTONE);
|
|
519
621
|
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
622
|
+
if (usingFused && fusedClient != null) {
|
|
623
|
+
LocationRequest oneShot = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 0L)
|
|
624
|
+
.setMaxUpdates(1)
|
|
625
|
+
.setWaitForAccurateLocation(false)
|
|
626
|
+
.build();
|
|
627
|
+
try {
|
|
628
|
+
fusedClient.requestLocationUpdates(oneShot, fusedPollCallback, Looper.getMainLooper());
|
|
629
|
+
} catch (SecurityException e) {
|
|
630
|
+
logger.error("Security exception (FLP one-shot): {}", e.getMessage());
|
|
631
|
+
} catch (IllegalArgumentException e) {
|
|
632
|
+
logger.warn("FLP one-shot failed: {}", e.getMessage());
|
|
633
|
+
}
|
|
634
|
+
} else if (locationManager != null && singleUpdatePI != null) {
|
|
635
|
+
String provider = pickProvider();
|
|
636
|
+
if (provider == null) {
|
|
637
|
+
logger.warn("Stationary monitor: no provider available");
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
try {
|
|
641
|
+
locationManager.requestSingleUpdate(provider, singleUpdatePI);
|
|
642
|
+
} catch (SecurityException e) {
|
|
643
|
+
logger.error("Security exception (single update): {}", e.getMessage());
|
|
644
|
+
} catch (IllegalArgumentException e) {
|
|
645
|
+
logger.warn("requestSingleUpdate failed: {}", e.getMessage());
|
|
646
|
+
}
|
|
533
647
|
}
|
|
534
648
|
}
|
|
535
649
|
}
|
|
536
|
-
|
|
537
650
|
private BroadcastReceiver stationaryLocationMonitorReceiver = new StationaryLocationMonitorReceiver();
|
|
538
651
|
|
|
539
|
-
/**
|
|
540
|
-
|
|
541
|
-
*/
|
|
542
|
-
private class StationaryRegionReceiver extends BroadcastReceiver {
|
|
652
|
+
/** Legacy single-update receiver — feeds {@link #onPollStationaryLocation(Location)}. */
|
|
653
|
+
private class SingleUpdateReceiver extends BroadcastReceiver {
|
|
543
654
|
@Override
|
|
544
655
|
public void onReceive(Context context, Intent intent) {
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
if (
|
|
549
|
-
logger.debug("
|
|
550
|
-
|
|
551
|
-
setPace(false);
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
else {
|
|
555
|
-
logger.debug("Exiting stationary region");
|
|
556
|
-
// There MUST be a valid, recent location if this event-handler was called.
|
|
557
|
-
Location location = getLastBestLocation();
|
|
558
|
-
if (location != null) {
|
|
559
|
-
onExitStationaryRegion(location);
|
|
560
|
-
}
|
|
656
|
+
Bundle extras = intent.getExtras();
|
|
657
|
+
if (extras == null) return;
|
|
658
|
+
Location location = extras.getParcelable(LocationManager.KEY_LOCATION_CHANGED);
|
|
659
|
+
if (location != null) {
|
|
660
|
+
logger.debug("Single location update: {}", location);
|
|
661
|
+
onPollStationaryLocation(location);
|
|
561
662
|
}
|
|
562
663
|
}
|
|
563
664
|
}
|
|
564
|
-
|
|
565
|
-
private BroadcastReceiver stationaryRegionReceiver = new StationaryRegionReceiver();
|
|
566
|
-
|
|
567
|
-
public void onProviderDisabled(String provider) {
|
|
568
|
-
// TODO Auto-generated method stub
|
|
569
|
-
logger.debug("Provider {} was disabled", provider);
|
|
570
|
-
}
|
|
571
|
-
|
|
572
|
-
public void onProviderEnabled(String provider) {
|
|
573
|
-
// TODO Auto-generated method stub
|
|
574
|
-
logger.debug("Provider {} was enabled", provider);
|
|
575
|
-
}
|
|
576
|
-
|
|
577
|
-
public void onStatusChanged(String provider, int status, Bundle extras) {
|
|
578
|
-
// TODO Auto-generated method stub
|
|
579
|
-
logger.debug("Provider {} status changed: {}", provider, status);
|
|
580
|
-
}
|
|
665
|
+
private BroadcastReceiver singleUpdateReceiver = new SingleUpdateReceiver();
|
|
581
666
|
|
|
582
667
|
@Override
|
|
583
668
|
public void onDestroy() {
|
|
@@ -590,9 +675,10 @@ public class DistanceFilterLocationProvider extends AbstractLocationProvider imp
|
|
|
590
675
|
}
|
|
591
676
|
|
|
592
677
|
try { unregisterReceiver(stationaryAlarmReceiver); } catch (Exception ignored) { }
|
|
593
|
-
try { unregisterReceiver(singleUpdateReceiver); } catch (Exception ignored) { }
|
|
594
|
-
try { unregisterReceiver(stationaryRegionReceiver); } catch (Exception ignored) { }
|
|
595
678
|
try { unregisterReceiver(stationaryLocationMonitorReceiver); } catch (Exception ignored) { }
|
|
679
|
+
if (!usingFused) {
|
|
680
|
+
try { unregisterReceiver(singleUpdateReceiver); } catch (Exception ignored) { }
|
|
681
|
+
}
|
|
596
682
|
|
|
597
683
|
super.onDestroy();
|
|
598
684
|
}
|