Skip to content

Commit a58387a

Browse files
committed
Simplify GPS logic
1 parent c980213 commit a58387a

File tree

1 file changed

+52
-99
lines changed
  • app/src/main/java/com/kylecorry/trailsensecore/infrastructure/sensors/gps

1 file changed

+52
-99
lines changed

app/src/main/java/com/kylecorry/trailsensecore/infrastructure/sensors/gps/GPS.kt

Lines changed: 52 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,13 @@ import com.kylecorry.trailsensecore.domain.Accuracy
99
import com.kylecorry.trailsensecore.domain.geo.Coordinate
1010
import com.kylecorry.trailsensecore.infrastructure.sensors.AbstractSensor
1111
import com.kylecorry.trailsensecore.infrastructure.sensors.SensorChecker
12+
import com.kylecorry.trailsensecore.infrastructure.system.PermissionUtils
13+
import java.time.Duration
1214
import java.time.Instant
1315

14-
class GPS(context: Context) : AbstractSensor(), IGPS {
16+
17+
@SuppressLint("MissingPermission")
18+
class GPS(private val context: Context) : AbstractSensor(), IGPS {
1519

1620
override val hasValidReading: Boolean
1721
get() = hadRecentValidReading()
@@ -34,14 +38,14 @@ class GPS(context: Context) : AbstractSensor(), IGPS {
3438
override val speed: Float
3539
get() = _speed
3640

37-
override val altitude: Float
38-
get() = _altitude
39-
4041
override val time: Instant
4142
get() = _time
4243

43-
private val locationManager = context.getSystemService<LocationManager>()
44-
private val sensorChecker = SensorChecker(context)
44+
override val altitude: Float
45+
get() = _altitude
46+
47+
private val locationManager by lazy { context.getSystemService<LocationManager>() }
48+
private val sensorChecker by lazy { SensorChecker(context) }
4549
private val locationListener = SimpleLocationListener { updateLastLocation(it, true) }
4650

4751
private var _altitude = 0f
@@ -54,19 +58,25 @@ class GPS(context: Context) : AbstractSensor(), IGPS {
5458
private var _location = Coordinate.zero
5559

5660
private var lastLocation: Location? = null
57-
private var lastUpdate = 0L
5861

59-
private var fixStart: Long = 0L
60-
private val maxFixTime = 8000L
62+
init {
63+
try {
64+
if (PermissionUtils.isLocationEnabled(context)) {
65+
updateLastLocation(
66+
locationManager?.getLastKnownLocation(LocationManager.GPS_PROVIDER),
67+
false
68+
)
69+
}
70+
} catch (e: Exception) {
71+
// Do nothing
72+
}
73+
}
6174

62-
@SuppressLint("MissingPermission")
6375
override fun startImpl() {
6476
if (!sensorChecker.hasGPS()) {
6577
return
6678
}
6779

68-
fixStart = System.currentTimeMillis()
69-
7080
if (lastLocation == null) {
7181
updateLastLocation(
7282
locationManager?.getLastKnownLocation(LocationManager.GPS_PROVIDER),
@@ -91,104 +101,47 @@ class GPS(context: Context) : AbstractSensor(), IGPS {
91101
return
92102
}
93103

104+
_location = Coordinate(location.latitude, location.longitude)
94105
_time = Instant.ofEpochMilli(location.time)
95-
96-
val satellites = location.extras.getInt("satellites")
97-
val dt = System.currentTimeMillis() - fixStart
98-
99-
if (useNewLocation(lastLocation, location) &&
100-
location.hasAltitude() && location.altitude != 0.0
101-
) {
102-
// Forces an altitude update irrespective of the satellite count - helps when the GPS is being polled in the background
103-
_altitude = location.altitude.toFloat()
104-
}
105-
106-
if (satellites < 4 && dt < maxFixTime) {
107-
return
108-
}
109-
110-
if (!useNewLocation(lastLocation, location)) {
111-
if (notify) notifyListeners()
112-
return
113-
}
114-
115-
fixStart = System.currentTimeMillis()
116-
lastUpdate = fixStart
117-
_satellites = satellites
118-
lastLocation = location
119-
120-
if (location.hasAccuracy()) {
121-
this._accuracy = when {
122-
location.accuracy < 8 -> Accuracy.High
123-
location.accuracy < 16 -> Accuracy.Medium
124-
else -> Accuracy.Low
125-
}
126-
this._horizontalAccuracy = location.accuracy
106+
_satellites =
107+
if (location.extras?.containsKey("satellites") == true) location.extras.getInt("satellites") else 0
108+
_altitude = if (location.hasAltitude()) location.altitude.toFloat() else 0f
109+
val accuracy = if (location.hasAccuracy()) location.accuracy else null
110+
_accuracy = when {
111+
accuracy != null && accuracy < 8 -> Accuracy.High
112+
accuracy != null && accuracy < 16 -> Accuracy.Medium
113+
accuracy != null -> Accuracy.Low
114+
else -> Accuracy.Unknown
127115
}
128-
129-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
130-
if (location.hasVerticalAccuracy()) {
131-
this._verticalAccuracy = location.verticalAccuracyMeters
116+
_horizontalAccuracy = accuracy ?: 0f
117+
_verticalAccuracy =
118+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O && location.hasVerticalAccuracy()) {
119+
location.verticalAccuracyMeters
120+
} else {
121+
null
132122
}
133-
}
134-
135-
if (location.hasSpeed()) {
136-
_speed =
137-
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O && location.hasSpeedAccuracy()) {
138-
if (location.speed < location.speedAccuracyMetersPerSecond * 0.68) {
139-
0f
140-
} else {
141-
location.speed
142-
}
143-
123+
// TODO: Add speed accuracy to IGPS
124+
_speed = if (location.hasSpeed()) {
125+
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O && location.hasSpeedAccuracy()) {
126+
if (location.speed < location.speedAccuracyMetersPerSecond * 0.68) {
127+
0f
144128
} else {
145129
location.speed
146130
}
147-
}
148-
149-
this._location = Coordinate(
150-
location.latitude,
151-
location.longitude
152-
)
153-
154-
if (location.hasAltitude() && location.altitude != 0.0) {
155-
_altitude = location.altitude.toFloat()
131+
} else {
132+
location.speed
133+
}
134+
} else {
135+
0f
156136
}
157137

158138
if (notify) notifyListeners()
159139
}
160140

161141
private fun hadRecentValidReading(): Boolean {
162-
val now = System.currentTimeMillis()
163-
val recentThreshold = 1000 * 60 * 2L
164-
return now - lastUpdate <= recentThreshold
165-
}
166-
167-
private fun useNewLocation(current: Location?, newLocation: Location): Boolean {
168-
// Modified from https://stackoverflow.com/questions/10588982/retrieving-of-satellites-used-in-gps-fix-from-android
169-
if (current == null) {
170-
return true
171-
}
172-
173-
val timeDelta = newLocation.time - current.time
174-
val isSignificantlyNewer: Boolean = timeDelta > 1000 * 60 * 2
175-
val isSignificantlyOlder: Boolean = timeDelta < -1000 * 60 * 2
176-
val isNewer = timeDelta > 0
177-
178-
if (isSignificantlyNewer) {
179-
return true
180-
} else if (isSignificantlyOlder) {
181-
return false
182-
}
183-
184-
val accuracyDelta = (newLocation.accuracy - current.accuracy).toInt()
185-
val isMoreAccurate = accuracyDelta < 0
186-
val isSignificantlyLessAccurate = accuracyDelta > 30
187-
188-
if (isMoreAccurate) {
189-
return true
190-
}
191-
192-
return isNewer && !isSignificantlyLessAccurate
142+
val last = time
143+
val now = Instant.now()
144+
val recentThreshold = Duration.ofMinutes(2)
145+
return Duration.between(last, now) <= recentThreshold && location != Coordinate.zero
193146
}
194147
}

0 commit comments

Comments
 (0)