Navigation Activity · Kotlin for Android
import android.location.Location
import android.os.Bundle
import android.os.Environment
import android.preference.PreferenceManager
import android.text.SpannableString
import android.text.Spanned
import android.text.style.AbsoluteSizeSpan
import android.view.View
import android.widget.TextView
import androidx.annotation.IdRes
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.jeluchu.laelipa.R
import com.mapbox.api.directions.v5.models.BannerInstructions
import com.mapbox.api.directions.v5.models.DirectionsResponse
import com.mapbox.api.directions.v5.models.DirectionsRoute
import com.mapbox.geojson.Point
import com.mapbox.mapboxsdk.Mapbox
import com.mapbox.mapboxsdk.camera.CameraPosition
import com.mapbox.mapboxsdk.geometry.LatLng
import com.mapbox.services.android.navigation.ui.v5.NavigationView
import com.mapbox.services.android.navigation.ui.v5.NavigationViewOptions
import com.mapbox.services.android.navigation.ui.v5.OnNavigationReadyCallback
import com.mapbox.services.android.navigation.ui.v5.listeners.BannerInstructionsListener
import com.mapbox.services.android.navigation.ui.v5.listeners.InstructionListListener
import com.mapbox.services.android.navigation.ui.v5.listeners.NavigationListener
import com.mapbox.services.android.navigation.v5.navigation.NavigationRoute
import com.mapbox.services.android.navigation.v5.routeprogress.ProgressChangeListener
import com.mapbox.services.android.navigation.v5.routeprogress.RouteProgress
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import timber.log.Timber
class NavigationActivity: AppCompatActivity(), OnNavigationReadyCallback, NavigationListener,
ProgressChangeListener, InstructionListListener, BannerInstructionsListener {
private var navigationView: NavigationView? = null
private var spacer: View? = null
private var speedWidget: TextView? = null
private var bottomSheetVisible = true
private var instructionListShown = false
var latshop: Double = 0.0
var longshop: Double = 0.0
var currentlat: Double = 0.0
var currentlong: Double = 0.0
override fun onCreate(savedInstanceState: Bundle?) {
Mapbox.getInstance(this, getString(R.string.acces_token))
setTheme(R.style.Theme_AppCompat_Light_NoActionBar)
initNightMode()
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_navigation)
navigationView = findViewById(R.id.navigationView)
speedWidget = findViewById(R.id.speed_limit)
spacer = findViewById(R.id.spacer)
setSpeedWidgetAnchor(R.id.summaryBottomSheet)
val intent = intent
latshop = intent.extras!!.getDouble("latshop")
longshop = intent.extras!!.getDouble("longshop")
currentlat = intent.extras!!.getDouble("currentlat")
currentlong = intent.extras!!.getDouble("currentlong")
val initialPosition = CameraPosition.Builder().target(LatLng(currentlat, currentlong))
.zoom(INITIAL_ZOOM.toDouble())
.build()
navigationView!!.onCreate(savedInstanceState)
navigationView!!.initialize(this, initialPosition)
}
override fun onNavigationReady(isRunning: Boolean) { fetchRoute() }
override fun onCancelNavigation() { finish() }
override fun onNavigationFinished() {}
override fun onNavigationRunning() {}
override fun onProgressChange(location: Location?, routeProgress: RouteProgress?) {
location?.let { setSpeed(it) }
}
override fun onInstructionListVisibilityChanged(show: Boolean) {
instructionListShown = show
speedWidget!!.visibility = if (show) View.GONE else View.VISIBLE
}
override fun willDisplay(instructions: BannerInstructions?): BannerInstructions = instructions!!
override fun onSaveInstanceState(outState: Bundle) {
navigationView!!.onSaveInstanceState(outState)
super.onSaveInstanceState(outState)
}
override fun onRestoreInstanceState(savedInstanceState: Bundle) {
super.onRestoreInstanceState(savedInstanceState)
navigationView!!.onRestoreInstanceState(savedInstanceState)
}
private fun startNavigation(directionsRoute: DirectionsRoute) {
val options = NavigationViewOptions.builder()
.navigationListener(this)
.directionsRoute(directionsRoute)
.shouldSimulateRoute(false)
.progressChangeListener(this)
.instructionListListener(this)
.bannerInstructionsListener(this)
.offlineRoutingTilesPath(obtainOfflineDirectory())
.offlineRoutingTilesVersion(obtainOfflineTileVersion())
setBottomSheetCallback(options)
navigationView!!.startNavigation(options.build())
}
private fun obtainOfflineDirectory(): String {
val offline = Environment.getExternalStoragePublicDirectory("Offline")
if (!offline.exists()) {
Timber.d("Offline directory does not exist")
offline.mkdirs()
}
return offline.absolutePath
}
private fun obtainOfflineTileVersion(): String? = PreferenceManager.getDefaultSharedPreferences(this).getString(getString(R.string.offline_version_key), "")
private fun fetchRoute() {
NavigationRoute.builder(this)
.accessToken(getString(R.string.acces_token))
.origin(Point.fromLngLat(currentlat, currentlong))
.destination(Point.fromLngLat(latshop, longshop))
.alternatives(true)
.build()
.getRoute(object : Callback<DirectionsResponse> {
override fun onFailure(call: Call<DirectionsResponse>, throwable: Throwable) {
Timber.e("Error: %s", throwable.message)
}
override fun onResponse(call: Call<DirectionsResponse>, response: Response<DirectionsResponse>) {
startNavigation(response.body()!!.routes()[0])
}
})
}
private fun setSpeedWidgetAnchor(@IdRes res: Int) {
val layoutParams = spacer!!.layoutParams as CoordinatorLayout.LayoutParams
layoutParams.anchorId = res
spacer!!.layoutParams = layoutParams
}
private fun setBottomSheetCallback(options: NavigationViewOptions.Builder) {
options.bottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) {
BottomSheetBehavior.STATE_HIDDEN -> {
bottomSheetVisible = false
setSpeedWidgetAnchor(R.id.recenterBtn)
}
BottomSheetBehavior.STATE_EXPANDED -> bottomSheetVisible = true
BottomSheetBehavior.STATE_SETTLING -> if (!bottomSheetVisible) { setSpeedWidgetAnchor(R.id.summaryBottomSheet) }
else -> return
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {}
})
}
private fun initNightMode() {
val nightMode = retrieveNightModeFromPreferences()
AppCompatDelegate.setDefaultNightMode(nightMode)
}
private fun retrieveNightModeFromPreferences(): Int {
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
return preferences.getInt(getString(R.string.current_night_mode), AppCompatDelegate.MODE_NIGHT_AUTO)
}
private fun saveNightModeToPreferences(nightMode: Int) {
val preferences = PreferenceManager.getDefaultSharedPreferences(this)
val editor = preferences.edit()
editor.putInt(getString(R.string.current_night_mode), nightMode)
editor.apply()
}
private fun setSpeed(location: Location) {
val string = String.format("%d\nKPH", (location.speed * 1.609344).toInt())
val mphTextSize = resources.getDimensionPixelSize(R.dimen.mph_text_size)
val speedTextSize = resources.getDimensionPixelSize(R.dimen.speed_text_size)
val spannableString = SpannableString(string)
spannableString.setSpan(
AbsoluteSizeSpan(mphTextSize),
string.length - 4, string.length, Spanned.SPAN_INCLUSIVE_INCLUSIVE
)
spannableString.setSpan(
AbsoluteSizeSpan(speedTextSize),
0, string.length - 3, Spanned.SPAN_INCLUSIVE_INCLUSIVE
)
speedWidget!!.text = spannableString
if (!instructionListShown) {
speedWidget!!.visibility = View.VISIBLE
}
}
public override fun onStart() {
super.onStart()
navigationView!!.onStart()
}
public override fun onResume() {
super.onResume()
navigationView!!.onResume()
}
override fun onLowMemory() {
super.onLowMemory()
navigationView!!.onLowMemory()
}
override fun onBackPressed() {
if (!navigationView!!.onBackPressed()) {
super.onBackPressed()
}
}
public override fun onPause() {
super.onPause()
navigationView!!.onPause()
}
public override fun onStop() {
super.onStop()
navigationView!!.onStop()
}
override fun onDestroy() {
super.onDestroy()
navigationView!!.onDestroy()
if (isFinishing) {
saveNightModeToPreferences(AppCompatDelegate.MODE_NIGHT_AUTO)
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_AUTO)
}
}
companion object {
private const val INITIAL_ZOOM = 16
}
}
Android API: 28
Mapbox Navigation SDK version: 8.1.0
2019-07-04 19:51:31.700 7161-7731/com.jeluchu.laelipa E/AndroidRuntime: FATAL EXCEPTION: mapbox_navigation_thread
Process: com.jeluchu.laelipa, PID: 7161
java.lang.Error: Any tile edge can only be used once as part of the geometry
at com.mapbox.navigator.Navigator.getRouteBufferGeoJson(Native Method)
at com.mapbox.services.android.navigation.v5.navigation.MapboxNavigator.retrieveRouteGeometryWithBuffer(MapboxNavigator.java:110)
at com.mapbox.services.android.navigation.v5.navigation.NavigationRouteProcessor.updateRoute(NavigationRouteProcessor.java:75)
at com.mapbox.services.android.navigation.v5.navigation.NavigationRouteProcessor.buildNewRouteProgress(NavigationRouteProcessor.java:53)
at com.mapbox.services.android.navigation.v5.navigation.RouteProcessorRunnable.process(RouteProcessorRunnable.java:63)
at com.mapbox.services.android.navigation.v5.navigation.RouteProcessorRunnable.run(RouteProcessorRunnable.java:46)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.os.HandlerThread.run(HandlerThread.java:61)
java.lang.Error: Any tile edge can only be used once as part of the geometry at com.mapbox.navigator.Navigator.getRouteBufferGeoJson(Native Method) at com.mapbox.services.android.navigation.v5.navigation.MapboxNavigator.retrieveRouteGeometryWithBuffer(MapboxNavigator.java:110) at com.mapbox.services.android.navigation.v5.navigation.NavigationRouteProcessor.updateRoute(NavigationRouteProcessor.java:75) at com.mapbox.services.android.navigation.v5.navigation.NavigationRouteProcessor.buildNewRouteProgress(NavigationRouteProcessor.java:53) at com.mapbox.services.android.navigation.v5.navigation.RouteProcessorRunnable.process(RouteProcessorRunnable.java:63) at com.mapbox.services.android.navigation.v5.navigation.RouteProcessorRunnable.run(RouteProcessorRunnable.java:46) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154) at android.os.HandlerThread.run(HandlerThread.java:61)
Crashlytics Reports
Fatal Exception: java.lang.IllegalArgumentException: Non-null and non-empty location list required.
at com.mapbox.services.android.navigation.v5.location.replay.ReplayLocationDispatcher.checkValidInput + 79(ReplayLocationDispatcher.java:79)
at com.mapbox.services.android.navigation.v5.location.replay.ReplayLocationDispatcher.<init> + 22(ReplayLocationDispatcher.java:22)
at com.mapbox.services.android.navigation.v5.location.replay.ReplayRouteLocationEngine.obtainDispatcher + 164(ReplayRouteLocationEngine.java:164)
at com.mapbox.services.android.navigation.v5.location.replay.ReplayRouteLocationEngine.start + 154(ReplayRouteLocationEngine.java:154)
at com.mapbox.services.android.navigation.v5.location.replay.ReplayRouteLocationEngine.beginReplayWith + 203(ReplayRouteLocationEngine.java:203)
at com.mapbox.services.android.navigation.v5.location.replay.ReplayRouteLocationEngine.requestLocationUpdates + 113(ReplayRouteLocationEngine.java:113)
at com.mapbox.services.android.navigation.v5.navigation.LocationUpdater.requestInitialLocationUpdates + 58(LocationUpdater.java:58)
at com.mapbox.services.android.navigation.v5.navigation.LocationUpdater.<init> + 31(LocationUpdater.java:31)
at com.mapbox.services.android.navigation.v5.navigation.NavigationService.initializeLocationUpdater + 124(NavigationService.java:124)
at com.mapbox.services.android.navigation.v5.navigation.NavigationService.initialize + 95(NavigationService.java:95)
at com.mapbox.services.android.navigation.v5.navigation.NavigationService.startNavigation + 66(NavigationService.java:66)
at com.mapbox.services.android.navigation.v5.navigation.MapboxNavigation.onServiceConnected + 810(MapboxNavigation.java:810)
at android.app.LoadedApk$ServiceDispatcher.doConnected + 1453(LoadedApk.java:1453)
at android.app.LoadedApk$ServiceDispatcher$RunConnection.run + 1481(LoadedApk.java:1481)
at android.os.Handler.handleCallback + 751(Handler.java:751)
at android.os.Handler.dispatchMessage + 95(Handler.java:95)
at android.os.Looper.loop + 154(Looper.java:154)
at android.app.ActivityThread.main + 6121(ActivityThread.java:6121)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run + 889(ZygoteInit.java:889)
at com.android.internal.os.ZygoteInit.main + 779(ZygoteInit.java:779)
Fatal Exception: java.lang.Error: Any tile edge can only be used once as part of the geometry
at com.mapbox.navigator.Navigator.getRouteBufferGeoJson(Navigator.java)
at com.mapbox.services.android.navigation.v5.navigation.MapboxNavigator.retrieveRouteGeometryWithBuffer + 110(MapboxNavigator.java:110)
at com.mapbox.services.android.navigation.v5.navigation.NavigationRouteProcessor.updateRoute + 75(NavigationRouteProcessor.java:75)
at com.mapbox.services.android.navigation.v5.navigation.NavigationRouteProcessor.buildNewRouteProgress + 53(NavigationRouteProcessor.java:53)
at com.mapbox.services.android.navigation.v5.navigation.RouteProcessorRunnable.process + 63(RouteProcessorRunnable.java:63)
at com.mapbox.services.android.navigation.v5.navigation.RouteProcessorRunnable.run + 46(RouteProcessorRunnable.java:46)
at android.os.Handler.handleCallback + 751(Handler.java:751)
at android.os.Handler.dispatchMessage + 95(Handler.java:95)
at android.os.Looper.loop + 154(Looper.java:154)
at android.os.HandlerThread.run + 61(HandlerThread.java:61)
Fatal Exception: kotlin.KotlinNullPointerException
at com.jeluchu.laelipa.activities.NavigationActivity$fetchRoute$1.onResponse + 139(NavigationActivity.kt:139)
at com.mapbox.services.android.navigation.v5.navigation.NavigationRouteCallback.onResponse + 30(NavigationRouteCallback.java:30)
at com.mapbox.api.directions.v5.MapboxDirections$1.onResponse + 185(MapboxDirections.java:185)
at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run + 71(ExecutorCallAdapterFactory.java:71)
at android.os.Handler.handleCallback + 751(Handler.java:751)
at android.os.Handler.dispatchMessage + 95(Handler.java:95)
at android.os.Looper.loop + 154(Looper.java:154)
at android.app.ActivityThread.main + 6121(ActivityThread.java:6121)
at java.lang.reflect.Method.invoke(Method.java)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run + 889(ZygoteInit.java:889)
at com.android.internal.os.ZygoteInit.main + 779(ZygoteInit.java:779)
I pick up both the current position and the destination from another activity (I have verified that I get them correctly)
But when starting the activity of navigation, it closes giving several errors, among them is that I show you. Another error that has come up is: Non-empty location list required
implementation 'com.mapbox.mapboxsdk:mapbox-android-navigation:0.40.0'
implementation 'com.mapbox.mapboxsdk:mapbox-android-navigation-ui:0.40.0'
implementation 'com.mapbox.mapboxsdk:mapbox-android-sdk:8.1.0'
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-building-v7:0.5.0'
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-localization-v7:0.9.0'
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-locationlayer:0.11.0'
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-places:0.6.0'
implementation 'com.mapbox.mapboxsdk:mapbox-android-plugin-geojson:0.3.0'
These are the libraries I use Mapbox, in addition to their plugins, if they help to find the solution to my problem. These errors come out randomly without changing any part of the activity
Navigation Activity · Kotlin for Android
Android API: 28
Mapbox Navigation SDK version: 8.1.0
Crashlytics Reports
I pick up both the current position and the destination from another activity (I have verified that I get them correctly)
But when starting the activity of navigation, it closes giving several errors, among them is that I show you. Another error that has come up is: Non-empty location list required
These are the libraries I use Mapbox, in addition to their plugins, if they help to find the solution to my problem. These errors come out randomly without changing any part of the activity