Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release/navigation 1.3.4 #134

Closed
wants to merge 15 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ With this SDK you can implement turn-by-turn navigation in your own Android app
- No Telemetry


## Why have we forked
## Why have we forked¬

1. Mapbox decided to put a closed-source component to their navigation SDK and introduced a non-open-source license. Maplibre wants an open-source solution.
2. Mapbox decided to put telemetry in their SDK. We couldn't turn this off without adjusting the source.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.mapbox.services.android.navigation.testapp.ValhallaNavigationActivity;

import org.maplibre.android.location.permissions.PermissionsListener;
import org.maplibre.android.location.permissions.PermissionsManager;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,39 @@ package org.maplibre.navigation.android.example

import android.annotation.SuppressLint
import android.os.Bundle
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.snackbar.Snackbar
import org.maplibre.navigation.android.navigation.v5.models.DirectionsResponse
import org.maplibre.geojson.Point
import org.maplibre.android.annotations.MarkerOptions
import org.maplibre.android.camera.CameraPosition
import android.preference.PreferenceManager
import androidx.activity.ComponentActivity
import org.maplibre.navigation.android.navigation.ui.v5.MapRouteData
import okhttp3.Request
import org.maplibre.android.geometry.LatLng
import org.maplibre.android.location.LocationComponent
import org.maplibre.android.location.LocationComponentActivationOptions
import org.maplibre.android.location.modes.CameraMode
import org.maplibre.android.location.modes.RenderMode
import org.maplibre.android.maps.MapLibreMap
import org.maplibre.android.maps.OnMapReadyCallback
import org.maplibre.android.maps.Style
import org.maplibre.geojson.Point
import org.maplibre.navigation.android.example.databinding.ActivityNavigationUiBinding
import org.maplibre.navigation.android.navigation.ui.v5.NavigationLauncher
import org.maplibre.navigation.android.navigation.ui.v5.NavigationLauncherOptions
import org.maplibre.navigation.android.navigation.ui.v5.NavigationViewOptions
import org.maplibre.navigation.android.navigation.ui.v5.OnNavigationReadyCallback
import org.maplibre.navigation.android.navigation.ui.v5.listeners.NavigationListener
import org.maplibre.navigation.android.navigation.ui.v5.route.NavigationRoute
import org.maplibre.navigation.android.navigation.v5.models.DirectionsCriteria
import org.maplibre.navigation.android.navigation.v5.models.DirectionsResponse
import org.maplibre.navigation.android.navigation.v5.models.DirectionsRoute
import org.maplibre.turf.TurfConstants
import org.maplibre.turf.TurfMeasurement
import okhttp3.Request
import org.maplibre.navigation.android.example.databinding.ActivityNavigationUiBinding
import org.maplibre.navigation.android.navigation.v5.navigation.MapLibreNavigationOptions
import org.maplibre.navigation.android.navigation.v5.navigation.NavigationConstants
import org.maplibre.navigation.android.navigation.ui.v5.route.NavigationMapRoute
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import timber.log.Timber

class NavigationUIActivity :
AppCompatActivity(),
OnMapReadyCallback,
MapLibreMap.OnMapClickListener {
private lateinit var mapLibreMap: MapLibreMap
ComponentActivity(),
MapLibreMap.OnMapClickListener, OnNavigationReadyCallback,
NavigationListener {

// Navigation related variables
private var route: DirectionsRoute? = null
Expand All @@ -60,71 +57,45 @@ class NavigationUIActivity :

binding = ActivityNavigationUiBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.mapView.apply {
onCreate(savedInstanceState)
getMapAsync(this@NavigationUIActivity)
}
binding.navigationView.onCreate(this, savedInstanceState, this, "https://api.maptiler.com/maps/streets-v2-dark/style.json?key=ZkZSWT2Q0ta4f3S1VyrZ")

binding.startRouteButton.setOnClickListener {
route?.let { route ->
val userLocation = mapLibreMap.locationComponent.lastKnownLocation ?: return@let

val options = NavigationLauncherOptions.builder()
.directionsRoute(route)
.shouldSimulateRoute(simulateRoute)
.initialMapCameraPosition(
CameraPosition.Builder()
.target(LatLng(userLocation.latitude, userLocation.longitude)).build()
)
.lightThemeResId(R.style.TestNavigationViewLight)
.darkThemeResId(R.style.TestNavigationViewDark)
.build()
NavigationLauncher.startNavigation(this@NavigationUIActivity, options)
}
}

binding.simulateRouteSwitch.setOnCheckedChangeListener { _, checked ->
simulateRoute = checked
}
// binding.mapView.apply {
// onCreate(savedInstanceState)
// getMapAsync(this@NavigationUIActivity)
// }

// binding.simulateRouteSwitch.setOnCheckedChangeListener { _, checked ->
// simulateRoute = checked
// }

binding.clearPoints.setOnClickListener {
if (::mapLibreMap.isInitialized) {
mapLibreMap.markers.forEach {
mapLibreMap.removeMarker(it)
}
}
destination = null
waypoint = null
it.visibility = View.GONE
binding.startRouteLayout.visibility = View.GONE

navigationMapRoute?.removeRoute()
}
}

override fun onMapReady(mapLibreMap: MapLibreMap) {
this.mapLibreMap = mapLibreMap
mapLibreMap.setStyle(
Style.Builder().fromUri(getString(R.string.map_style_light))
) { style ->
enableLocationComponent(style)
navigationMapRoute = NavigationMapRoute(binding.mapView, mapLibreMap)

mapLibreMap.addOnMapClickListener(this)

Snackbar.make(
findViewById(R.id.container),
"Tap map to place waypoint",
Snackbar.LENGTH_LONG,
).show()
binding.startRouteButton.setOnClickListener {
val points = mutableListOf<Pair<Double, Double>>()
points.add(Pair(76.930137, 43.230361))
points.add(Pair(76.928316, 43.236109))
points.add(Pair(76.920187, 43.236783))
binding.navigationView.calculateRoute(
MapRouteData(getString(R.string.mapbox_access_token), "", points, Pair(76.930137, 43.230361), MapRouteData.DARK_THEME)
)
}
// binding.clearPoints.setOnClickListener {
// if (::mapboxMap.isInitialized) {
// mapboxMap.markers.forEach {
// mapboxMap.removeMarker(it)
// }
// }
// destination = null
// waypoint = null
// it.visibility = View.GONE
// binding.startRouteLayout.visibility = View.GONE
//
// navigationMapRoute?.removeRoute()
// }
}

@SuppressWarnings("MissingPermission")
private fun enableLocationComponent(style: Style) {
// Get an instance of the component
locationComponent = mapLibreMap.locationComponent
// locationComponent = mapboxMap.locationComponent

locationComponent?.let {
// Activate with a built LocationComponentActivationOptions object
Expand All @@ -144,46 +115,46 @@ class NavigationUIActivity :
}

override fun onMapClick(point: LatLng): Boolean {
var addMarker = true
when {
destination == null -> destination = Point.fromLngLat(point.longitude, point.latitude)
waypoint == null -> waypoint = Point.fromLngLat(point.longitude, point.latitude)
else -> {
Toast.makeText(this, "Only 2 waypoints supported", Toast.LENGTH_LONG).show()
addMarker = false
}
}

if (addMarker) {
mapLibreMap.addMarker(MarkerOptions().position(point))
binding.clearPoints.visibility = View.VISIBLE
}
calculateRoute()
// var addMarker = true
// when {
// destination == null -> destination = Point.fromLngLat(point.longitude, point.latitude)
// waypoint == null -> waypoint = Point.fromLngLat(point.longitude, point.latitude)
// else -> {
// Toast.makeText(this, "Only 2 waypoints supported", Toast.LENGTH_LONG).show()
// addMarker = false
// }
// }
//
// if (addMarker) {
// mapboxMap.addMarker(MarkerOptions().position(point))
// binding.clearPoints.visibility = View.VISIBLE
// }
// calculateRoute()
return true
}

private fun calculateRoute() {
binding.startRouteLayout.visibility = View.GONE
val userLocation = mapLibreMap.locationComponent.lastKnownLocation
// binding.startRouteLayout.visibility = View.GONE
// val userLocation = mapboxMap.locationComponent.lastKnownLocation
val destination = destination
if (userLocation == null) {
Timber.d("calculateRoute: User location is null, therefore, origin can't be set.")
return
}
// if (userLocation == null) {
// Timber.d("calculateRoute: User location is null, therefore, origin can't be set.")
// return
// }

if (destination == null) {
return
}

val origin = Point.fromLngLat(userLocation.longitude, userLocation.latitude)
if (TurfMeasurement.distance(origin, destination, TurfConstants.UNIT_METERS) < 50) {
binding.startRouteLayout.visibility = View.GONE
return
}
// val origin = Point.fromLngLat(userLocation.longitude, userLocation.latitude)
// if (TurfMeasurement.distance(origin, destination, TurfConstants.UNIT_METERS) < 50) {
// binding.startRouteLayout.visibility = View.GONE
// return
// }

val navigationRouteBuilder = NavigationRoute.builder(this).apply {
this.accessToken(getString(R.string.mapbox_access_token))
this.origin(origin)
// this.origin(origin)
this.destination(destination)
this.voiceUnits(DirectionsCriteria.METRIC)
this.alternatives(true)
Expand All @@ -193,6 +164,20 @@ class NavigationUIActivity :
this.baseUrl(getString(R.string.base_url))
}


navigationRouteBuilder.addWaypoint(
Point.fromLngLat(76.930137, 43.230361)
)

navigationRouteBuilder.addWaypoint(
Point.fromLngLat(76.928316, 43.236109)
)

navigationRouteBuilder.addWaypoint(
Point.fromLngLat(76.920187, 43.236783)
)


navigationRouteBuilder.build().getRoute(object : Callback<DirectionsResponse> {
override fun onResponse(
call: Call<DirectionsResponse>,
Expand All @@ -201,10 +186,13 @@ class NavigationUIActivity :
Timber.d("Url: %s", (call.request() as Request).url.toString())
response.body()?.let { response ->
if (response.routes.isNotEmpty()) {
val maplibreResponse = DirectionsResponse.fromJson(response.toJson());
val maplibreResponse =
DirectionsResponse.fromJson(
response.toJson()
);
[email protected] = maplibreResponse.routes.first()
navigationMapRoute?.addRoutes(maplibreResponse.routes)
binding.startRouteLayout.visibility = View.VISIBLE
// binding.startRouteLayout.visibility = View.VISIBLE
}
}

Expand All @@ -218,39 +206,85 @@ class NavigationUIActivity :

override fun onResume() {
super.onResume()
binding.mapView.onResume()
binding.navigationView.onResume()
}

override fun onPause() {
super.onPause()
binding.mapView.onPause()
binding.navigationView.onPause()
}

override fun onStart() {
super.onStart()
binding.mapView.onStart()
binding.navigationView.onStart()
}

override fun onStop() {
super.onStop()
binding.mapView.onStop()
binding.navigationView.onStop()
}

override fun onLowMemory() {
super.onLowMemory()
binding.mapView.onLowMemory()
binding.navigationView.onLowMemory()
}

override fun onDestroy() {
super.onDestroy()
if (::mapLibreMap.isInitialized) {
mapLibreMap.removeOnMapClickListener(this)
}
binding.mapView.onDestroy()
// if (::mapboxMap.isInitialized) {
// mapboxMap.removeOnMapClickListener(this)
// }
// binding.navigationView.onDestroy()
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
binding.mapView.onSaveInstanceState(outState)
binding.navigationView.onSaveInstanceState(outState)
}

override fun onNavigationReady(isRunning: Boolean) {
val options = NavigationViewOptions.builder()
options.navigationListener(this)
extractRoute(options)
extractConfiguration(options)
options.navigationOptions(MapLibreNavigationOptions())
binding.navigationView.startNavigation(options.build())
}

override fun onCancelNavigation() {
finishNavigation()
}

override fun onNavigationFinished() {
finishNavigation()
}

override fun onNavigationRunning() {
// Intentionally empty
}

override fun onMapReadyCallback() {
// Intentionally empty
}

private fun extractRoute(options: NavigationViewOptions.Builder) {
val route = NavigationLauncher.extractRoute(this)
options.directionsRoute(route)
}

private fun extractConfiguration(options: NavigationViewOptions.Builder) {
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
options.shouldSimulateRoute(
preferences.getBoolean(
NavigationConstants.NAVIGATION_VIEW_SIMULATE_ROUTE,
false
)
)
}

private fun finishNavigation() {
// NavigationLauncher.cleanUpPreferences(this)
binding.navigationView.onDestroy()
// finish()
}
}
Loading
Loading