Removed AdaptiveLocationListenerPolicy.

Fixes #886.
This commit is contained in:
Dennis Guse
2021-08-16 23:07:00 +02:00
parent 6b3a2eae5e
commit 68c447f77e
62 changed files with 42 additions and 428 deletions
@@ -1,53 +0,0 @@
/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks.services.handlers;
import java.time.Duration;
/**
* This is a simple location listener policy that will always dictate the same polling interval.
*
* @author Sandor Dornbush
*/
public class AbsoluteLocationListenerPolicy implements LocationListenerPolicy {
private final Duration interval;
/**
* Constructor.
*
* @param interval the interval to request for gps signal
*/
public AbsoluteLocationListenerPolicy(Duration interval) {
this.interval = interval;
}
@Override
public Duration getDesiredPollingInterval() {
return interval;
}
@Override
public int getMinDistance_m() {
return 0;
}
@Override
public void updateIdleTime(Duration idleTime) {
// Ignore
}
}
@@ -1,76 +0,0 @@
/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks.services.handlers;
import java.time.Duration;
/**
* A {@link LocationListenerPolicy} that will change based on how long the user has been stationary.
* This policy will dictate a policy based on a min, max and idle time.
* The policy will dictate an interval bounded by min and max, and is half of the idle time.
*
* @author Sandor Dornbush
*/
public class AdaptiveLocationListenerPolicy implements LocationListenerPolicy {
private final Duration minInterval;
private final Duration maxInterval;
private final int minDistance_m;
// The time the user has been idle at the current location, in milliseconds.
private Duration idleTime;
/**
* Creates a policy that will be bounded by the given minInterval_ms and maxInterval_ms.
*
* @param minInterval the smallest interval this policy will dictate
* @param maxInterval the largest interval this policy will dictate
* @param minDistance_m the minimum distance
*/
public AdaptiveLocationListenerPolicy(Duration minInterval, Duration maxInterval, int minDistance_m) {
this.minInterval = minInterval;
this.maxInterval = maxInterval;
this.minDistance_m = minDistance_m;
}
/*
* Returns an interval half of the idle time, but bounded by minInterval and maxInterval.
*/
public Duration getDesiredPollingInterval() {
Duration desiredInterval = idleTime.dividedBy(2);
// Round to second to avoid setting the interval too often
desiredInterval = Duration.ofSeconds(desiredInterval.getSeconds());
if (minInterval.compareTo(desiredInterval) > 0) {
return minInterval;
} else if (maxInterval.compareTo(desiredInterval) < 0) {
return maxInterval;
}
return desiredInterval;
}
@Override
public int getMinDistance_m() {
return minDistance_m;
}
@Override
public void updateIdleTime(Duration newIdleTime) {
idleTime = newIdleTime;
}
}
@@ -71,8 +71,8 @@ class GpsStatus {
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
thresholdHorizontalAccuracy = PreferencesUtils.getRecordingDistanceInterval(sharedPreferences, context);
Duration minRecordingInterval = Duration.ofSeconds(PreferencesUtils.getMinRecordingInterval(sharedPreferences, context));
signalLostThreshold = !minRecordingInterval.isNegative() ? SIGNAL_LOST_THRESHOLD.plus(minRecordingInterval) : SIGNAL_LOST_THRESHOLD;
Duration minRecordingInterval = PreferencesUtils.getMinRecordingInterval(sharedPreferences, context);
signalLostThreshold = SIGNAL_LOST_THRESHOLD.plus(minRecordingInterval);
gpsStatusHandler = new Handler();
}
@@ -102,13 +102,8 @@ class GpsStatus {
thresholdHorizontalAccuracy = value;
}
/**
* Method to change the lost threshold from outside.
*
* @param value Minimal recording interval preference value in seconds or an special value: -1, -2, 0.
*/
public void onMinRecordingIntervalChanged(int value) {
signalLostThreshold = value > 0 ? SIGNAL_LOST_THRESHOLD.plus(Duration.ofSeconds(value)) : SIGNAL_LOST_THRESHOLD;
public void onMinRecordingIntervalChanged(Duration value) {
signalLostThreshold = SIGNAL_LOST_THRESHOLD.plus(value);
}
/**
@@ -19,7 +19,7 @@ import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.util.LocationUtils;
import de.dennisguse.opentracks.util.PreferencesUtils;
@VisibleForTesting(otherwise = 3)
@VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public class LocationHandler implements LocationListener, GpsStatus.GpsStatusListener {
private final String TAG = LocationHandler.class.getSimpleName();
@@ -27,8 +27,7 @@ public class LocationHandler implements LocationListener, GpsStatus.GpsStatusLis
private LocationManager locationManager;
private final TrackPointCreator handlerServer;
private GpsStatus gpsStatus;
private LocationListenerPolicy locationListenerPolicy;
private Duration currentRecordingInterval;
private Duration gpsInterval;
private Distance thresholdHorizontalAccuracy;
private TrackPoint lastTrackPoint;
@@ -64,32 +63,31 @@ public class LocationHandler implements LocationListener, GpsStatus.GpsStatusLis
}
public void onSharedPreferenceChanged(@NonNull Context context, @NonNull SharedPreferences sharedPreferences, String key) {
if (PreferencesUtils.isKey(context, R.string.min_recording_interval_key, key)) {
int minRecordingInterval = PreferencesUtils.getMinRecordingInterval(sharedPreferences, context);
if (minRecordingInterval == PreferencesUtils.getMinRecordingIntervalAdaptBatteryLife(context)) {
// Choose battery life over moving time accuracy.
locationListenerPolicy = new AdaptiveLocationListenerPolicy(Duration.ofSeconds(30), Duration.ofSeconds(5), 5);
} else if (minRecordingInterval == PreferencesUtils.getMinRecordingIntervalAdaptAccuracy(context)) {
// Get all the updates.
locationListenerPolicy = new AdaptiveLocationListenerPolicy(Duration.ofSeconds(1), Duration.ofSeconds(30), 0);
} else {
locationListenerPolicy = new AbsoluteLocationListenerPolicy(Duration.ofSeconds(minRecordingInterval));
}
boolean registerListener = false;
registerLocationListener();
if (PreferencesUtils.isKey(context, R.string.min_recording_interval_key, key)) {
registerListener = true;
gpsInterval = PreferencesUtils.getMinRecordingInterval(sharedPreferences, context);
if (gpsStatus != null) {
gpsStatus.onMinRecordingIntervalChanged(gpsInterval);
}
}
if (PreferencesUtils.isKey(context, R.string.recording_gps_accuracy_key, key)) {
thresholdHorizontalAccuracy = PreferencesUtils.getThresholdHorizontalAccuracy(sharedPreferences, context);
}
if (PreferencesUtils.isKey(context, R.string.min_recording_interval_key, key)) {
if (PreferencesUtils.isKey(context, R.string.recording_distance_interval_key, key)) {
registerListener = true;
if (gpsStatus != null) {
gpsStatus.onMinRecordingIntervalChanged(PreferencesUtils.getMinRecordingInterval(sharedPreferences, context));
Distance gpsMinDistance = PreferencesUtils.getRecordingDistanceInterval(sharedPreferences, context);
gpsStatus.onRecordingDistanceChanged(gpsMinDistance);
}
}
if (PreferencesUtils.isKey(context, R.string.recording_distance_interval_key, key)) {
if (gpsStatus != null) {
gpsStatus.onRecordingDistanceChanged(PreferencesUtils.getRecordingDistanceInterval(sharedPreferences, context));
}
if (registerListener) {
registerLocationListener();
}
}
@@ -123,16 +121,6 @@ public class LocationHandler implements LocationListener, GpsStatus.GpsStatusLis
return;
}
Duration idleTime = Duration.ofSeconds(0);
if (lastTrackPoint != null && trackPoint.getTime().isAfter(lastTrackPoint.getTime())) {
idleTime = Duration.between(lastTrackPoint.getTime(), trackPoint.getTime());
}
locationListenerPolicy.updateIdleTime(idleTime);
if (currentRecordingInterval != locationListenerPolicy.getDesiredPollingInterval()) {
registerLocationListener();
}
lastTrackPoint = trackPoint;
handlerServer.onNewTrackPoint(trackPoint, thresholdHorizontalAccuracy);
}
@@ -161,9 +149,7 @@ public class LocationHandler implements LocationListener, GpsStatus.GpsStatusLis
return;
}
try {
Duration interval = locationListenerPolicy.getDesiredPollingInterval();
currentRecordingInterval = interval;
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, interval.toMillis(), locationListenerPolicy.getMinDistance_m(), this);
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, gpsInterval.toMillis(), 0, this);
} catch (SecurityException e) {
Log.e(TAG, "Could not register location listener; permissions not granted.", e);
}
@@ -1,46 +0,0 @@
/*
* Copyright 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package de.dennisguse.opentracks.services.handlers;
import java.time.Duration;
/**
* This is an interface for classes that will manage the location listener policy.
*
* @author Sandor Dornbush
*/
interface LocationListenerPolicy {
/**
* Returns the polling interval this policy would like at this moment.
*
* @return the polling interval
*/
Duration getDesiredPollingInterval();
/**
* Returns the minimum distance between updates.
*/
int getMinDistance_m();
/**
* Notifies the amount of time the user has been idle at his current location.
*
* @param idleTime the time that the user has been idle at his current location
*/
void updateIdleTime(Duration idleTime);
}
@@ -14,11 +14,7 @@ final class PreferenceHelper {
for (int i = 0; i < entryValues.length; i++) {
int value = Integer.parseInt(entryValues[i]);
if (value == PreferencesUtils.getMinRecordingIntervalAdaptAccuracy(context)) {
entries[i] = context.getString(R.string.value_adapt_accuracy);
} else if (value == PreferencesUtils.getMinRecordingIntervalAdaptBatteryLife(context)) {
entries[i] = context.getString(R.string.value_adapt_battery_life);
} else if (value == PreferencesUtils.getMinRecordingIntervalDefault(context)) {
if (value == PreferencesUtils.getMinRecordingIntervalDefault(context).getSeconds()) {
entries[i] = context.getString(R.string.value_smallest_recommended);
} else {
entries[i] = value < 60 ? context.getString(R.string.value_integer_second, value) : context.getString(R.string.value_integer_minute, value / 60);
@@ -203,7 +203,7 @@ public class SettingsActivity extends AbstractActivity implements ChooseActivity
findPreference(getString(R.string.min_recording_interval_key))
.setSummaryProvider(
preference -> {
Duration interval = Duration.ofSeconds(PreferencesUtils.getMinRecordingInterval(sharedPreferences, getContext()));
Duration interval = PreferencesUtils.getMinRecordingInterval(sharedPreferences, getContext());
return getString(R.string.settings_recording_location_frequency_summary, getString(R.string.value_integer_second, interval.getSeconds()));
}
);
@@ -28,6 +28,8 @@ import androidx.annotation.VisibleForTesting;
import androidx.documentfile.provider.DocumentFile;
import androidx.preference.PreferenceManager;
import java.time.Duration;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
@@ -241,22 +243,19 @@ public class PreferencesUtils {
return Distance.of(getInt(sharedPreferences, context, R.string.max_recording_distance_key, MAX_RECORDING_DISTANCE));
}
//TODO Duration
public static int getMinRecordingInterval(SharedPreferences sharedPreferences, Context context) {
final int MIN_RECORDING_INTERVAL = Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_default));
return getInt(sharedPreferences, context, R.string.min_recording_interval_key, MIN_RECORDING_INTERVAL);
public static Duration getMinRecordingInterval(SharedPreferences sharedPreferences, Context context) {
final Duration MIN_RECORDING_INTERVAL = getMinRecordingIntervalDefault(context);
Duration interval = Duration.ofSeconds(getInt(sharedPreferences, context, R.string.min_recording_interval_key, (int) MIN_RECORDING_INTERVAL.getSeconds()));
if (interval.isNegative()) {
// Due to removal of adaptive listener policy; used -1, and -2
interval = getMinRecordingIntervalDefault(context);
}
return interval;
}
public static int getMinRecordingIntervalAdaptAccuracy(Context context) {
return Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_adapt_accuracy));
}
public static int getMinRecordingIntervalAdaptBatteryLife(Context context) {
return Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_adapt_battery_life));
}
public static int getMinRecordingIntervalDefault(Context context) {
return Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_default));
public static Duration getMinRecordingIntervalDefault(Context context) {
return Duration.ofSeconds(Integer.parseInt(context.getResources().getString(R.string.min_recording_interval_default)));
}
public static Distance getThresholdHorizontalAccuracy(SharedPreferences sharedPreferences, Context context) {