Repository navigation
Android SmartDrive framework
This document describes how ScopeTechnology framework "SmartDrive" works and how to integrate into your application. While the target audience is coders/developers, it brings better understanding for those who are not too tech-savvy as well.
SmartDrive framework main functionality is to record trips. It supports trip recording:
- with Beacons (BLE device from ScopeTechnology).
- with MHub837s (BLE device from ScopeTechnology).
- without any BLE device (called "Smart" solution).
Following instructions will allow you to integrate our SDK into your application. Additionally, here is the demo sample app that you can follow while going through this document.
In introduction we mentioned that SmartDrive has two configuration types:
- for BLE devices (including ScopeTechnology - beacons and MHubs837s)
- for no BLE devices (smart solution)
Important
It is important to apply correct configuration and permissions for your specific business needs.
SDKs:
- Minimum SDK: 24 (Android 7.0)
- Target SDK: 33 (Android 13)
Permissions:
- Location permissions. Location permissions are used for getting location data that allows us to draw trip route and analyze trip in details, it also is needed for BLE device scanning.
Important
Mandatory permissions (for all SmartDrive configurations).
Manifest.permission.ACCESS_FINE_LOCATION
Manifest.permission.ACCESS_BACKGROUND_LOCATIONTip
Remember that for Build.VERSION_CODES.Q and higher both permissions are required, whereas below Build.VERSION_CODES.Q only ACCESS_FINE_LOCATION is needed.
Tip
use SDFPermissionUtil.getAllMandatoryLocationPermissions() to retrieve needed location permissions based on your device OS level.
- Activity Recognition permission. Activity Recognition allows our algorithm to understand weather the user is in a car (so we can detect trip in timely manner) or is taking a walk (to avoid ghost trips).
Important
Mandatory permission only for "smart" solution (no BLE decices).
Manifest.permission.ACTIVITY_RECOGNITIONWhile all of these permissions are bundled with our SDK library, some of them need to be requested during runtime. To understand how to do it, please read Android Developer Guide - Runtime permissions.
The library (SDK) is published on a private maven repository. Before you follow integration steps, make sure Scope Technologies has invited user (your GitHub dev account) to the repository with correct access. After that, developer will need to create GitHub personal access token (classic) with read permission to GitHub packages.
github_username=<GITHUB_USERNAME>
github_key=<PERSONAL_ACCESS_TOKEN>repositories {
maven {
url "https://maven.pkg.github.com/scopetech/Frameworks-Mobile"
credentials {
username = github_username
password = github_key
}
}
}implementation 'com.scopetechnology:smartdrive:1.2.1'
// the following line is needed to send trips to server
implementation 'com.scopetechnology:portal-api-base:1.2.0'
// the following line is needed to access some helper classes.
implementation 'com.scopetechnology:shared-classes:1.1.0' Important
Always confirm that you are using latest version.
All core configuration happens using SCPSmartDriveManager helper class.
with (SCPSmartDriveManager.getInstance(context)) {
appName = context.getString(R.string.app_name)
setAppNameAbbreviation(BuildConfig.APP_NAME)
setTripActivity(MainActivity::class.java) //This Activity will be opened when user clicks on notification
recordTripServiceHandledFromAppClass(true)
}We need to tell SmartDrive framework weather we want to use BLE devices for trip recording or use smart solution instead.
Important
If SmartDrive is intended to work with BLE devices
SCPSmartDriveManager.getInstance(context).tripRecordingOnlyWhenBeaconInRange = true
PrefUtil.setString(SharedConstants.PREFERENCES_CONFIG_TYPE, ConfigType.BLE.name)and additionally we would want to start bluetooth service (this ties together with BLE framework):
BLEManager.retrieveInstance(context).startForegroundBluetoothService()Important
If SmartDrive is intended to work with no BLE devices using smart solution
SCPSmartDriveManager.getInstance(context).tripRecordingOnlyWhenBeaconInRange = false
PrefUtil.setString(SharedConstants.PREFERENCES_CONFIG_TYPE, ConfigType.SMART.name)If enabled true trip auto sending happens automatically, no additional code needed.
SCPSmartDriveManager.getInstance(context).isTripAutoSendingEnabled = trueIf enabled true framework will try to send failed trips automatically.
SCPSmartDriveManager.getInstance(context).resendFailedTrips(true)Our solution uses trip end timer to validate if trip has truly finished (compared to heavy traffic with no movement for longer period of time). Trip end timer does not change recorded trip actual time range.
Warning
While you can change trip end timer based on your needs, it is strongly suggested to configure it between 3 - 5 minutes range to avoid ghost trips.
val tripEndTimerMinutes = 5.0f //Example for 5 minutes
SmartDriveUtils.setFloatPreference(
context,
MHubConstants.AUTOSTOP_THRESHOLD_PREF,
tripEndTimerMinutes
)By default extreme battery saver is disabled.
Warning
Using extreme battery saver can result in missing trips for some phone manufacturers.
val extremeBatterySaver = false
SmartDriveUtils.setBooleanPreference(
context,
MHubConstants.PREF_EXTREME_BATTERY_SAVER_ENABLED,
extremeBatterySaver
)Mode of Transport is clever solution to avoid trip recording on pre-defined transport types. For instance, if you want to avoid public transport buses or trains, you can configure so and framework will discard them. By default - disabled.
val motSkipTrips = listOf(
"Air", // Airplane
"Water", // Boats, jet skis
"Public", // Bus, trams etc.
"Railway" // Train
).toSet()
with (SCPSmartDriveManager.getInstance(context)) {
motEnabled = true
skipTripMOTs = motSkipTrips
}Real time trip sending configuration by default is disabled. It is used to display trip that are still in progress in real time (unfinished trips).
val realTimeTripDataSendingEnabled = true
SmartDriveUtils.setBooleanPreference(
context,
MHubConstants.PREF_REAL_TIME_TRIP_DATA_SENDING_ENABLED,
realTimeTripDataSendingEnabled
)When enabled, framework will be able to detect if driver has encountered serious accident. SDK will display a fragment view with a timer to the user. If user is not able to take action while timer runs out, we will call configured emergency phone number.
Note
This feature is available only for Beacon devices (BLE configuration).
val isAccidentDetectionEnabled = true
SmartDriveUtils.setBooleanPreference(
context,
MHubConstants.ACCIDENT_DETECTION_PREF,
ConfigHelper.isAccidentDetectionEnabled()
)When enabled will monitor driver actions during the trip. Following distracting driving types are available:
- PHONE USE - phone is being used while driving. Browsing different apps, tilting it, shaking it and other similar actions will be caught.
- PHONE CALLS - user is having a phone call while driving (WITHOUT headset that is considered safe).
val isDistractedDrivingEnabled = true
SmartDriveUtils.setBooleanPreference(
context,
MHubConstants.DISTRACTION_DETECTION_PREF,
isDistractedDrivingEnabled
)
// set distraction types which should be tracked
SmartDriveUtils.setBooleanPreference(
context,
MHubConstants.DISTRACTION_DETECTION_TYPE_PHONE_USE_PREF,
true
)
SmartDriveUtils.setBooleanPreference(
context,
MHubConstants.DISTRACTION_DETECTION_TYPE_PHONE_CALL_PREF,
true
)Tip
If you want to detect events based on minimum speed, make sure you are using library version v1.2.1+
SmartDriveUtils.setFloatPreference(
context,
MHubConstants.DISTRACTION_DETECTION_MINIMUM_SPEED_PREF,
5.0f // If user speed is below 5km/h -> ignore events
)To start SmartDrive simply call runRecordTripService when onboarding process has been finished for your app and view is ready. It will always check if service is running before creating a new one.
fun runSmartDrive(context: Context) {
val smartDriveManager = SCPSmartDriveManager.getInstance(context)
if (smartDriveManager.isTripAutoStartEnabled || smartDriveManager.activeTripInProgress()) {
smartDriveManager.runRecordTripService()
}
}To stop RecordTripService (core logic of trip recording) call stopRecordTripService().
fun stopSmartDrive(context: Context) {
SCPSmartDriveManager.getInstance(context).stopRecordTripService()
}Tip
If you want to clean all resources for SmartDrive, use logout() function.
SCPSmartDriveManager.getInstance(context).logout()Note
Calling logout function will automatically stop RecordTripService.
Caution
Calling logout function will remove all local trip data.
Trip management is handled using TripManagmentHelper class.
To start helper, use startHelper(). If you want to stop it, call stopHelper().
with (TripManagementHelper.getInstance(context)) {
startHelper()
}Tip
registerTripEventReceiver offers callback methods that are triggered on trip start or end - in case you want to add custom logic.
If you want to retrieve local trip data, use:
SCPSmartDriveManager.getInstance(context).allTrips // all finished trips
SCPSmartDriveManager.getInstance(context).allUnsentTrips // all finished unsent trips To retrieve current trip status (as LiveData) use:
liveActiveTripInProgress.observe(viewLifecycleOwner) { inProgress ->
// true or false
}Tip
If trip is in progress, you can also retrieve additional information (as LiveData)
with (TripManagementHelper.getInstance(requireContext())) {
tripDistance.observe(viewLifecycleOwner) {
//Receive trip distance updates (float)
}
tripDuration.observe(viewLifecycleOwner) {
//Receive trip duration (period)
}
tripCount.observe(viewLifecycleOwner) {
//Receive trip count (int)
}
unsentTripCount.observe(viewLifecycleOwner) {
//Receive unsent trip count (int)
}
tripSendingFinished.observe(viewLifecycleOwner) {
//Called when trip sending finished
}
}If your logic requires to delete specific trip, you can do so using:
SCPSmartDriveManager.getInstance(this).deleteTrip(trip)If you handle trip sending logic manually, use:
SCPSmartDriveManager.getInstance(this).sendTrip(trip) // Send specific trip
SCPSmartDriveManager.getInstance(this).sendAllTrips() // Send all trips Caution
If you use sendAllTrips() remember that it takes into account Mode of Transport (MOT) configuration.
Trip processing is usually done when the app is opened. It double checks if there is any trip locally that was not sent to Server side - if there is, it will re-send it and clear local data once done.
TripManagementHelper.getInstance(this).checkProcessingTrips()To receive updates on trip start or end, use following callback:
with (TripManagementHelper.getInstance(context)) {
registerTripEventReceiver(object : TripManagementHelper.TripEventReceiver() {
override fun onTripStarted() {
// Trip started
}
override fun onTripEnded() {
// Trip ended
}
})
startHelper()
}SmartDrive framework caters for cases where trips have not been sent to Server side. This usually happens if user has no network. Two notifications are being sent:
- After 2 days
- After 1 week
If you want to disable notifications for unsent trips, use:
SCPSmartDriveManager.getInstance(context).checkForOldTrips(false)If you want to mock IN_VEHICLE state use:
SCPSmartDriveManager.getInstance(context).sendFakeInVehicleActivityUpdate(context)Note
Used for smart (no BLE devices) solution only!
Consolidated SDK
SmartDrive
PortalApiBase
PortalApiClient
Wellness
SBeacon
- Overview
- Installation
- Initialization
- Beacon Scanning
- Beacon Pairing
- Trip Management
- Driving Behavior
- Calibration
- Event Handling
- Data Models
- API Reference
Consolidated SPM
SDApiManager
CCFrameworkOpen
SmartDrive
SBeacon