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.
- Kotlin
- Java
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)
DataSource dataSource = DataSourceFactory.produceLive();
DriverBehaviour driverBehaviour = DriverBehaviour.produce(dataSource, true);
boolean started = false;
if (driverBehaviour != null) {
started = driverBehaviour.startAnalysis();
}
if (!started) {
Log.e("DriverBehaviour", "Failed to start analysis");
return;
}
// ... after some driving
DriverBehaviourAnalysis result = driverBehaviour.stopAnalysis();
if (result == null || !result.getValid()) {
Log.w("DriverBehaviour", "The analysis is invalid and cannot be used");
return;
}
// Process the analysis result
// processAnalysisResult(result);
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:
- Kotlin
- Java
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
if (result == null || !result.getValid()) {
Log.w("DriverBehaviour", "The analysis is invalid and cannot be used");
return;
}
Time startTime = result.getStartTime(); // Time object
Time finishTime = result.getFinishTime(); // Time object
double distance = result.getKilometersDriven(); // Double
double drivingDuration = result.getMinutesDriven(); // Double
double speedingTime = result.getMinutesSpeeding(); // Double
double totalElapsedTime = result.getMinutesTotalElapsed(); // Double
double tailgatingTime = result.getMinutesTailgating(); // Double
The session also includes risk scores:
- Kotlin
- Java
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
DrivingScores scores = result.getDrivingScores();
if (scores == null) {
Log.w("DriverBehaviour", "No driving scores available");
return;
}
double speedRisk = scores.getSpeedAverageRiskScore();
double speedVariableRisk = scores.getSpeedVariableRiskScore();
double harshAccelerationRisk = scores.getHarshAccelerationScore();
double brakingRisk = scores.getHarshBrakingScore();
double swervingRisk = scores.getSwervingScore();
double corneringRisk = scores.getCorneringScore();
double tailgatingRisk = scores.getTailgatingScore();
double ignoredSignsRisk = scores.getIgnoredStopSignsScore();
double fatigue = scores.getFatigueScore();
double overallScore = scores.getAggregateScore();
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:
- Kotlin
- Java
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")
}
DrivingEventList events = result.getDrivingEvents();
if (events != null) {
for (DrivingEvent event : events.asArrayList()) {
Time time = event.getTime();
double latitude = event.getLatitudeDeg();
double longitude = event.getLongitudeDeg();
EDrivingEvent eventType = event.getEventType();
Log.d("DriverBehaviour",
"Event at " + latitude + ", " + longitude + " at " + (time != null ? time.asLong() : 0) + " with type " + eventType);
}
}
Event types are defined by the EDrivingEvent enum:
Driving Event Types
| Enum Value | Description |
|---|---|
NoEvent | No event |
StartingTrip | Starting a trip |
FinishingTrip | Finishing a trip |
Resting | Resting |
HarshAcceleration | Harsh acceleration |
HarshBraking | Harsh braking |
Cornering | Cornering |
Swerving | Swerving |
Tailgating | Tailgating |
IgnoringSigns | Ignoring traffic signs |
Real-time Feedback
If the analysis is ongoing, you can fetch real-time scores using:
- Kotlin
- Java
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)
}
DrivingScores instantScores = driverBehaviour != null ? driverBehaviour.getInstantaneousScores() : null;
if (instantScores != null) {
double currentSpeedRisk = instantScores.getSpeedAverageRiskScore();
double currentBrakingRisk = instantScores.getHarshBrakingScore();
double currentOverallScore = instantScores.getAggregateScore();
// 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:
- Kotlin
- Java
val analysis = driverBehaviour?.stopAnalysis()
if (analysis?.valid != true) {
Log.w("DriverBehaviour", "No valid analysis available")
return
}
// Process the completed analysis
processCompletedAnalysis(analysis)
DriverBehaviourAnalysis analysis = driverBehaviour != null ? driverBehaviour.stopAnalysis() : null;
if (analysis == null || !analysis.getValid()) {
Log.w("DriverBehaviour", "No valid analysis available");
return;
}
// Process the completed analysis
processCompletedAnalysis(analysis);
You can also retrieve the last completed analysis:
- Kotlin
- Java
val lastAnalysis = driverBehaviour?.lastAnalysis
if (lastAnalysis?.valid != true) {
Log.w("DriverBehaviour", "No valid analysis available")
return
}
// Process the last analysis
processLastAnalysis(lastAnalysis)
DriverBehaviourAnalysis lastAnalysis = driverBehaviour != null ? driverBehaviour.getLastAnalysis() : null;
if (lastAnalysis == null || !lastAnalysis.getValid()) {
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:
- Kotlin
- Java
val pastSessions = driverBehaviour?.allDriverBehaviourAnalyses
pastSessions?.forEach { analysis ->
if (analysis.valid) {
// Process each valid analysis
processAnalysis(analysis)
}
}
List<DriverBehaviourAnalysis> pastSessions = driverBehaviour != null ? driverBehaviour.getAllDriverBehaviourAnalyses() : null;
if (pastSessions != null) {
for (DriverBehaviourAnalysis analysis : pastSessions) {
if (analysis.getValid()) {
// Process each valid analysis
processAnalysis(analysis);
}
}
}
You can also obtain a combined analysis over a time interval:
- Kotlin
- Java
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)
}
Time startTime = new Time();
startTime.setLongValue(System.currentTimeMillis() - (7L * 24 * 60 * 60 * 1000)); // 7 days ago
Time endTime = new Time();
endTime.setLongValue(System.currentTimeMillis()); // Now
DriverBehaviourAnalysis combined = driverBehaviour != null ? driverBehaviour.getCombinedAnalysis(startTime, endTime) : null;
if (combined != null && combined.getValid()) {
// 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:
- Kotlin
- Java
val thirtyDaysAgo = Time().apply {
longValue = System.currentTimeMillis() - (30L * 24 * 60 * 60 * 1000) // 30 days ago
}
driverBehaviour?.eraseAnalysesOlderThan(thirtyDaysAgo)
Time thirtyDaysAgo = new Time();
thirtyDaysAgo.setLongValue(System.currentTimeMillis() - (30L * 24 * 60 * 60 * 1000)); // 30 days ago
if (driverBehaviour != null) {
driverBehaviour.eraseAnalysesOlderThan(thirtyDaysAgo);
}
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:
- Kotlin
- Java
driverBehaviour?.stopAnalysis()
driverBehaviour?.release()
dataSource?.release()
if (driverBehaviour != null) {
driverBehaviour.stopAnalysis();
driverBehaviour.release();
}
if (dataSource != null) {
dataSource.release();
}
Background Location
For driver behavior analysis while the app is in the background, ensure your app has the necessary location permissions:
- Kotlin
- Java
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)
}
private boolean requestPermissions(Activity activity) {
String[] permissions = new String[]{
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);
}