Skip to content

Module Navigation

Tomas Valenta edited this page Sep 6, 2019 · 16 revisions

Specialized module for simple implementation of Navigation functionality including Signpost View (Full, Simplified), Simple Lanes View, Infobar, Route Preview Controls, Current Speed View, Speed Limit View and Action Menu. Every feature is customizable by end developer (can be turned on/off or styled).

Before you start, please use README to learn how to integrate this module into your project.

NOTE: This module uses custom global theme attributes. Please define them first or use/extend our predefined theme! (otherwise, the app will crash :( )

Navigation - Default

The most basic example. It shows the Navigation module with zero lines of configuration. It also contains basic location access and permission logic. This sample use your current location as start position, so you can try the real navigation with it.

Preview

Code

Xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/navigationFragment"
        class="com.sygic.maps.module.navigation.NavigationFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

Activity

class NavigationDefaultActivity : CommonSampleActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_navigation_default)

        if (savedInstanceState == null) {
            createRoutePlanAndComputeRoute()
        }
    }

    private fun createRoutePlanAndComputeRoute() {
        requestLastValidLocation { lastValidLocation ->
            val routePlan = RoutePlan().apply {
                setStart(lastValidLocation)
                setDestination(GeoCoordinates(41.893056, 12.482778))
                routingOptions = RoutingOptions().apply {
                    transportMode = RoutingOptions.TransportMode.Car
                    routingType = RoutingOptions.RoutingType.Economic
                }
            }

            computePrimaryRoute(routePlan) { route ->
                (supportFragmentManager.findFragmentById(R.id.navigationFragment) as NavigationFragment).routeInfo =
                    route
            }
        }
    }

    private fun requestLastValidLocation(currentLocationCallback: (GeoCoordinates) -> Unit) {
        if (isPermissionNotGranted(Manifest.permission.ACCESS_FINE_LOCATION)) {
            requestPermission(Manifest.permission.ACCESS_FINE_LOCATION, REQUEST_CODE_PERMISSION_ACCESS_FINE_LOCATION)
            return
        }

        if (isGpsNotEnabled()) {
            if (isGooglePlayServicesAvailable()) {
                createGoogleApiLocationRequest(REQUEST_CODE_GOOGLE_API_CLIENT)
            } else {
                showGenericNoGpsDialog(REQUEST_CODE_SETTING_ACTIVITY)
            }
            return
        }

        getLastValidLocation(currentLocationCallback)
    }

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
        when (requestCode) {
            REQUEST_CODE_PERMISSION_ACCESS_FINE_LOCATION -> {
                if ((grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED)) {
                    createRoutePlanAndComputeRoute()
                } else {
                    longToast("Sorry, location permission is needed!")
                    finish()
                }
            }
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)

        when (requestCode) {
            REQUEST_CODE_SETTING_ACTIVITY, REQUEST_CODE_GOOGLE_API_CLIENT -> {
                if (isGpsEnabled()) {
                    createRoutePlanAndComputeRoute()
                } else {
                    longToast("GPS module is not enabled :(")
                    finish()
                }
            }
        }
    }
}

Sample


Navigation - Preview enabled

The most basic example with navigation preview mode enabled (the route demonstration is automatically started from the specific start position).

Preview

Code

Xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/navigationFragment"
        class="com.sygic.maps.module.navigation.NavigationFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:sygic_navigation_previewMode="true" />

</FrameLayout>

Activity

class NavigationPreviewEnabledActivity : CommonSampleActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_navigation_preview_enabled)

        if (savedInstanceState == null) {
            computePrimaryRoute(SampleDemonstrationRoutePlan()) { route ->
                (supportFragmentManager.findFragmentById(R.id.navigationFragment) as NavigationFragment).routeInfo = route
            }
        }
    }
}

Sample


Navigation - Simplified signpost

The navigation example with sygic_signpost_type set to simplified and navigation preview mode enabled.

Preview

Code

Xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/navigationFragment"
        class="com.sygic.maps.module.navigation.NavigationFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:sygic_navigation_previewMode="true"
        app:sygic_signpost_type="simplified" />

</FrameLayout>

Activity

class NavigationSimplifiedSignpostActivity : CommonSampleActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_navigation_simplified_signpost)

        if (savedInstanceState == null) {
            computePrimaryRoute(SampleDemonstrationRoutePlan()) { route ->
                (supportFragmentManager.findFragmentById(R.id.navigationFragment) as NavigationFragment).routeInfo = route
            }
        }
    }
}

Sample


Navigation - Infobar custom click listener

The navigation example with custom infobar click listener without braking the default lock functionality.

Preview

Code

Xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/navigationFragment"
        class="com.sygic.maps.module.navigation.NavigationFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:sygic_navigation_previewMode="true" />

</FrameLayout>

Activity

class NavigationInfobarCustomClickListenerActivity : CommonSampleActivity() {

    private var fanfareMediaPlayer: MediaPlayer? = null
    private lateinit var navigationFragment: NavigationFragment

    private val unlockedLeftInfobarButtonClickListener = object : OnInfobarButtonClickListener {
        override val button = NavigationDefaultUnlockedLeftInfobarButton()
        override fun onButtonClick() = lockVehicle()
    }

    private val customLeftInfobarButtonClickListener = object : OnInfobarButtonClickListener {
        override val button = InfobarButton(
            R.drawable.ic_play,
            R.drawable.bg_infobar_button_rounded,
            R.color.white,
            R.color.colorAccent
        )

        override fun onButtonClick() = playFanfare()
    }

    private val cameraModeChangedListener = object : Camera.ModeChangedListener {
        override fun onRotationModeChanged(@Camera.RotationMode mode: Int) {}
        override fun onMovementModeChanged(@Camera.MovementMode mode: Int) {
            when (mode) {
                Camera.MovementMode.Free ->
                    setLeftInfobarButtonClickListener(unlockedLeftInfobarButtonClickListener)
                Camera.MovementMode.FollowGpsPosition, Camera.MovementMode.FollowGpsPositionWithAutozoom ->
                    setLeftInfobarButtonClickListener(customLeftInfobarButtonClickListener)
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_navigation_infobar_custom_click_listener)

        fanfareMediaPlayer = MediaPlayer.create(this, R.raw.fanfare)
        navigationFragment = (supportFragmentManager.findFragmentById(R.id.navigationFragment) as NavigationFragment)

        if (savedInstanceState == null) {
            setLeftInfobarButtonClickListener(customLeftInfobarButtonClickListener)
            computePrimaryRoute(SampleDemonstrationRoutePlan()) {
                navigationFragment.routeInfo = it
            }
        }
    }

    override fun onResume() {
        super.onResume()

        navigationFragment.cameraDataModel.addModeChangedListener(cameraModeChangedListener)
    }

    private fun setLeftInfobarButtonClickListener(listener: OnInfobarButtonClickListener) =
        navigationFragment.setOnInfobarButtonClickListener(InfobarButtonType.LEFT, listener)

    private fun playFanfare() {
        fanfareMediaPlayer?.apply {
            if (isPlaying) {
                stop()
                prepare()
            }

            start()
        }
    }

    private fun lockVehicle() {
        with(supportFragmentManager.findFragmentById(R.id.navigationFragment)) {
            if (this is NavigationFragment) {
                cameraDataModel.rotationMode = Camera.RotationMode.Vehicle
                cameraDataModel.movementMode = Camera.MovementMode.FollowGpsPositionWithAutozoom
            }
        }
    }

    override fun onPause() {
        super.onPause()

        ((supportFragmentManager.findFragmentById(R.id.navigationFragment) as NavigationFragment))
            .cameraDataModel.removeModeChangedListener(cameraModeChangedListener)
    }

    override fun onDestroy() {
        super.onDestroy()

        fanfareMediaPlayer?.apply {
            stop()
            if (isFinishing) release()
        }
    }
}

Sample