diff --git a/core/devicepose/src/main/java/de/mm20/launcher2/devicepose/DevicePoseProvider.kt b/core/devicepose/src/main/java/de/mm20/launcher2/devicepose/DevicePoseProvider.kt index aa03f74d..7b13c408 100644 --- a/core/devicepose/src/main/java/de/mm20/launcher2/devicepose/DevicePoseProvider.kt +++ b/core/devicepose/src/main/java/de/mm20/launcher2/devicepose/DevicePoseProvider.kt @@ -18,6 +18,8 @@ import kotlinx.coroutines.channels.awaitClose import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.callbackFlow import kotlinx.coroutines.flow.channelFlow +import de.mm20.launcher2.ktx.foldOrNull +import de.mm20.launcher2.ktx.isBetterThan import kotlinx.coroutines.flow.combine class DevicePoseProvider internal constructor( @@ -37,10 +39,16 @@ class DevicePoseProvider internal constructor( } fun getLocation(minTimeMs: Long = 1000, minDistanceM: Float = 1f) = channelFlow { + fun updateLocation(update: Location?) { + if (update == null) return + if (!update.isBetterThan(lastLocation)) return + lastLocation = update + updateDeclination(update) + trySend(update) + } + val locationCallback = LocationListenerCompat { - lastLocation = it - updateDeclination(it) - trySend(it) + updateLocation(it) } context.getSystemService() @@ -50,20 +58,14 @@ class DevicePoseProvider internal constructor( val hasCoarseAccess = context.checkPermission(Manifest.permission.ACCESS_COARSE_LOCATION) - val location = - (if (hasFineAccess) this@runCatching.getLastKnownLocation(LocationManager.GPS_PROVIDER) else null) - ?: if (hasCoarseAccess) this@runCatching.getLastKnownLocation( - LocationManager.NETWORK_PROVIDER - ) else null + val previousLocation = + hasFineAccess.foldOrNull { getLastKnownLocation(LocationManager.GPS_PROVIDER) } ?: + hasCoarseAccess.foldOrNull { getLastKnownLocation(LocationManager.NETWORK_PROVIDER) } - if (location != null) { - lastLocation = location - updateDeclination(location) - trySend(location) - } + updateLocation(previousLocation) if (hasFineAccess) { - this@runCatching.requestLocationUpdates( + requestLocationUpdates( LocationManager.GPS_PROVIDER, minTimeMs, minDistanceM, @@ -71,7 +73,7 @@ class DevicePoseProvider internal constructor( ) } if (hasCoarseAccess) { - this@runCatching.requestLocationUpdates( + requestLocationUpdates( LocationManager.NETWORK_PROVIDER, minTimeMs, minDistanceM, diff --git a/core/ktx/src/main/java/de/mm20/launcher2/ktx/AndroidLocation.kt b/core/ktx/src/main/java/de/mm20/launcher2/ktx/AndroidLocation.kt new file mode 100644 index 00000000..c1dbec4e --- /dev/null +++ b/core/ktx/src/main/java/de/mm20/launcher2/ktx/AndroidLocation.kt @@ -0,0 +1,37 @@ +package de.mm20.launcher2.ktx + +import kotlin.time.Duration.Companion.minutes +import kotlin.time.Duration.Companion.nanoseconds + +import android.location.Location as AndroidLocation + +/* https://github.com/streetcomplete/StreetComplete/blob/master/app/src/main/java/de/westnordost/streetcomplete/util/location/LocationUtils.kt + * GPL-3.0-or-later + */ +fun AndroidLocation.isBetterThan(previous: AndroidLocation?): Boolean { + if (longitude.isNaN() || latitude.isNaN()) return false + if (previous == null) return true + + val locationTimeDiff = elapsedRealtimeNanos.nanoseconds - previous.elapsedRealtimeNanos.nanoseconds + val isMuchNewer = locationTimeDiff > 2.minutes + val isMuchOlder = locationTimeDiff < (-2).minutes + val isNewer = locationTimeDiff.isPositive() + + val accuracyDelta = accuracy - previous.accuracy + val isLessAccurate = accuracyDelta > 0f + val isMoreAccurate = accuracyDelta < 0f + val isMuchLessAccurate = accuracyDelta > 200f + + val isFromSameProvider = provider == previous.provider + + return when { + // the user has likely moved + isMuchNewer -> true + // If the new location is more than two minutes older, it must be worse + isMuchOlder -> false + isMoreAccurate -> true + isNewer && !isLessAccurate -> true + isNewer && !isMuchLessAccurate && isFromSameProvider -> true + else -> false + } +} diff --git a/core/ktx/src/main/java/de/mm20/launcher2/ktx/Boolean.kt b/core/ktx/src/main/java/de/mm20/launcher2/ktx/Boolean.kt index 5c8196f6..6473e0a3 100644 --- a/core/ktx/src/main/java/de/mm20/launcher2/ktx/Boolean.kt +++ b/core/ktx/src/main/java/de/mm20/launcher2/ktx/Boolean.kt @@ -1,5 +1,14 @@ package de.mm20.launcher2.ktx -inline fun Boolean.toInt(): Int { +fun Boolean.toInt(): Int { return if (this) 1 else 0 -} \ No newline at end of file +} + +fun Boolean.fold( + whenTrue: () -> T, + otherwise: () -> T +): T = if (this) whenTrue() else otherwise() + +fun Boolean.foldOrNull( + whenTrue: () -> T +): T? = fold(whenTrue) { null }