checkpoint
This commit is contained in:
		
							parent
							
								
									df77b089ac
								
							
						
					
					
						commit
						04fa76249b
					
				
					 7 changed files with 197 additions and 191 deletions
				
			
		|  | @ -58,7 +58,7 @@ class MapFragment : Fragment() | |||
|         // https://gist.github.com/Dvik/a3de88d39da9d1d6d175025a56c5e797#file-viewextension-kt and | ||||
|         // https://proandroiddev.com/android-full-screen-ui-with-transparent-status-bar-ef52f3adde63 | ||||
|         // get current best location | ||||
|         currentBestLocation = LocationHelper.getLastKnownLocation(activity as Context) | ||||
|         currentBestLocation = getLastKnownLocation(activity as Context) | ||||
|         // get saved tracking state | ||||
|         trackingState = PreferencesHelper.loadTrackingState() | ||||
|         requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); | ||||
|  |  | |||
|  | @ -20,7 +20,9 @@ import YesNoDialog | |||
| import android.content.ClipData | ||||
| import android.content.ClipboardManager | ||||
| import android.content.Context | ||||
| import android.content.SharedPreferences | ||||
| import android.os.Bundle | ||||
| import android.util.Log | ||||
| import android.view.View | ||||
| import android.widget.Toast | ||||
| import androidx.preference.* | ||||
|  | @ -118,6 +120,10 @@ class SettingsFragment : PreferenceFragmentCompat(), YesNoDialog.YesNoDialogList | |||
|         preferenceDeviceID.summary = getString(R.string.pref_device_id_summary) + "\n" + PreferencesHelper.load_device_id() | ||||
|         preferenceDeviceID.setDefaultValue(random_device_id()) | ||||
|         preferenceCategoryGeneral.contains(preferenceDeviceID) | ||||
|         preferenceDeviceID.setOnPreferenceChangeListener { preference, newValue -> | ||||
|             preferenceDeviceID.summary = getString(R.string.pref_device_id_summary) + "\n" + newValue | ||||
|             return@setOnPreferenceChangeListener true | ||||
|         } | ||||
|         screen.addPreference(preferenceDeviceID) | ||||
| 
 | ||||
|         val preferenceCategoryAbout: PreferenceCategory = PreferenceCategory(context) | ||||
|  |  | |||
|  | @ -57,7 +57,7 @@ class TrackerService: Service(), SensorEventListener | |||
|     var device_id: String = random_device_id() | ||||
|     var recording_started: Date = GregorianCalendar.getInstance().time | ||||
|     var commitInterval: Int = Keys.COMMIT_INTERVAL | ||||
|     var currentBestLocation: Location = LocationHelper.getDefaultLocation() | ||||
|     var currentBestLocation: Location = getDefaultLocation() | ||||
|     var lastCommit: Date = Keys.DEFAULT_DATE | ||||
|     var stepCountOffset: Float = 0f | ||||
|     lateinit var track: Track | ||||
|  | @ -74,7 +74,6 @@ class TrackerService: Service(), SensorEventListener | |||
|     private lateinit var gpsLocationListener: LocationListener | ||||
|     private lateinit var networkLocationListener: LocationListener | ||||
| 
 | ||||
|     /* Adds a GPS location listener to location manager */ | ||||
|     private fun addGpsLocationListener() | ||||
|     { | ||||
|         if (gpsLocationListenerRegistered) | ||||
|  | @ -83,7 +82,7 @@ class TrackerService: Service(), SensorEventListener | |||
|             return | ||||
|         } | ||||
| 
 | ||||
|         gpsProviderActive = LocationHelper.isGpsEnabled(locationManager) | ||||
|         gpsProviderActive = isGpsEnabled(locationManager) | ||||
|         if (! gpsProviderActive) | ||||
|         { | ||||
|             LogHelper.w(TAG, "Device GPS is not enabled.") | ||||
|  | @ -107,7 +106,6 @@ class TrackerService: Service(), SensorEventListener | |||
|         LogHelper.v(TAG, "Added GPS location listener.") | ||||
|     } | ||||
| 
 | ||||
|     /* Adds a Network location listener to location manager */ | ||||
|     private fun addNetworkLocationListener() | ||||
|     { | ||||
|         if (gpsOnly) | ||||
|  | @ -122,7 +120,7 @@ class TrackerService: Service(), SensorEventListener | |||
|             return | ||||
|         } | ||||
| 
 | ||||
|         networkProviderActive = LocationHelper.isNetworkEnabled(locationManager) | ||||
|         networkProviderActive = isNetworkEnabled(locationManager) | ||||
|         if (!networkProviderActive) | ||||
|         { | ||||
|             LogHelper.w(TAG, "Unable to add Network location listener.") | ||||
|  | @ -151,7 +149,7 @@ class TrackerService: Service(), SensorEventListener | |||
|         return object : LocationListener { | ||||
|             override fun onLocationChanged(location: Location) | ||||
|             { | ||||
|                 if (LocationHelper.isBetterLocation(location, currentBestLocation)) { | ||||
|                 if (isBetterLocation(location, currentBestLocation)) { | ||||
|                     currentBestLocation = location | ||||
|                 } | ||||
|             } | ||||
|  | @ -159,16 +157,16 @@ class TrackerService: Service(), SensorEventListener | |||
|             { | ||||
|                 LogHelper.v(TAG, "onProviderEnabled $provider") | ||||
|                 when (provider) { | ||||
|                     LocationManager.GPS_PROVIDER -> gpsProviderActive = LocationHelper.isGpsEnabled(locationManager) | ||||
|                     LocationManager.NETWORK_PROVIDER -> networkProviderActive = LocationHelper.isNetworkEnabled(locationManager) | ||||
|                     LocationManager.GPS_PROVIDER -> gpsProviderActive = isGpsEnabled(locationManager) | ||||
|                     LocationManager.NETWORK_PROVIDER -> networkProviderActive = isNetworkEnabled(locationManager) | ||||
|                 } | ||||
|             } | ||||
|             override fun onProviderDisabled(provider: String) | ||||
|             { | ||||
|                 LogHelper.v(TAG, "onProviderDisabled $provider") | ||||
|                 when (provider) { | ||||
|                     LocationManager.GPS_PROVIDER -> gpsProviderActive = LocationHelper.isGpsEnabled(locationManager) | ||||
|                     LocationManager.NETWORK_PROVIDER -> networkProviderActive = LocationHelper.isNetworkEnabled(locationManager) | ||||
|                     LocationManager.GPS_PROVIDER -> gpsProviderActive = isGpsEnabled(locationManager) | ||||
|                     LocationManager.NETWORK_PROVIDER -> networkProviderActive = isNetworkEnabled(locationManager) | ||||
|                 } | ||||
|             } | ||||
|             override fun onStatusChanged(p0: String?, p1: Int, p2: Bundle?) | ||||
|  | @ -179,7 +177,8 @@ class TrackerService: Service(), SensorEventListener | |||
|     } | ||||
| 
 | ||||
|     /* Displays or updates notification */ | ||||
|     private fun displayNotification(): Notification { | ||||
|     private fun displayNotification(): Notification | ||||
|     { | ||||
|         val notification: Notification = notificationHelper.createNotification( | ||||
|             trackingState, | ||||
|             iso8601(GregorianCalendar.getInstance().time) | ||||
|  | @ -189,7 +188,8 @@ class TrackerService: Service(), SensorEventListener | |||
|     } | ||||
| 
 | ||||
|     /* Overrides onAccuracyChanged from SensorEventListener */ | ||||
|     override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) { | ||||
|     override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) | ||||
|     { | ||||
|         LogHelper.v(TAG, "Accuracy changed: $accuracy") | ||||
|     } | ||||
| 
 | ||||
|  | @ -220,24 +220,24 @@ class TrackerService: Service(), SensorEventListener | |||
|         sensorManager = this.getSystemService(Context.SENSOR_SERVICE) as SensorManager | ||||
|         notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager | ||||
|         notificationHelper = NotificationHelper(this) | ||||
|         gpsProviderActive = LocationHelper.isGpsEnabled(locationManager) | ||||
|         networkProviderActive = LocationHelper.isNetworkEnabled(locationManager) | ||||
|         gpsProviderActive = isGpsEnabled(locationManager) | ||||
|         networkProviderActive = isNetworkEnabled(locationManager) | ||||
|         gpsLocationListener = createLocationListener() | ||||
|         networkLocationListener = createLocationListener() | ||||
|         trackingState = PreferencesHelper.loadTrackingState() | ||||
|         currentBestLocation = LocationHelper.getLastKnownLocation(this) | ||||
|         currentBestLocation = getLastKnownLocation(this) | ||||
|         PreferencesHelper.registerPreferenceChangeListener(sharedPreferenceChangeListener) | ||||
|     } | ||||
| 
 | ||||
|     /* Overrides onDestroy from Service */ | ||||
|     override fun onDestroy() { | ||||
|         LogHelper.i("VOUSSOIR", "TrackerService.onDestroy.") | ||||
|         super.onDestroy() | ||||
|         LogHelper.i(TAG, "onDestroy called.") | ||||
|         if (trackingState == Keys.STATE_TRACKING_ACTIVE) | ||||
|         { | ||||
|             pauseTracking() | ||||
|         } | ||||
|         stopForeground(true) | ||||
|         stopForeground(STOP_FOREGROUND_REMOVE) | ||||
|         notificationManager.cancel(Keys.TRACKER_SERVICE_NOTIFICATION_ID) // this call was not necessary prior to Android 12 | ||||
|         PreferencesHelper.unregisterPreferenceChangeListener(sharedPreferenceChangeListener) | ||||
|         removeGpsLocationListener() | ||||
|  | @ -316,7 +316,6 @@ class TrackerService: Service(), SensorEventListener | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Adds location listeners to location manager */ | ||||
|     fun removeNetworkLocationListener() | ||||
|     { | ||||
|         if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { | ||||
|  | @ -365,15 +364,14 @@ class TrackerService: Service(), SensorEventListener | |||
|         stopForeground(STOP_FOREGROUND_DETACH) | ||||
|     } | ||||
| 
 | ||||
|     /* | ||||
|      * Defines the listener for changes in shared preferences | ||||
|      */ | ||||
|     private val sharedPreferenceChangeListener = SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key -> | ||||
|         when (key) { | ||||
|         when (key) | ||||
|         { | ||||
|             Keys.PREF_GPS_ONLY -> | ||||
|             { | ||||
|                 gpsOnly = PreferencesHelper.loadGpsOnly() | ||||
|                 when (gpsOnly) { | ||||
|                 when (gpsOnly) | ||||
|                 { | ||||
|                     true -> removeNetworkLocationListener() | ||||
|                     false -> addNetworkLocationListener() | ||||
|                 } | ||||
|  | @ -418,12 +416,12 @@ class TrackerService: Service(), SensorEventListener | |||
|             Log.i("VOUSSOIR", "Omitting due to 0,0 location.") | ||||
|             return false | ||||
|         } | ||||
|         if (! LocationHelper.isRecentEnough(location)) | ||||
|         if (! isRecentEnough(location)) | ||||
|         { | ||||
|             Log.i("VOUSSOIR", "Omitting due to not recent enough.") | ||||
|             return false | ||||
|         } | ||||
|         if (! LocationHelper.isAccurateEnough(location, Keys.DEFAULT_THRESHOLD_LOCATION_ACCURACY)) | ||||
|         if (! isAccurateEnough(location, Keys.DEFAULT_THRESHOLD_LOCATION_ACCURACY)) | ||||
|         { | ||||
|             Log.i("VOUSSOIR", "Omitting due to not accurate enough.") | ||||
|             return false | ||||
|  | @ -440,7 +438,7 @@ class TrackerService: Service(), SensorEventListener | |||
|         { | ||||
|             return true | ||||
|         } | ||||
|         if (! LocationHelper.isDifferentEnough(track.trkpts.last().toLocation(), location, omitRests)) | ||||
|         if (! isDifferentEnough(track.trkpts.last().toLocation(), location, omitRests)) | ||||
|         { | ||||
|             Log.i("VOUSSOIR", "Omitting due to too close to previous.") | ||||
|             return false | ||||
|  |  | |||
|  | @ -17,7 +17,7 @@ | |||
| package org.y20k.trackbook | ||||
| 
 | ||||
| import android.location.Location | ||||
| import org.y20k.trackbook.helpers.LocationHelper | ||||
| import org.y20k.trackbook.helpers.getNumberOfSatellites | ||||
| import java.util.* | ||||
| 
 | ||||
| /* | ||||
|  | @ -42,7 +42,7 @@ data class Trkpt( | |||
|         altitude=location.altitude, | ||||
|         accuracy=location.accuracy, | ||||
|         time=location.time, | ||||
|         numberSatellites=LocationHelper.getNumberOfSatellites(location), | ||||
|         numberSatellites=getNumberOfSatellites(location), | ||||
|     ) | ||||
| 
 | ||||
|     /* Converts WayPoint into Location */ | ||||
|  |  | |||
|  | @ -27,159 +27,163 @@ import androidx.core.content.ContextCompat | |||
| import org.y20k.trackbook.Keys | ||||
| import kotlin.math.pow | ||||
| 
 | ||||
| /* | ||||
|  * Keys object | ||||
|  */ | ||||
| object LocationHelper { | ||||
| 
 | ||||
|     /* Define log tag */ | ||||
|     private val TAG: String = LogHelper.makeLogTag(LocationHelper::class.java) | ||||
| 
 | ||||
|     /* Get default location */ | ||||
|     fun getDefaultLocation(): Location { | ||||
|         val defaultLocation: Location = Location(LocationManager.NETWORK_PROVIDER) | ||||
|         defaultLocation.latitude = Keys.DEFAULT_LATITUDE | ||||
|         defaultLocation.longitude = Keys.DEFAULT_LONGITUDE | ||||
|         defaultLocation.accuracy = Keys.DEFAULT_ACCURACY | ||||
|         defaultLocation.altitude = Keys.DEFAULT_ALTITUDE | ||||
|         defaultLocation.time = Keys.DEFAULT_DATE.time | ||||
|         return defaultLocation | ||||
|     } | ||||
| 
 | ||||
|     /* Tries to return the last location that the system has stored */ | ||||
|     fun getLastKnownLocation(context: Context): Location { | ||||
|         // get last location that Trackbook has stored | ||||
|         var lastKnownLocation: Location = PreferencesHelper.loadCurrentBestLocation() | ||||
|         // try to get the last location the system has stored - it is probably more recent | ||||
|         if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { | ||||
|             val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager | ||||
|             val lastKnownLocationGps: Location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) ?: lastKnownLocation | ||||
|             val lastKnownLocationNetwork: Location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER) ?: lastKnownLocation | ||||
|             when (isBetterLocation(lastKnownLocationGps, lastKnownLocationNetwork)) { | ||||
|                 true -> lastKnownLocation = lastKnownLocationGps | ||||
|                 false -> lastKnownLocation = lastKnownLocationNetwork | ||||
|             } | ||||
|         } | ||||
|         return lastKnownLocation | ||||
|     } | ||||
| 
 | ||||
|     /* Determines whether one location reading is better than the current location fix */ | ||||
|     fun isBetterLocation(location: Location, currentBestLocation: Location?): Boolean | ||||
|     { | ||||
|         // Credit: https://developer.android.com/guide/topics/location/strategies.html#BestEstimate | ||||
| 
 | ||||
|         if (currentBestLocation == null) { | ||||
|             // a new location is always better than no location | ||||
|             return true | ||||
|         } | ||||
| 
 | ||||
|         // check whether the new location fix is newer or older | ||||
|         val timeDelta: Long = location.time - currentBestLocation.time | ||||
|         val isSignificantlyNewer: Boolean = timeDelta > Keys.SIGNIFICANT_TIME_DIFFERENCE | ||||
|         val isSignificantlyOlder:Boolean = timeDelta < -Keys.SIGNIFICANT_TIME_DIFFERENCE | ||||
| 
 | ||||
|         when { | ||||
|             // if it's been more than two minutes since the current location, use the new location because the user has likely moved | ||||
|             isSignificantlyNewer -> return true | ||||
|             // if the new location is more than two minutes older, it must be worse | ||||
|             isSignificantlyOlder -> return false | ||||
|         } | ||||
| 
 | ||||
|         // check whether the new location fix is more or less accurate | ||||
|         val isNewer: Boolean = timeDelta > 0L | ||||
|         val accuracyDelta: Float = location.accuracy - currentBestLocation.accuracy | ||||
|         val isLessAccurate: Boolean = accuracyDelta > 0f | ||||
|         val isMoreAccurate: Boolean = accuracyDelta < 0f | ||||
|         val isSignificantlyLessAccurate: Boolean = accuracyDelta > 200f | ||||
| 
 | ||||
|         // check if the old and new location are from the same provider | ||||
|         val isFromSameProvider: Boolean = location.provider == currentBestLocation.provider | ||||
| 
 | ||||
|         // determine location quality using a combination of timeliness and accuracy | ||||
|         return when { | ||||
|             isMoreAccurate -> true | ||||
|             isNewer && !isLessAccurate -> true | ||||
|             isNewer && !isSignificantlyLessAccurate && isFromSameProvider -> true | ||||
|             else -> false | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Checks if GPS location provider is available and enabled */ | ||||
|     fun isGpsEnabled(locationManager: LocationManager): Boolean | ||||
|     { | ||||
|         if (locationManager.allProviders.contains(LocationManager.GPS_PROVIDER)) | ||||
|         { | ||||
|             return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) | ||||
|         } | ||||
|         else | ||||
|         { | ||||
|             return false | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /* Checks if Network location provider is available and enabled */ | ||||
|     fun isNetworkEnabled(locationManager: LocationManager): Boolean { | ||||
|         if (locationManager.allProviders.contains(LocationManager.NETWORK_PROVIDER)) { | ||||
|             return locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) | ||||
|         } else { | ||||
|             return false | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     /* Checks if given location is new */ | ||||
|     fun isRecentEnough(location: Location): Boolean { | ||||
|         val locationAge: Long = SystemClock.elapsedRealtimeNanos() - location.elapsedRealtimeNanos | ||||
|         return locationAge < Keys.DEFAULT_THRESHOLD_LOCATION_AGE | ||||
|     } | ||||
| 
 | ||||
|     /* Checks if given location is accurate */ | ||||
|     fun isAccurateEnough(location: Location, locationAccuracyThreshold: Int): Boolean { | ||||
|         val isAccurate: Boolean | ||||
|         when (location.provider) { | ||||
|             LocationManager.GPS_PROVIDER -> isAccurate = location.accuracy < locationAccuracyThreshold | ||||
|             else -> isAccurate = location.accuracy < locationAccuracyThreshold + 10 // a bit more relaxed when location comes from network provider | ||||
|         } | ||||
|         return isAccurate | ||||
|     } | ||||
| 
 | ||||
|     /* Checks if given location is different enough compared to previous location */ | ||||
|     fun isDifferentEnough(previousLocation: Location?, location: Location, omitRests: Boolean): Boolean { | ||||
|         // check if previous location is (not) available | ||||
|         if (previousLocation == null) | ||||
|         { | ||||
|             return true | ||||
|         } | ||||
| 
 | ||||
|         if (! omitRests) | ||||
|         { | ||||
|             return true | ||||
|         } | ||||
|         // location.accuracy is given as 1 standard deviation, with a 68% chance | ||||
|         // that the true position is within a circle of this radius. | ||||
|         // These formulas determine if the difference between the last point and | ||||
|         // new point is statistically significant. | ||||
|         val accuracy: Float = if (location.accuracy != 0.0f) location.accuracy else Keys.DEFAULT_THRESHOLD_DISTANCE | ||||
|         val previousAccuracy: Float = if (previousLocation.accuracy != 0.0f) previousLocation.accuracy else Keys.DEFAULT_THRESHOLD_DISTANCE | ||||
|         val accuracyDelta: Double = Math.sqrt((accuracy.pow(2) + previousAccuracy.pow(2)).toDouble()) | ||||
|         val distance: Float = previousLocation.distanceTo(location) | ||||
| 
 | ||||
|         // With 1*accuracyDelta we have 68% confidence that the points are | ||||
|         // different. We can multiply this number to increase confidence but | ||||
|         // decrease point recording frequency if needed. | ||||
|         return distance > accuracyDelta | ||||
|     } | ||||
| 
 | ||||
|     /* Get number of satellites from Location extras */ | ||||
|     fun getNumberOfSatellites(location: Location): Int { | ||||
|         val numberOfSatellites: Int | ||||
|         val extras: Bundle? = location.extras | ||||
|         if (extras != null && extras.containsKey("satellites")) { | ||||
|             numberOfSatellites = extras.getInt("satellites", 0) | ||||
|         } else { | ||||
|             numberOfSatellites = 0 | ||||
|         } | ||||
|         return numberOfSatellites | ||||
|     } | ||||
| 
 | ||||
| /* Get default location */ | ||||
| fun getDefaultLocation(): Location | ||||
| { | ||||
|     val defaultLocation: Location = Location(LocationManager.NETWORK_PROVIDER) | ||||
|     defaultLocation.latitude = Keys.DEFAULT_LATITUDE | ||||
|     defaultLocation.longitude = Keys.DEFAULT_LONGITUDE | ||||
|     defaultLocation.accuracy = Keys.DEFAULT_ACCURACY | ||||
|     defaultLocation.altitude = Keys.DEFAULT_ALTITUDE | ||||
|     defaultLocation.time = Keys.DEFAULT_DATE.time | ||||
|     return defaultLocation | ||||
| } | ||||
| 
 | ||||
| /* Tries to return the last location that the system has stored */ | ||||
| fun getLastKnownLocation(context: Context): Location | ||||
| { | ||||
|     // get last location that Trackbook has stored | ||||
|     var lastKnownLocation: Location = PreferencesHelper.loadCurrentBestLocation() | ||||
|     // try to get the last location the system has stored - it is probably more recent | ||||
|     if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { | ||||
|         val locationManager = context.getSystemService(Context.LOCATION_SERVICE) as LocationManager | ||||
|         val lastKnownLocationGps: Location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER) ?: lastKnownLocation | ||||
|         val lastKnownLocationNetwork: Location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER) ?: lastKnownLocation | ||||
|         when (isBetterLocation(lastKnownLocationGps, lastKnownLocationNetwork)) { | ||||
|             true -> lastKnownLocation = lastKnownLocationGps | ||||
|             false -> lastKnownLocation = lastKnownLocationNetwork | ||||
|         } | ||||
|     } | ||||
|     return lastKnownLocation | ||||
| } | ||||
| 
 | ||||
| /* Determines whether one location reading is better than the current location fix */ | ||||
| fun isBetterLocation(location: Location, currentBestLocation: Location?): Boolean | ||||
| { | ||||
|     // Credit: https://developer.android.com/guide/topics/location/strategies.html#BestEstimate | ||||
| 
 | ||||
|     if (currentBestLocation == null) | ||||
|     { | ||||
|         // a new location is always better than no location | ||||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     // check whether the new location fix is newer or older | ||||
|     val timeDelta: Long = location.time - currentBestLocation.time | ||||
|     val isSignificantlyNewer: Boolean = timeDelta > Keys.SIGNIFICANT_TIME_DIFFERENCE | ||||
|     val isSignificantlyOlder:Boolean = timeDelta < -Keys.SIGNIFICANT_TIME_DIFFERENCE | ||||
| 
 | ||||
|     when { | ||||
|         // if it's been more than two minutes since the current location, use the new location because the user has likely moved | ||||
|         isSignificantlyNewer -> return true | ||||
|         // if the new location is more than two minutes older, it must be worse | ||||
|         isSignificantlyOlder -> return false | ||||
|     } | ||||
| 
 | ||||
|     // check whether the new location fix is more or less accurate | ||||
|     val isNewer: Boolean = timeDelta > 0L | ||||
|     val accuracyDelta: Float = location.accuracy - currentBestLocation.accuracy | ||||
|     val isLessAccurate: Boolean = accuracyDelta > 0f | ||||
|     val isMoreAccurate: Boolean = accuracyDelta < 0f | ||||
|     val isSignificantlyLessAccurate: Boolean = accuracyDelta > 200f | ||||
| 
 | ||||
|     // check if the old and new location are from the same provider | ||||
|     val isFromSameProvider: Boolean = location.provider == currentBestLocation.provider | ||||
| 
 | ||||
|     // determine location quality using a combination of timeliness and accuracy | ||||
|     return when { | ||||
|         isMoreAccurate -> true | ||||
|         isNewer && !isLessAccurate -> true | ||||
|         isNewer && !isSignificantlyLessAccurate && isFromSameProvider -> true | ||||
|         else -> false | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Checks if GPS location provider is available and enabled */ | ||||
| fun isGpsEnabled(locationManager: LocationManager): Boolean | ||||
| { | ||||
|     if (locationManager.allProviders.contains(LocationManager.GPS_PROVIDER)) | ||||
|     { | ||||
|         return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER) | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         return false | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Checks if Network location provider is available and enabled */ | ||||
| fun isNetworkEnabled(locationManager: LocationManager): Boolean | ||||
| { | ||||
|     if (locationManager.allProviders.contains(LocationManager.NETWORK_PROVIDER)) | ||||
|     { | ||||
|         return locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER) | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         return false | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* Checks if given location is new */ | ||||
| fun isRecentEnough(location: Location): Boolean | ||||
| { | ||||
|     val locationAge: Long = SystemClock.elapsedRealtimeNanos() - location.elapsedRealtimeNanos | ||||
|     return locationAge < Keys.DEFAULT_THRESHOLD_LOCATION_AGE | ||||
| } | ||||
| 
 | ||||
| /* Checks if given location is accurate */ | ||||
| fun isAccurateEnough(location: Location, locationAccuracyThreshold: Int): Boolean | ||||
| { | ||||
|     if (location.provider == LocationManager.GPS_PROVIDER) | ||||
|     { | ||||
|         return location.accuracy < locationAccuracyThreshold | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         return location.accuracy < locationAccuracyThreshold + 10 // a bit more relaxed when location comes from network provider | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| /* Checks if given location is different enough compared to previous location */ | ||||
| fun isDifferentEnough(previousLocation: Location?, location: Location, omitRests: Boolean): Boolean | ||||
| { | ||||
|     // check if previous location is (not) available | ||||
|     if (previousLocation == null) | ||||
|     { | ||||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     if (! omitRests) | ||||
|     { | ||||
|         return true | ||||
|     } | ||||
| 
 | ||||
|     // location.accuracy is given as 1 standard deviation, with a 68% chance | ||||
|     // that the true position is within a circle of this radius. | ||||
|     // These formulas determine if the difference between the last point and | ||||
|     // new point is statistically significant. | ||||
|     val accuracy: Float = if (location.accuracy != 0.0f) location.accuracy else Keys.DEFAULT_THRESHOLD_DISTANCE | ||||
|     val previousAccuracy: Float = if (previousLocation.accuracy != 0.0f) previousLocation.accuracy else Keys.DEFAULT_THRESHOLD_DISTANCE | ||||
|     val accuracyDelta: Double = Math.sqrt((accuracy.pow(2) + previousAccuracy.pow(2)).toDouble()) | ||||
|     val distance: Float = previousLocation.distanceTo(location) | ||||
| 
 | ||||
|     // With 1*accuracyDelta we have 68% confidence that the points are | ||||
|     // different. We can multiply this number to increase confidence but | ||||
|     // decrease point recording frequency if needed. | ||||
|     return distance > accuracyDelta | ||||
| } | ||||
| 
 | ||||
| /* Get number of satellites from Location extras */ | ||||
| fun getNumberOfSatellites(location: Location): Int | ||||
| { | ||||
|     val numberOfSatellites: Int | ||||
|     val extras: Bundle? = location.extras | ||||
|     if (extras != null && extras.containsKey("satellites")) { | ||||
|         numberOfSatellites = extras.getInt("satellites", 0) | ||||
|     } else { | ||||
|         numberOfSatellites = 0 | ||||
|     } | ||||
|     return numberOfSatellites | ||||
| } | ||||
|  | @ -134,8 +134,6 @@ fun createSpecialMakersTrackOverlay(context: Context, map_view: MapView, track: | |||
|     map_view.overlays.add(createOverlay(context, overlayItems)) | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| fun createOverlayItem(context: Context, latitude: Double, longitude: Double, accuracy: Float, provider: String, time: Long): OverlayItem | ||||
| { | ||||
|     val title: String = "${context.getString(R.string.marker_description_time)}: ${SimpleDateFormat.getTimeInstance(SimpleDateFormat.MEDIUM, Locale.getDefault()).format(time)}" | ||||
|  |  | |||
|  | @ -65,7 +65,6 @@ data class MapFragmentLayoutHolder( | |||
|     private val trackingState: Int | ||||
| ) | ||||
| { | ||||
|     /* Main class variables */ | ||||
|     val rootView: View | ||||
|     var userInteraction: Boolean = false | ||||
|     val currentLocationButton: FloatingActionButton | ||||
|  | @ -75,12 +74,13 @@ data class MapFragmentLayoutHolder( | |||
|     private var current_location_radius: Polygon = Polygon() | ||||
|     private var currentTrackOverlay: SimpleFastPointOverlay? | ||||
|     private var currentTrackSpecialMarkerOverlay: ItemizedIconOverlay<OverlayItem>? | ||||
|     private val useImperial: Boolean = PreferencesHelper.loadUseImperialUnits() | ||||
|     private var locationErrorBar: Snackbar | ||||
|     private var controller: IMapController | ||||
|     private var zoomLevel: Double | ||||
| 
 | ||||
|     init { | ||||
|     init | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "MapFragmentLayoutHolder.init") | ||||
|         // find views | ||||
|         rootView = inflater.inflate(R.layout.fragment_map, container, false) | ||||
|         mapView = rootView.findViewById(R.id.map) | ||||
|  | @ -164,7 +164,7 @@ data class MapFragmentLayoutHolder( | |||
|     fun markCurrentPosition(location: Location, trackingState: Int = Keys.STATE_TRACKING_STOPPED) | ||||
|     { | ||||
|         Log.i("VOUSSOIR", "MapFragmentLayoutHolder.markCurrentPosition") | ||||
|         val locationIsOld: Boolean = !(LocationHelper.isRecentEnough(location)) | ||||
|         val locationIsOld: Boolean = !(isRecentEnough(location)) | ||||
| 
 | ||||
|         // create marker | ||||
|         val newMarker: Drawable | ||||
|  | @ -228,7 +228,7 @@ data class MapFragmentLayoutHolder( | |||
|             val p = Polygon() | ||||
|             p.points = Polygon.pointsAsCircle(GeoPoint(homepoint.location.latitude, homepoint.location.longitude), homepoint.location.accuracy.toDouble()) | ||||
|             p.fillPaint.color = Color.argb(64, 255, 193, 7) | ||||
|             p.outlinePaint.color = Color.argb(128, 255, 193, 7) | ||||
|             p.outlinePaint.color = Color.argb(0, 0, 0, 0) | ||||
|             map_view.overlays.add(p) | ||||
|         } | ||||
|     } | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue