Commit 39fee9ba authored by Bartek Fabiszewski's avatar Bartek Fabiszewski
Browse files

Merge branch 'master' into android_11

# Conflicts:
#	app/build.gradle
parents dd65bf2a 66379a10
Loading
Loading
Loading
Loading
+6 −3
Original line number Diff line number Diff line
@@ -13,11 +13,14 @@ script:
after_success:
  - |
    if [ ! -z "$TRANSIFEX_PASSWORD" ]; then
      pip install --user virtualenv
      virtualenv ~/env
      source ~/env/bin/activate
      pip install transifex-client
      echo -e "[https://www.transifex.com]\nhostname = https://www.transifex.com\nusername = api\npassword = ${TRANSIFEX_PASSWORD}\n" > ~/.transifexrc
      python -m pip install --upgrade pip
      python -m pip install --upgrade setuptools
      python -m pip install --upgrade requests[security] urllib3
      python -m pip install --upgrade transifex-client
      echo -e "[https://www.transifex.com]\napi_hostname = https://api.transifex.com\nhostname = https://www.transifex.com\nusername = api\npassword = ${TRANSIFEX_PASSWORD}\n" > ~/.transifexrc
      tx --version
      tx push -s --no-interactive
    fi
after_failure:
+11 −0
Original line number Diff line number Diff line
@@ -50,6 +50,17 @@ led | tracking | synchronization
  - Tasker (joaomgcd) – System → Send intent. Fields `Action`, `Package`, `Class` as above and `Extra` field eg. `command:start logger`
- command line: `am broadcast -a net.fabiszewski.ulogger.intent.action.COMMAND -e "command" "start logger" net.fabiszewski.ulogger net.fabiszewski.ulogger.ExternalCommandReceiver`

## App settings guidelines
Finding the optimized settings for your practice can be a bit complex and may require you to do a lot of testing.
As a first approach, here are some parameters that offer a good compromise between precision and the number of points acquired by your server.

| Activity | Time | Distance | Accuracy | Provider |
|---|---|---|---|---|
| **hiking/cycling** | 30 seconds | 100m | 100m | GPS + Network |
| **motorbiking** | 1 minute | 500m | 50m | GPS + Network |

They may not be optimal, depending on your feelings, and you will have to adapt them.

## Contribute translations
[![Translate with transifex](https://img.shields.io/badge/translate-transifex-green.svg)](https://www.transifex.com/bfabiszewski/ulogger/)

+4 −4
Original line number Diff line number Diff line
@@ -17,8 +17,8 @@ android {
        applicationId 'net.fabiszewski.ulogger'
        minSdkVersion 19
        targetSdkVersion 30
        versionCode 302
        versionName '3.2'
        versionCode 304
        versionName '3.4'
    }

    buildTypes {
@@ -45,8 +45,8 @@ android {

dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'androidx.preference:preference:1.1.1'
    implementation 'androidx.exifinterface:exifinterface:1.2.0'
    implementation 'androidx.exifinterface:exifinterface:1.3.2'
    testImplementation 'junit:junit:4.13'
}
+90 −48
Original line number Diff line number Diff line
@@ -25,6 +25,9 @@ import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.preference.PreferenceManager;

import java.util.ArrayList;
import java.util.List;

class LocationHelper {

    private static final String TAG = LocationHelper.class.getSimpleName();
@@ -32,6 +35,13 @@ class LocationHelper {
    private final Context context;
    private final LocationManager locationManager;

    // millis 1999-08-21T23:59:42+00:00
    private static final long FIRST_ROLLOVER_TIMESTAMP = 935279982000L;
    // millis 2019-04-06T23:59:42+00:00
    private static final long SECOND_ROLLOVER_TIMESTAMP = 1554595182000L;
    // 1024 weeks in milliseconds
    private static final long ROLLOVER_MILLIS = 1024 * 7 * 24 * 60 * 60 * 1000L;

    private boolean liveSync = false;
    private int maxAccuracy;
    private float minDistance;
@@ -39,8 +49,7 @@ class LocationHelper {
    // max time tolerance is half min time, but not more that 5 min
    final private long minTimeTolerance = Math.min(minTimeMillis / 2, 5 * 60 * 1000);
    final private long maxTimeMillis = minTimeMillis + minTimeTolerance;
    private boolean useGps;
    private boolean useNet;
    private List<String> userProviders = new ArrayList<>();


    private LocationHelper(@NonNull Context context) {
@@ -72,8 +81,13 @@ class LocationHelper {
        minTimeMillis = Long.parseLong(prefs.getString(SettingsActivity.KEY_MIN_TIME, context.getString(R.string.pref_mintime_default))) * 1000;
        minDistance = Float.parseFloat(prefs.getString(SettingsActivity.KEY_MIN_DISTANCE, context.getString(R.string.pref_mindistance_default)));
        maxAccuracy = Integer.parseInt(prefs.getString(SettingsActivity.KEY_MIN_ACCURACY, context.getString(R.string.pref_minaccuracy_default)));
        useGps = prefs.getBoolean(SettingsActivity.KEY_USE_GPS, providerExists(LocationManager.GPS_PROVIDER));
        useNet = prefs.getBoolean(SettingsActivity.KEY_USE_NET, providerExists(LocationManager.NETWORK_PROVIDER));
        userProviders.clear();
        if (prefs.getBoolean(SettingsActivity.KEY_USE_GPS, providerExists(LocationManager.GPS_PROVIDER))) {
            userProviders.add(LocationManager.GPS_PROVIDER);
        }
        if (prefs.getBoolean(SettingsActivity.KEY_USE_NET, providerExists(LocationManager.NETWORK_PROVIDER))) {
            userProviders.add(LocationManager.NETWORK_PROVIDER);
        }
        liveSync = prefs.getBoolean(SettingsActivity.KEY_LIVE_SYNC, false);
    }

@@ -107,53 +121,38 @@ class LocationHelper {
     * @throws LoggerException Exception on permission denied or all providers disabled
     */
    void requestSingleUpdate(@NonNull LocationListener listener, @Nullable Looper looper) throws LoggerException {
        int errorCode = LoggerException.E_DISABLED;
        if (useNet) {
            try {
                requestProviderUpdates(LocationManager.NETWORK_PROVIDER, listener, looper, true);
                errorCode = LoggerException.E_OK;
            } catch (LoggerException e) {
                errorCode = e.getCode();
            }
        }
        if (useGps) {
            try {
                requestProviderUpdates(LocationManager.GPS_PROVIDER, listener, looper, true);
                errorCode = LoggerException.E_OK;
            } catch (LoggerException e) {
                errorCode = e.getCode();
            }
        }
        if (errorCode != LoggerException.E_OK) {
            throw new LoggerException(errorCode);
        }
        requestAllProvidersUpdates(listener, looper, true);
    }

    /**
     * Request location updates for user selected providers
     * @param listener Listener
     * @param looper Looper
     * @throws LoggerException Exception on permission denied or all providers disabled
     * @throws LoggerException Exception on all requested providers failure
     */
    void requestLocationUpdates(@NonNull LocationListener listener, @Nullable Looper looper) throws LoggerException {
        int errorCode = LoggerException.E_DISABLED;
        if (useNet) {
            try {
                requestProviderUpdates(LocationManager.NETWORK_PROVIDER, listener, looper, false);
                errorCode = LoggerException.E_OK;
            } catch (LoggerException e) {
                errorCode = e.getCode();
            }
        requestAllProvidersUpdates(listener, looper, false);
    }
        if (useGps) {

    /**
     * Request location updates for user selected providers
     * @param listener Listener
     * @param looper Looper
     * @param singleShot Request single update if true
     * @throws LoggerException Exception on all requested providers failure
     */
    private void requestAllProvidersUpdates(@NonNull LocationListener listener, @Nullable Looper looper, boolean singleShot) throws LoggerException {
        List<Integer> results = new ArrayList<>();
        for (String provider : userProviders) {
            try {
                requestProviderUpdates(LocationManager.GPS_PROVIDER, listener, looper, false);
                errorCode = LoggerException.E_OK;
                requestProviderUpdates(provider, listener, looper, singleShot);
                results.add(LoggerException.E_OK);
            } catch (LoggerException e) {
                errorCode = e.getCode();
                results.add(e.getCode());
            }
        }
        if (errorCode != LoggerException.E_OK) {
        if (!results.contains(LoggerException.E_OK)) {
            int errorCode = results.isEmpty() ? LoggerException.E_DISABLED : results.get(0);
            throw new LoggerException(errorCode);
        }
    }
@@ -164,18 +163,18 @@ class LocationHelper {
     * @param listener Listener
     * @param looper Looper
     * @param singleShot Request single update if true
     * @throws LoggerException Exception on permission denied or all providers disabled
     * @throws LoggerException Exception on permission denied or provider disabled
     */
    private void requestProviderUpdates(@NonNull String provider, @NonNull LocationListener listener, @Nullable Looper looper, boolean singleShot) throws LoggerException {
        if (Logger.DEBUG) { Log.d(TAG, "[requestProviderUpdates: " + provider + " (" + singleShot + ")]"); }
        try {
            if (locationManager.isProviderEnabled(provider)) {
                if (singleShot) {
                    locationManager.requestSingleUpdate(provider, listener, looper);
                } else {
            if (!singleShot) {
                // request even if provider is disabled to allow users re-enable it later
                locationManager.requestLocationUpdates(provider, minTimeMillis, minDistance, listener, looper);
            } else if (locationManager.isProviderEnabled(provider)) {
                locationManager.requestSingleUpdate(provider, listener, looper);
            }
                if (Logger.DEBUG) { Log.d(TAG, "[requestProviderUpdates success: " + provider + " (" + singleShot + ")]"); }
            } else {
            if (!locationManager.isProviderEnabled(provider)) {
                if (Logger.DEBUG) { Log.d(TAG, "[requestProviderUpdates disabled: " + provider + " (" + singleShot + ")]"); }
                throw new LoggerException("Provider disabled", LoggerException.E_DISABLED);
            }
@@ -194,6 +193,19 @@ class LocationHelper {
        locationManager.removeUpdates(listener);
    }

    /**
     * Is any of user location providers enabled
     * @return True if enabled
     */
    boolean hasEnabledProviders() {
        for (String provider : userProviders) {
            if (locationManager.isProviderEnabled(provider)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Check location accuracy meets user criteria
     * @param location Location
@@ -206,6 +218,22 @@ class LocationHelper {
        return ret;
    }

    /**
     * Check location distance meets user criteria
     * @param location Current location
     * @param lastLocation Previous location
     * @return True if location distance within limit
     */
    boolean hasRequiredDistance(@NonNull Location location, @Nullable Location lastLocation) {
        if (lastLocation == null) {
            return true;
        }
        float distance = location.distanceTo(lastLocation);
        boolean ret = distance >= minDistance;
        if (Logger.DEBUG) { Log.d(TAG, "[hasRequiredDistance: " + ret + "]"); }
        return ret;
    }

    /**
     * Check location time meets user criteria when compared to current time
     * @param location Location
@@ -249,6 +277,20 @@ class LocationHelper {
        return liveSync;
    }


    /**
     * Fix GPS week count rollover bug if needed
     * https://galileognss.eu/gps-week-number-rollover-april-6-2019/
     * @param location Location
     */
    static void handleRolloverBug(@NonNull Location location) {
        long gpsTime = location.getTime();
        if (gpsTime > FIRST_ROLLOVER_TIMESTAMP && gpsTime < SECOND_ROLLOVER_TIMESTAMP) {
            if (Logger.DEBUG) { Log.d(TAG, "[Fixing GPS rollover bug: " + gpsTime + "]"); }
            location.setTime(gpsTime + ROLLOVER_MILLIS);
        }
    }

    /**
     * Logger exceptions
     */
+11 −5
Original line number Diff line number Diff line
@@ -90,6 +90,7 @@ public class LoggerService extends Service {
        looper = thread.getLooper();

        try {
            locationHelper.updatePreferences();
            locationHelper.requestLocationUpdates(locationListener, looper);
            setRunning(true);
            sendBroadcast(BROADCAST_LOCATION_STARTED);
@@ -153,7 +154,6 @@ public class LoggerService extends Service {
                // no valid providers after preferences update
                stopSelf();
            }

        }
    }

@@ -190,7 +190,6 @@ public class LoggerService extends Service {
            thread.interrupt();
            thread = null;
        }

    }

    @Override
@@ -301,6 +300,8 @@ public class LoggerService extends Service {
        public void onLocationChanged(@NonNull Location location) {
            if (Logger.DEBUG) { Log.d(TAG, "[location changed: " + location + "]"); }

            LocationHelper.handleRolloverBug(location);

            if (meetsCriteria(location)) {
                lastLocation = location;
                DbAccess.writeLocation(LoggerService.this, location);
@@ -317,6 +318,10 @@ public class LoggerService extends Service {
         * @return True if matches
         */
        private boolean meetsCriteria(Location location) {
            // skip if distance is below user criterion
            if (!locationHelper.hasRequiredDistance(location, lastLocation)) {
                return false;
            }
            // accuracy radius too high
            if (!locationHelper.hasRequiredAccuracy(location)) {
                if (Logger.DEBUG) { Log.d(TAG, "[location accuracy above limit: " + location.getAccuracy() + "]"); }
@@ -354,6 +359,9 @@ public class LoggerService extends Service {
            } else if (provider.equals(LocationManager.NETWORK_PROVIDER)) {
                sendBroadcast(BROADCAST_LOCATION_NETWORK_DISABLED);
            }
            if (!locationHelper.hasEnabledProviders()) {
                sendBroadcast(BROADCAST_LOCATION_DISABLED);
            }
        }

        /**
@@ -373,8 +381,6 @@ public class LoggerService extends Service {

        @SuppressWarnings({"deprecation", "RedundantSuppression"})
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) {

        }
        public void onStatusChanged(String provider, int status, Bundle extras) { }
    }
}
Loading