Skip to main content

Driver Behaviour

|

The Driver Behaviour feature enables the analysis and scoring of a driver's behavior during a trip, identifying risky driving patterns and summarizing them with safety scores. This feature tracks both real-time and session-level driving events, such as harsh braking, cornering, or ignoring traffic signs, and evaluates overall risk using multiple criteria.

This data can be used to offer user feedback, identify unsafe habits, and assess safety levels over time. All information is processed using on-device sensor data (via the configured DataSource) and optionally matched to the road network if useMapMatchedPosition is enabled.

Starting and Stopping Analysis

To use the Driver Behaviour module, you first need to create a data source and then produce a DriverBehaviour instance using the factory method. The session is started using startAnalysis() and closed using stopAnalysis(), which returns a DriverBehaviourAnalysis instance representing the complete analysis.

val dataSource = DataSourceFactory.produceLive()
val driverBehaviour = DriverBehaviour.produce(dataSource!!, useMapMatchedPosition = true)

val started = driverBehaviour?.startAnalysis() ?: false

if (!started) {
Log.e("DriverBehaviour", "Failed to start analysis")
return
}

// ... after some driving

val result = driverBehaviour.stopAnalysis()

if (result?.valid != true) {
Log.w("DriverBehaviour", "The analysis is invalid and cannot be used")
return
}

// Process the analysis result
// processAnalysisResult(result)
danger

All DriverBehaviourAnalysis instances expose a valid property to determine whether the analysis is valid. Always verify this property before accessing or relying on the data it contains.

Inspecting a Driving Session

The result returned by stopAnalysis() (or via lastAnalysis) contains aggregate and detailed information on the trip:

if (result?.valid != true) {
Log.w("DriverBehaviour", "The analysis is invalid and cannot be used")
return
}

val startTime = result.startTime // Time object
val finishTime = result.finishTime // Time object
val distance = result.kilometersDriven // Double
val drivingDuration = result.minutesDriven // Double
val speedingTime = result.minutesSpeeding // Double
val totalElapsedTime = result.minutesTotalElapsed // Double
val tailgatingTime = result.minutesTailgating // Double

The session also includes risk scores:

val scores = result.drivingScores
if (scores == null) {
Log.w("DriverBehaviour", "No driving scores available")
return
}

val speedRisk = scores.speedAverageRiskScore
val speedVariableRisk = scores.speedVariableRiskScore
val harshAccelerationRisk = scores.harshAccelerationScore
val brakingRisk = scores.harshBrakingScore
val swervingRisk = scores.swervingScore
val corneringRisk = scores.corneringScore
val tailgatingRisk = scores.tailgatingScore
val ignoredSignsRisk = scores.ignoredStopSignsScore
val fatigue = scores.fatigueScore
val overallScore = scores.aggregateScore
info

Each score ranges from 0 (unsafe) to 100 (safe). A score of -1 means invalid or unavailable.

Inspecting Driving Events

Use the drivingEvents property of the session result to access discrete driving incidents that were detected:

val events = result.drivingEvents
events?.asArrayList()?.forEach { event ->
val time = event.time
val latitude = event.latitudeDeg
val longitude = event.longitudeDeg
val eventType = event.eventType

Log.d("DriverBehaviour",
"Event at $latitude, $longitude at ${time?.asLong()} with type $eventType")
}

Event types are defined by the EDrivingEvent enum:

Driving Event Types

Enum ValueDescription
NoEventNo event
StartingTripStarting a trip
FinishingTripFinishing a trip
RestingResting
HarshAccelerationHarsh acceleration
HarshBrakingHarsh braking
CorneringCornering
SwervingSwerving
TailgatingTailgating
IgnoringSignsIgnoring traffic signs

Real-time Feedback

If the analysis is ongoing, you can fetch real-time scores using:

val instantScores = driverBehaviour?.instantaneousScores
instantScores?.let { scores ->
val currentSpeedRisk = scores.speedAverageRiskScore
val currentBrakingRisk = scores.harshBrakingScore
val currentOverallScore = scores.aggregateScore

// Use scores for real-time feedback
updateUIWithScores(currentSpeedRisk, currentBrakingRisk, currentOverallScore)
}

These reflect the user's current behavior and are useful for immediate in-app feedback.

Stop Analysis and Get Last Analysis

To stop an ongoing analysis you can use:

val analysis = driverBehaviour?.stopAnalysis()
if (analysis?.valid != true) {
Log.w("DriverBehaviour", "No valid analysis available")
return
}

// Process the completed analysis
processCompletedAnalysis(analysis)

You can also retrieve the last completed analysis:

val lastAnalysis = driverBehaviour?.lastAnalysis
if (lastAnalysis?.valid != true) {
Log.w("DriverBehaviour", "No valid analysis available")
return
}

// Process the last analysis
processLastAnalysis(lastAnalysis)

Retrieve Past Analyses

All completed sessions are stored locally and accessible via:

val pastSessions = driverBehaviour?.allDriverBehaviourAnalyses
pastSessions?.forEach { analysis ->
if (analysis.valid) {
// Process each valid analysis
processAnalysis(analysis)
}
}

You can also obtain a combined analysis over a time interval:

val startTime = Time().apply {
longValue = System.currentTimeMillis() - (7 * 24 * 60 * 60 * 1000) // 7 days ago
}
val endTime = Time().apply {
longValue = System.currentTimeMillis() // Now
}

val combined = driverBehaviour?.getCombinedAnalysis(startTime, endTime)
if (combined?.valid == true) {
// Process combined analysis
processCombinedAnalysis(combined)
}

Analyses Storage Location

Driver behaviour analyses are stored locally on the device. Inside the app's directory, a folder named DriverBehaviour is created (at the same level as Data).

Data Cleanup

To save space or comply with privacy policies, older sessions can be erased:

val thirtyDaysAgo = Time().apply {
longValue = System.currentTimeMillis() - (30L * 24 * 60 * 60 * 1000) // 30 days ago
}

driverBehaviour?.eraseAnalysesOlderThan(thirtyDaysAgo)
info

Driver behaviour analysis requires a properly configured DataSource. Use DataSourceFactory.produceLive() to create a live data source for real-time position updates. To ensure reliable results, make sure to start and stop the analysis appropriately and avoid frequent interruptions or overlapping sessions.

Memory Management

Remember to properly release resources when done:

driverBehaviour?.stopAnalysis()
driverBehaviour?.release()
dataSource?.release()

Background Location

For driver behavior analysis while the app is in the background, ensure your app has the necessary location permissions:

private fun requestPermissions(activity: Activity): Boolean {
val permissions = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.ACCESS_COARSE_LOCATION,
Manifest.permission.ACCESS_BACKGROUND_LOCATION // For API 29+
)

return PermissionsHelper.requestPermissions(REQUEST_PERMISSIONS, activity, permissions)
}