Skip to content

Commit

Permalink
Merge pull request #112 from stadiamaps/android-location-provider
Browse files Browse the repository at this point in the history
Android location provider
  • Loading branch information
ianthetechie authored Jun 4, 2024
2 parents f256608 + c6b4c40 commit 181ed00
Show file tree
Hide file tree
Showing 27 changed files with 721 additions and 525 deletions.
4 changes: 2 additions & 2 deletions Package.resolved
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/maplibre/maplibre-gl-native-distribution.git",
"state" : {
"revision" : "6d0071977ed1f2380c739715f82ac650f99b0824",
"version" : "6.4.0"
"revision" : "816a24eb56b7cd004e389f7da404047839d5dc2b",
"version" : "6.4.2"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ publishing {

allprojects {
group = "com.stadiamaps.ferrostar"
version = "0.0.32"
version = "0.0.33"
}
4 changes: 4 additions & 0 deletions android/composeui/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ android {
}
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
Expand All @@ -43,6 +44,9 @@ android {
}

dependencies {
// For as long as we support API 25; once we can raise support to 26, all is fine
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'

implementation 'androidx.core:core-ktx:1.12.0'
implementation platform('org.jetbrains.kotlin:kotlin-bom:1.8.0')
implementation 'androidx.appcompat:appcompat:1.6.1'
Expand Down
7 changes: 6 additions & 1 deletion android/core/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ android {
}
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
Expand All @@ -42,6 +43,9 @@ android {
dependencies {
implementation(platform("com.squareup.okhttp3:okhttp-bom:4.10.0"))

// For as long as we support API 25; once we can raise support to 26, all is fine
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.0.4'

implementation 'androidx.core:core-ktx:1.12.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.squareup.okhttp3:okhttp'
Expand All @@ -65,6 +69,7 @@ dependencies {
cargoNdk {
module = "../common" // Directory containing Cargo.toml
librariesNames = ["libferrostar.so"]
extraCargoBuildArguments = ["-p", "ferrostar"]
}

android.libraryVariants.all { variant ->
Expand All @@ -88,7 +93,7 @@ android.libraryVariants.all { variant ->
}

def sourceSet = variant.sourceSets.find { it.name == variant.name }
sourceSet.java.srcDir new File(buildDir, "generated/source/uniffi/${variant.name}/java")
sourceSet.java.srcDir layout.buildDirectory.file("generated/source/uniffi/${variant.name}/java")

// UniFFI tutorial notes that they made several attempts like this but were unsuccessful coming
// to a good solution for forcing the directory to be marked as generated (short of checking in
Expand Down
3 changes: 2 additions & 1 deletion android/core/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapter
import java.net.URL
import java.time.Instant
import java.util.concurrent.Executors
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand All @@ -13,6 +14,7 @@ import kotlinx.coroutines.launch
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import uniffi.ferrostar.GeographicCoordinate
import uniffi.ferrostar.Heading
import uniffi.ferrostar.NavigationController
import uniffi.ferrostar.NavigationControllerConfig
Expand All @@ -27,6 +29,7 @@ import uniffi.ferrostar.Waypoint
data class FerrostarCoreState(
/** The raw trip state from the core. */
val tripState: TripState,
val routeGeometry: List<GeographicCoordinate>,
/** Indicates when the core is calculating a new route (ex: due to the user being off route). */
val isCalculatingNewRoute: Boolean
)
Expand All @@ -52,6 +55,10 @@ class FerrostarCore(
val httpClient: OkHttpClient,
val locationProvider: LocationProvider,
) : LocationUpdateListener {
companion object {
private const val TAG = "FerrostarCore"
}

/**
* The minimum time to wait before initiating another route recalculation.
*
Expand Down Expand Up @@ -99,7 +106,7 @@ class FerrostarCore(
var isCalculatingNewRoute: Boolean = false
private set

private val _executor = Executors.newSingleThreadExecutor()
private val _executor = Executors.newSingleThreadScheduledExecutor()
private val _scope = CoroutineScope(Dispatchers.IO)
private var _navigationController: NavigationController? = null
private var _state: MutableStateFlow<FerrostarCoreState>? = null
Expand Down Expand Up @@ -184,6 +191,10 @@ class FerrostarCore(
* subscribe to location provider updates. Returns a view model which is tied to the navigation
* session. You can observe this in either your own or one of the provided navigation compose
* views.
*
* WARNING: If you want to reuse the existing view model, ex: when getting a new route after going
* off course, use [replaceRoute] instead! Otherwise, you will miss out on updates as the old view
* model is "orphaned"!
*/
@Throws(UserLocationUnknown::class)
fun startNavigation(route: Route, config: NavigationControllerConfig): NavigationViewModel {
Expand All @@ -194,18 +205,50 @@ class FerrostarCore(
route,
config,
)
val startingLocation = locationProvider.lastLocation ?: throw UserLocationUnknown()
val startingLocation =
locationProvider.lastLocation
?: UserLocation(route.geometry.first(), 0.0, null, Instant.now(), null)

val initialTripState = controller.getInitialState(startingLocation)
val stateFlow = MutableStateFlow(FerrostarCoreState(tripState = initialTripState, false))
val stateFlow =
MutableStateFlow(FerrostarCoreState(tripState = initialTripState, route.geometry, false))
handleStateUpdate(initialTripState, startingLocation)

_navigationController = controller
_state = stateFlow

locationProvider.addListener(this, _executor)

return NavigationViewModel(stateFlow, startingLocation, route.geometry)
return NavigationViewModel(stateFlow, startingLocation)
}

/**
* Replace the currently running route with a new one.
*
* This allows you to reuse the existing view model. Do not call this method unless you are
* already navigating.
*/
fun replaceRoute(route: Route, config: NavigationControllerConfig) {
val controller =
NavigationController(
route,
config,
)
val startingLocation =
locationProvider.lastLocation
?: UserLocation(route.geometry.first(), 0.0, null, Instant.now(), null)

_navigationController = controller
if (_state == null) {
android.util.Log.e(TAG, "Unexpected null state")
}
_state?.update {
val newState = controller.getInitialState(startingLocation)

handleStateUpdate(newState, startingLocation)

FerrostarCoreState(tripState = newState, route.geometry, false)
}
}

fun advanceToNextStep() {
Expand All @@ -218,7 +261,7 @@ class FerrostarCore(

handleStateUpdate(newState, location)

FerrostarCoreState(tripState = newState, isCalculatingNewRoute)
FerrostarCoreState(tripState = newState, currentValue.routeGeometry, isCalculatingNewRoute)
}
}
}
Expand Down Expand Up @@ -270,9 +313,11 @@ class FerrostarCore(
// Default behavior when there is no user-defined behavior:
// accept the first route, as this is what most users want when they go off
// route.
startNavigation(routes.first(), config)
replaceRoute(routes.first(), config)
}
}
} catch (e: Throwable) {
android.util.Log.e(TAG, "Failed to recalculate route: $e")
} finally {
_lastAutomaticRecalculation = System.nanoTime()
isCalculatingNewRoute = false
Expand Down Expand Up @@ -303,7 +348,7 @@ class FerrostarCore(

handleStateUpdate(newState, location)

FerrostarCoreState(tripState = newState, isCalculatingNewRoute)
FerrostarCoreState(tripState = newState, currentValue.routeGeometry, isCalculatingNewRoute)
}
}
}
Expand Down
Loading

0 comments on commit 181ed00

Please sign in to comment.