flutter_mapbox_navigation icon indicating copy to clipboard operation
flutter_mapbox_navigation copied to clipboard

Android 14 version

Open Arshad-ullah opened this issue 1 year ago • 3 comments

Hello team,

When I use navigation in android 14 through this error.

I/flutter (12851): The Dart VM service is listening on http://127.0.0.1:32815/uJBo6ChplKw=/ D/FlutterGeolocator(12851): Creating service. D/FlutterGeolocator(12851): Binding to location service. D/FlutterGeolocator(12851): Geolocator foreground service connected D/FlutterGeolocator(12851): Initializing Geolocator services D/FlutterGeolocator(12851): Flutter engine connected. Connected engine count 1 E/AndroidRuntime(12851): FATAL EXCEPTION: main E/AndroidRuntime(12851): Process: com.iconictek.cabtify, PID: 12851 E/AndroidRuntime(12851): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.iconictek.cabtify/com.eopeter.fluttermapboxnavigation.activity.NavigationActivity}: java.lang.SecurityException: com.iconictek.cabtify: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts E/AndroidRuntime(12851): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3782) E/AndroidRuntime(12851): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3922) E/AndroidRuntime(12851): at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:103) E/AndroidRuntime(12851): at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:139) E/AndroidRuntime(12851): at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:96) E/AndroidRuntime(12851): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2443) E/AndroidRuntime(12851): at android.os.Handler.dispatchMessage(Handler.java:106) E/AndroidRuntime(12851): at android.os.Looper.loopOnce(Looper.java:205) E/AndroidRuntime(12851): at android.os.Looper.loop(Looper.java:294) E/AndroidRuntime(12851): at android.app.ActivityThread.main(ActivityThread.java:8177) E/AndroidRuntime(12851): at java.lang.reflect.Method.invoke(Native Method) E/AndroidRuntime(12851): at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:552) E/AndroidRuntime(12851): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:971) E/AndroidRuntime(12851): Caused by: java.lang.SecurityException: com.iconictek.cabtify: One of RECEIVER_EXPORTED or RECEIVER_NOT_EXPORTED should be specified when a receiver isn't being registered exclusively for system broadcasts E/AndroidRuntime(12851): at android.os.Parcel.createExceptionOrNull(Parcel.java:3057) E/AndroidRuntime(12851): at android.os.Parcel.createException(Parcel.java:3041) E/AndroidRuntime(12851): at android.os.Parcel.readException(Parcel.java:3024) E/AndroidRuntime(12851): at android.os.Parcel.readException(Parcel.java:2966) E/AndroidRuntime(12851): at android.app.IActivityManager$Stub$Proxy.registerReceiverWithFeature(IActivityManager.java:5684) E/AndroidRuntime(12851): at java.lang.reflect.Method.invoke(Native Method) E/AndroidRuntime(12851): at leakcanary.ServiceWatcher$install$4$2.invoke(ServiceWatcher.kt:93) E/AndroidRuntime(12851): at java.lang.reflect.Proxy.invoke(Proxy.java:1006) E/AndroidRuntime(12851): at $Proxy3.registerReceiverWithFeature(Unknown Source) E/AndroidRuntime(12851): at android.app.ContextImpl.registerReceiverInternal(ContextImpl.java:1852) E/AndroidRuntime(12851): at android.app.ContextImpl.registerReceiver(ContextImpl.java:1792) E/AndroidRuntime(12851): at android.app.ContextImpl.registerReceiver(ContextImpl.java:1780) E/AndroidRuntime(12851): at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:755) E/AndroidRuntime(12851): at android.content.ContextWrapper.registerReceiver(ContextWrapper.java:755) E/AndroidRuntime(12851): at com.eopeter.fluttermapboxnavigation.activity.NavigationActivity.onCreate(NavigationActivity.kt:142) E/AndroidRuntime(12851): at android.app.Activity.performCreate(Activity.java:8595) E/AndroidRuntime(12851): at android.app.Activity.performCreate(Activity.java:8573) E/AndroidRuntime(12851): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1456) E/AndroidRuntime(12851): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3764) E/AndroidRuntime(12851): ... 12 more E/AndroidRuntime(12851): Caused by: android.os.RemoteException: Remote stack trace: E/AndroidRuntime(12851): at com.android.server.am.ActivityManagerService.registerReceiverWithFeature(ActivityManagerService.java:13927) E/AndroidRuntime(12851): at android.app.IActivityManager$Stub.onTransact(IActivityManager.java:2570) E/AndroidRuntime(12851): at com.android.server.am.ActivityManagerService.onTransact(ActivityManagerService.java:2720) E/AndroidRuntime(12851): at android.os.Binder.execTransactInternal(Binder.java:1339) E/AndroidRuntime(12851): at android.os.Binder.execTransact(Binder.java:1275) E/AndroidRuntime(12851):

Arshad-ullah avatar Sep 10 '24 12:09 Arshad-ullah

Will be fixed when this is merged and published to pub.dev

https://github.com/eopeter/flutter_mapbox_navigation/pull/374/

For now can update this code in your locally stored pub-cache version of this package and reference it locally in your pubspec.yaml

xavidram avatar Nov 20 '24 17:11 xavidram

Will be fixed when this is merged and published to pub.dev

#374

For now can update this code in your locally stored pub-cache version of this package and reference it locally in your pubspec.yaml

can you please add more description to your suggestion

prof-sarumbo avatar Mar 14 '25 14:03 prof-sarumbo

Hi @prof-sarumbo you need to update this file flutter_mapbox_navigation-0.2.2/android/src/main/kotlin/com/eopeter/fluttermapboxnavigation/activity/NavigationActivity.kt

to this `package com.eopeter.fluttermapboxnavigation.activity

import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.content.IntentFilter import android.location.Location import android.os.Build import android.os.Bundle import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat import com.eopeter.fluttermapboxnavigation.FlutterMapboxNavigationPlugin import com.eopeter.fluttermapboxnavigation.R import com.eopeter.fluttermapboxnavigation.databinding.NavigationActivityBinding import com.eopeter.fluttermapboxnavigation.models.MapBoxEvents import com.eopeter.fluttermapboxnavigation.models.MapBoxRouteProgressEvent import com.eopeter.fluttermapboxnavigation.models.Waypoint import com.eopeter.fluttermapboxnavigation.models.WaypointSet import com.eopeter.fluttermapboxnavigation.utilities.CustomInfoPanelEndNavButtonBinder import com.eopeter.fluttermapboxnavigation.utilities.PluginUtilities import com.eopeter.fluttermapboxnavigation.utilities.PluginUtilities.Companion.sendEvent import com.google.gson.Gson import com.mapbox.api.directions.v5.models.DirectionsRoute import com.mapbox.api.directions.v5.models.RouteOptions import com.mapbox.geojson.Point import com.mapbox.maps.MapView import com.mapbox.maps.Style import com.mapbox.maps.plugin.gestures.OnMapLongClickListener import com.mapbox.maps.plugin.gestures.gestures import com.mapbox.navigation.base.extensions.applyDefaultNavigationOptions import com.mapbox.navigation.base.extensions.applyLanguageAndVoiceUnitOptions import com.mapbox.navigation.base.options.NavigationOptions import com.mapbox.navigation.base.route.NavigationRoute import com.mapbox.navigation.base.route.NavigationRouterCallback import com.mapbox.navigation.base.route.RouterFailure import com.mapbox.navigation.base.route.RouterOrigin import com.mapbox.navigation.base.trip.model.RouteLegProgress import com.mapbox.navigation.base.trip.model.RouteProgress import com.mapbox.navigation.core.arrival.ArrivalObserver import com.mapbox.navigation.core.directions.session.RoutesObserver import com.mapbox.navigation.core.lifecycle.MapboxNavigationApp import com.mapbox.navigation.core.trip.session.BannerInstructionsObserver import com.mapbox.navigation.core.trip.session.LocationMatcherResult import com.mapbox.navigation.core.trip.session.LocationObserver import com.mapbox.navigation.core.trip.session.OffRouteObserver import com.mapbox.navigation.core.trip.session.RouteProgressObserver import com.mapbox.navigation.core.trip.session.VoiceInstructionsObserver import com.mapbox.navigation.dropin.map.MapViewObserver import com.mapbox.navigation.dropin.navigationview.NavigationViewListener import com.mapbox.navigation.utils.internal.ifNonNull

class NavigationActivity : AppCompatActivity() { private var finishBroadcastReceiver: BroadcastReceiver? = null private var addWayPointsBroadcastReceiver: BroadcastReceiver? = null private var points: MutableList<Waypoint> = mutableListOf() private var waypointSet: WaypointSet = WaypointSet() private var canResetRoute: Boolean = false private var accessToken: String? = null private var lastLocation: Location? = null private var isNavigationInProgress = false

private val navigationStateListener = object : NavigationViewListener() {
    override fun onFreeDrive() {
        // Handle free drive state
    }

    override fun onDestinationPreview() {
        // Handle destination preview state
    }

    override fun onRoutePreview() {
        // Handle route preview state
    }

    override fun onActiveNavigation() {
        isNavigationInProgress = true
    }

    override fun onArrival() {
        // Handle arrival state
    }
}

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setTheme(R.style.Theme_AppCompat_NoActionBar)
    binding = NavigationActivityBinding.inflate(layoutInflater)
    setContentView(binding.root)
    binding.navigationView.addListener(navigationStateListener)
    accessToken =
        PluginUtilities.getResourceFromContext(this.applicationContext, "mapbox_access_token")

    val navigationOptions = NavigationOptions.Builder(this.applicationContext)
        .accessToken(accessToken)
        .build()

    MapboxNavigationApp
        .setup(navigationOptions)
        .attach(this)

    if (FlutterMapboxNavigationPlugin.longPressDestinationEnabled) {
        binding.navigationView.registerMapObserver(onMapLongClick)
        binding.navigationView.customizeViewOptions {
            enableMapLongClickIntercept = false
        }
    }

    val act = this
    // Add custom view binders
    binding.navigationView.customizeViewBinders {
        infoPanelEndNavigationButtonBinder =
            CustomInfoPanelEndNavButtonBinder(act)
    }

    MapboxNavigationApp.current()?.registerBannerInstructionsObserver(bannerInstructionObserver)
    MapboxNavigationApp.current()?.registerVoiceInstructionsObserver(voiceInstructionObserver)
    MapboxNavigationApp.current()?.registerOffRouteObserver(offRouteObserver)
    MapboxNavigationApp.current()?.registerRoutesObserver(routesObserver)
    MapboxNavigationApp.current()?.registerLocationObserver(locationObserver)
    MapboxNavigationApp.current()?.registerRouteProgressObserver(routeProgressObserver)
    MapboxNavigationApp.current()?.registerArrivalObserver(arrivalObserver)

    finishBroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            finish()
        }
    }

    addWayPointsBroadcastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            //get waypoints
            val stops = intent.getSerializableExtra("waypoints") as? MutableList<Waypoint>
            val nextIndex = 1
            if (stops != null) {
                //append to points
                if (points.count() >= nextIndex)
                    points.addAll(nextIndex, stops)
                else
                    points.addAll(stops)
            }
        }
    }

    // Register broadcast receivers with appropriate flags for Android 14
    ContextCompat.registerReceiver(
        this,
        finishBroadcastReceiver,
        IntentFilter(NavigationLauncher.KEY_STOP_NAVIGATION),
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            ContextCompat.RECEIVER_NOT_EXPORTED
        } else {
            ContextCompat.RECEIVER_EXPORTED
        }
    )

    ContextCompat.registerReceiver(
        this,
        addWayPointsBroadcastReceiver,
        IntentFilter(NavigationLauncher.KEY_ADD_WAYPOINTS),
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            ContextCompat.RECEIVER_NOT_EXPORTED
        } else {
            ContextCompat.RECEIVER_EXPORTED
        }
    )

    // Set the style Uri
    var styleUrlDay = FlutterMapboxNavigationPlugin.mapStyleUrlDay
    var styleUrlNight = FlutterMapboxNavigationPlugin.mapStyleUrlNight

    if (styleUrlDay == null) styleUrlDay = Style.MAPBOX_STREETS
    if (styleUrlNight == null) styleUrlNight = Style.DARK
    
    // set map style
    binding.navigationView.customizeViewOptions {
        mapStyleUriDay = styleUrlDay
        mapStyleUriNight = styleUrlNight
    }

    if (FlutterMapboxNavigationPlugin.enableFreeDriveMode) {
        binding.navigationView.api.routeReplayEnabled(FlutterMapboxNavigationPlugin.simulateRoute)
        binding.navigationView.api.startFreeDrive()
        return
    }

    val p = intent.getSerializableExtra("waypoints") as? MutableList<Waypoint>
    if (p != null) points = p
    points.map { waypointSet.add(it) }
    requestRoutes(waypointSet)
}

override fun onDestroy() {
    super.onDestroy()
    if (FlutterMapboxNavigationPlugin.longPressDestinationEnabled) {
        binding.navigationView.unregisterMapObserver(onMapLongClick)
    }
    binding.navigationView.removeListener(navigationStateListener)

    MapboxNavigationApp.current()?.unregisterBannerInstructionsObserver(bannerInstructionObserver)
    MapboxNavigationApp.current()?.unregisterVoiceInstructionsObserver(voiceInstructionObserver)
    MapboxNavigationApp.current()?.unregisterOffRouteObserver(offRouteObserver)
    MapboxNavigationApp.current()?.unregisterRoutesObserver(routesObserver)
    MapboxNavigationApp.current()?.unregisterLocationObserver(locationObserver)
    MapboxNavigationApp.current()?.unregisterRouteProgressObserver(routeProgressObserver)
    MapboxNavigationApp.current()?.unregisterArrivalObserver(arrivalObserver)

    // Unregister receivers
    finishBroadcastReceiver?.let { unregisterReceiver(it) }
    addWayPointsBroadcastReceiver?.let { unregisterReceiver(it) }
}

fun tryCancelNavigation() {
    if (isNavigationInProgress) {
        isNavigationInProgress = false
        sendEvent(MapBoxEvents.NAVIGATION_CANCELLED)
    }
}

private fun requestRoutes(waypointSet: WaypointSet) {
    sendEvent(MapBoxEvents.ROUTE_BUILDING)
    MapboxNavigationApp.current()!!.requestRoutes(
        routeOptions = RouteOptions
            .builder()
            .applyDefaultNavigationOptions()
            .applyLanguageAndVoiceUnitOptions(this)
            .coordinatesList(waypointSet.coordinatesList())
            .waypointIndicesList(waypointSet.waypointsIndices())
            .waypointNamesList(waypointSet.waypointsNames())
            .language(FlutterMapboxNavigationPlugin.navigationLanguage)
            .alternatives(FlutterMapboxNavigationPlugin.showAlternateRoutes)
            .voiceUnits(FlutterMapboxNavigationPlugin.navigationVoiceUnits)
            .bannerInstructions(FlutterMapboxNavigationPlugin.bannerInstructionsEnabled)
            .voiceInstructions(FlutterMapboxNavigationPlugin.voiceInstructionsEnabled)
            .steps(true)
            .build(),
        callback = object : NavigationRouterCallback {
            override fun onCanceled(routeOptions: RouteOptions, routerOrigin: RouterOrigin) {
                sendEvent(MapBoxEvents.ROUTE_BUILD_CANCELLED)
            }

            override fun onFailure(reasons: List<RouterFailure>, routeOptions: RouteOptions) {
                sendEvent(MapBoxEvents.ROUTE_BUILD_FAILED)
            }

            override fun onRoutesReady(
                routes: List<NavigationRoute>,
                routerOrigin: RouterOrigin
            ) {
                sendEvent(
                    MapBoxEvents.ROUTE_BUILT,
                    Gson().toJson(routes.map { it.directionsRoute.toJson() })
                )
                if (routes.isEmpty()) {
                    sendEvent(MapBoxEvents.ROUTE_BUILD_NO_ROUTES_FOUND)
                    return
                }
                binding.navigationView.api.routeReplayEnabled(FlutterMapboxNavigationPlugin.simulateRoute)
                binding.navigationView.api.startActiveGuidance(routes)
            }
        }
    )
}

private fun addWaypoint(destination: Point, name: String?) {
    val originLocation = lastLocation
    val originPoint = originLocation?.let {
        Point.fromLngLat(it.longitude, it.latitude)
    } ?: return

    // we always start a route from the current location
    if (addedWaypoints.isEmpty) {
        addedWaypoints.add(Waypoint(originPoint))
    }

    if (!name.isNullOrBlank()) {
        addedWaypoints.add(Waypoint(name, destination))
    } else {
        addedWaypoints.add(Waypoint(destination, true))
    }

    MapboxNavigationApp.current()!!.requestRoutes(
        routeOptions = RouteOptions
            .builder()
            .applyDefaultNavigationOptions()
            .applyLanguageAndVoiceUnitOptions(this)
            .coordinatesList(addedWaypoints.coordinatesList())
            .waypointIndicesList(addedWaypoints.waypointsIndices())
            .waypointNamesList(addedWaypoints.waypointsNames())
            .alternatives(true)
            .build(),
        callback = object : NavigationRouterCallback {
            override fun onRoutesReady(
                routes: List<NavigationRoute>,
                routerOrigin: RouterOrigin
            ) {
                sendEvent(
                    MapBoxEvents.ROUTE_BUILT,
                    Gson().toJson(routes.map { it.directionsRoute.toJson() })
                )
                binding.navigationView.api.routeReplayEnabled(true)
                binding.navigationView.api.startActiveGuidance(routes)
            }

            override fun onFailure(
                reasons: List<RouterFailure>,
                routeOptions: RouteOptions
            ) {
                sendEvent(MapBoxEvents.ROUTE_BUILD_FAILED)
            }

            override fun onCanceled(routeOptions: RouteOptions, routerOrigin: RouterOrigin) {
                sendEvent(MapBoxEvents.ROUTE_BUILD_CANCELLED)
            }
        }
    )
}

private val routeProgressObserver = RouteProgressObserver { routeProgress ->
    //Notify the client
    val progressEvent = MapBoxRouteProgressEvent(routeProgress)
    FlutterMapboxNavigationPlugin.distanceRemaining = routeProgress.distanceRemaining
    FlutterMapboxNavigationPlugin.durationRemaining = routeProgress.durationRemaining
    sendEvent(progressEvent)
}

private val arrivalObserver: ArrivalObserver = object : ArrivalObserver {
    override fun onFinalDestinationArrival(routeProgress: RouteProgress) {
        isNavigationInProgress = false
        sendEvent(MapBoxEvents.ON_ARRIVAL)
    }

    override fun onNextRouteLegStart(routeLegProgress: RouteLegProgress) {
        // Handle next route leg start
    }

    override fun onWaypointArrival(routeProgress: RouteProgress) {
        // Handle waypoint arrival
    }
}

private val locationObserver = object : LocationObserver {
    override fun onNewLocationMatcherResult(locationMatcherResult: LocationMatcherResult) {
        lastLocation = locationMatcherResult.enhancedLocation
    }

    override fun onNewRawLocation(rawLocation: Location) {
        // no impl
    }
}

private val bannerInstructionObserver = BannerInstructionsObserver { bannerInstructions ->
    sendEvent(MapBoxEvents.BANNER_INSTRUCTION, bannerInstructions.primary().text())
}

private val voiceInstructionObserver = VoiceInstructionsObserver { voiceInstructions ->
    sendEvent(MapBoxEvents.SPEECH_ANNOUNCEMENT, voiceInstructions.announcement().toString())
}

private val offRouteObserver = OffRouteObserver { offRoute ->
    if (offRoute) {
        sendEvent(MapBoxEvents.USER_OFF_ROUTE)
    }
}

private val routesObserver = RoutesObserver { routeUpdateResult ->
    if (routeUpdateResult.navigationRoutes.isNotEmpty()) {
        sendEvent(MapBoxEvents.REROUTE_ALONG)
    }
}

private val onMapLongClick = object : MapViewObserver(), OnMapLongClickListener {
    override fun onAttached(mapView: MapView) {
        mapView.gestures.addOnMapLongClickListener(this)
    }

    override fun onDetached(mapView: MapView) {
        mapView.gestures.removeOnMapLongClickListener(this)
    }

    override fun onMapLongClick(point: Point): Boolean {
        ifNonNull(lastLocation) {
            val waypointSet = WaypointSet()
            waypointSet.add(Waypoint(Point.fromLngLat(it.longitude, it.latitude)))
            waypointSet.add(Waypoint(point))
            requestRoutes(waypointSet)
        }
        return false
    }
}

private lateinit var binding: NavigationActivityBinding
private val addedWaypoints = WaypointSet()

}`

JaguarPetroleum avatar Jun 23 '25 12:06 JaguarPetroleum