Speed Voice Warning ¶
Setup ¶
Download the
SpeedTTSWarning
project
archive file or clone the project with Git
See the Configure Android Example guide.
Run the example ¶
In Android Studio, from the
File
menu, select
Sync
Project
with
Gradle
Files
|
How it works ¶

1private val navigationService = NavigationService()
A navigation service is instantiated from which to start simulated navigation.
1override fun onCreate(savedInstanceState: Bundle?)
2{
3 super.onCreate(savedInstanceState)
4 setContentView(R.layout.activity_main)
5 gemSurfaceView = findViewById(R.id.gem_surface)
6 progressBar = findViewById(R.id.progressBar)
7 currentSpeed = findViewById(R.id.current_speed)
8 speedLimit = findViewById(R.id.speed_limit)
9 followCursorButton = findViewById(R.id.followCursor)
10 SdkSettings.onMapDataReady = onMapDataReady@{ isReady ->
11 if (!isReady) return@onMapDataReady
12 startNavigation()
13 }
14 ...
15 requestPermissions(this)
16 if (!Util.isInternetConnected(this))
17 {
18 showDialog("You must be connected to the internet!")
19 }
20}
onCreate()
function is overridden in the
MainActivity:
AppCompatActivity()
class.
findViewById()
is used to obtain pointers to the various
graphical user interface elements where text or graphical data
is to be displayed.
startNavigation()
function is called once the map data is loaded.
1private fun requestPermissions(activity: Activity): Boolean {
2 val permissions = arrayListOf(
3 Manifest.permission.INTERNET,
4 Manifest.permission.ACCESS_NETWORK_STATE,
5 Manifest.permission.ACCESS_FINE_LOCATION,
6 Manifest.permission.ACCESS_COARSE_LOCATION
7 )
8 return PermissionsHelper.requestPermissions(
9 REQUEST_PERMISSIONS, activity, permissions.toTypedArray()
10 )
11}
requestPermissions()
function requests internet and
location permissions from the user, if not already available.
1override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray)
2{
3 super.onRequestPermissionsResult(requestCode, permissions, grantResults)
4 if (requestCode != REQUEST_PERMISSIONS) return
5 for (item in grantResults)
6 {
7 if (item != PackageManager.PERMISSION_GRANTED)
8 {
9 finish()
10 exitProcess(0)
11 }
12 }
13 SdkCall.execute {
14 // Notice permission status had changed
15 PermissionsHelper.onRequestPermissionsResult(this, requestCode, grantResults)
16 }
17 startNavigation()
18}
onRequestPermissionsResult()
function is overridden, to receive
the results of the permission requests, and ends the program
if permissions are denied, otherwise, it calls the
startNavigation()
function below.
1private val navigationListener: NavigationListener = NavigationListener.create(
2 onNavigationStarted = {
3 SdkCall.execute {
4 gemSurfaceView.mapView?.let { mapView ->
5 mapView.preferences?.enableCursor = false
6 navRoute?.let { route ->
7 mapView.presentRoute(route)
8 }
9 // Start listening for new positions.
10 PositionService.addListener(positionListener, EDataType.Position)
11 enableGPSButton()
12 mapView.followPosition()
13 }
14 }
15 },
16 onNavigationInstructionUpdated = { instr ->
17 // From every new navigation instruction get the speed limit.
18 val limit = SdkCall.execute execute@{
19 val pair = GemUtil.getSpeedText(instr.currentStreetSpeedLimit, EUnitSystem.Metric)
20 speedLimitValue = pair.first.toInt()
21 return@execute pair.first + " " + pair.second
22 }
23 speedLimit.text = limit
24 },
25 onDestinationReached = {
26 // DON'T FORGET to remove the position listener after the navigation is done.
27 PositionService.removeListener(positionListener)
28 }
29)
onNavigationStarted
or
onDestinationReached
, which are the usual ones. In this case,
the
onNavigationInstructionUpdated
notification is also implemented,
because the current speed limit is included with the navigation
instructions, which are used for turns, for example.
1private val positionListener = object : PositionListener()
2{
3 override fun onNewPosition(value: PositionData)
4 {
5 // Get the current speed for every new position received
6 val speed = GemUtil.getSpeedText(value.speed, EUnitSystem.Metric).let { speedPair ->
7 currentSpeedValue = speedPair.first.toInt()
8 speedPair.first + " " + speedPair.second
9 }
10 if (currentSpeedValue > speedLimitValue)
11 {
12 if (!wasSpeedWarningPlayed)
13 {
14 SoundPlayingService.playText(GemUtil.getTTSString(EStringIds.eStrMindYourSpeed),
15 SoundPlayingListener(), SoundPlayingPreferences())
16 wasSpeedWarningPlayed = true
17 }
18 }
19 else
20 {
21 wasSpeedWarningPlayed = false
22 }
23 Util.postOnMain {
24 currentSpeed.text = speed
25 }
26 }
27}
speedLimitValue
.
SoundPlayingService.playText(GemUtil.getTTSString(EStringIds.eStrMindYourSpeed),
...
1private val routingProgressListener = ProgressListener.create(
2 onStarted = {
3 progressBar.visibility = View.VISIBLE
4 },
5 onCompleted = { _, _ ->
6 progressBar.visibility = View.GONE
7 },
8 postOnMain = true
9)
1private fun startNavigation()
2{
3 val startNavigationTask = {
4 val hasPermissions = PermissionsHelper.hasPermission(this,
5 Manifest.permission.ACCESS_FINE_LOCATION)
6 if (hasPermissions)
7 {
8 val destination = Landmark("Paris", 48.8566932, 2.3514616)
9 navigationService.cancelNavigation(navigationListener)
10 val error = navigationService.startNavigation(
11 destination,
12 navigationListener,
13 routingProgressListener,
14 )
15 Log.i(TAG, "MainActivity.startNavigation: after = $error")
16 }
17 }
18 SdkCall.execute {
19 lateinit var positionListener: PositionListener
20 if (PositionService.position?.isValid() == true)
21 {
22 startNavigationTask()
23 }
24 else
25 {
26 positionListener = PositionListener {
27 if (!it.isValid()) return@PositionListener
28 PositionService.removeListener(positionListener)
29 startNavigationTask()
30 }
31 PositionService.addListener(positionListener)
32 }
33 }
34}
startNavigation()
function queries the
PermissionsHelper
to
check if location permission has been obtained in order to start navigation.
navigationService.cancelNavigation(navigationListener)
navigationService.startNavigation()
PositionListener
added to the
PositionService
. Once the first valid location is received,
the listener is removed and navigation starts.
|
1private fun enableGPSButton() { 2 // Set actions for entering/ exiting following position mode. 3 gemSurfaceView.mapView?.apply { 4 onExitFollowingPosition = { 5 followCursorButton.visibility = View.VISIBLE 6 } 7 onEnterFollowingPosition = { 8 followCursorButton.visibility = View.GONE 9 } 10 // Set on click action for the GPS button. 11 followCursorButton.setOnClickListener { 12 SdkCall.execute { followPosition() } 13 } 14 } 15}
enableGPSButton()
causes a round purple button to appear in the lower
right corner of the screen, whenever the simulation is active and
the camera is not following the green arrow. This can happen if the user
does a pan away from the route during the simulation.
followPosition()
function is called,
and thus the camera starts to follow the green arrow once again.