Repository navigation
Android SmartDrive framework
Tip
New integrations: start with the Android Simplified SDK Integration. Since SmartDrive 1.6.5 the SDK ships a facade, TripWrapper, that replaces the manual configuration, service control and broadcast handling this page describes with one host class, one typed configuration and five calls. This page remains the reference for the direct SCPSmartDriveManager API and for the permission and battery-optimisation requirements, which apply either way. Moving an existing app over: Android TripWrapper Migration Guide.
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).
Related: Requirements & permissions · Reading the current trip · Release notes · Demo app
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) for SmartDrive alone; 27 (Android 8.1) with the Wellness SDK
- Target SDK: 35 (Android 15)
Permissions. SmartDrive needs location, activity recognition and notification access to record trips and to keep the user informed. Some permissions are already declared in the SDK manifest, some must be declared by your app, and all of them have to be requested at runtime. In addition, dependable trip start detection needs the app to be excluded from battery optimisation, which is a device setting rather than a permission. See the table below and the details in the following subsections.
| Capability | Declared in | Needed for | If missing or denied |
|---|---|---|---|
Location — ACCESS_FINE_LOCATION + ACCESS_BACKGROUND_LOCATION ("Allow all the time") |
SDK manifest + runtime prompt (1.2.1) | All trip recording, BLE device scanning | No trips recorded |
Activity Recognition — ACTIVITY_RECOGNITION
|
SDK manifest + runtime prompt (1.2.2) | Trip detection in smart mode (no BLE devices) | Trips detected late or not at all, ghost trips |
Bluetooth — BLUETOOTH_SCAN, BLUETOOTH_CONNECT (Android 12+) |
BLE framework manifest + runtime prompt | Beacon / MHub mode only | No beacon trips |
Notifications — POST_NOTIFICATIONS (Android 13+) |
App manifest + runtime prompt (1.2.3) | Trip-in-progress notification and SDK warnings (location off, permission revoked, unsent trips, distracted driving) | No trip indicator and no SDK warnings — recording problems go unnoticed |
Phone state — READ_PHONE_STATE
|
App manifest + runtime prompt | Phone-call detection in Distracted Driving (2.2.0) | Phone calls during trips not detected |
Foreground service — FOREGROUND_SERVICE, FOREGROUND_SERVICE_LOCATION, FOREGROUND_SERVICE_DATA_SYNC
|
SDK manifest — no action needed | Background trip recording | — |
| Battery optimisation exemption | Device setting — not a runtime permission (1.2.4) | Timely trip start detection while the phone is idle (Doze) | Trips start late or are missed after the phone has been idle |
| Battery saver off (Power saving mode) | Device setting — not a permission (1.2.4) | Trip start detection and steady location updates during drives | Trips missed or started far too late; the phone keeps dropping into deep sleep, even while driving |
Tip
PermissionsUtil.getNotGrantedPermissions() in the demo app builds the complete list of runtime permissions for the current Android version, including the separate background-location request required on Android 11+.
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 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 devices).
Manifest.permission.ACTIVITY_RECOGNITIONSmartDrive records trips from a foreground service, and Android requires every foreground service to show an ongoing notification. SmartDrive shows a "Trip in progress" notification while recording, and it also uses notifications to warn the user when something prevents trips from being recorded or sent:
- location services turned off,
- location permission revoked,
- unsent trips older than 2 days / 1 week (see Section 5.1),
- distracted driving detected during a trip.
Starting with Android 13 (API 33) notifications require the runtime permission POST_NOTIFICATIONS. It is not bundled with the SDK, so declare it in your app manifest:
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />and request it at runtime together with the other permissions:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
permissionsRequired.add(arrayOf(Manifest.permission.POST_NOTIFICATIONS))
}Important
If the permission is denied, the recording service still runs, but the user sees neither the trip-in-progress notification nor any of the SDK warnings listed above — recording problems go unnoticed until trips are missing. Treat the notification permission as required for dependable trip recording.
If the user has denied the permission permanently, requestPermissions() no longer shows a dialog. Open the app's notification settings instead so the user can re-enable notifications:
val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
.putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName)
context.startActivity(intent)Note
All SDK notifications are posted to the notification channel default ("Application notifications", low importance), so the user can also silence them per channel in system settings. The title of the trip notification is the appName configured in Section 2.1.1, and tapping it opens the Activity passed to setTripActivity(). To show the trip notification only once the trip has covered a minimum distance, call showNotificationForValidTripOnly(true).
Android puts idle apps into Doze and App Standby, and most manufacturers add their own battery managers on top (Samsung Sleeping apps, Xiaomi / Huawei Autostart and similar). While the app is optimised this way, the system delays the activity-recognition and location wake-ups the SDK relies on to notice that a drive has started. Unlike the permissions above this is a device setting, not a runtime permission — there is no dialog the SDK can show for you.
- Trip recording itself is not affected. Once a trip is running, the recorder is a foreground service and keeps working with optimisation on.
- Trip start detection degrades. With optimisation on, trips may start late or be missed entirely after the phone has been parked and idle for a while — this is the most common cause of missing trips on Android.
Ask the user to exclude your app from battery optimisation. Check the current state with PowerManager:
fun Context.isIgnoringBatteryOptimizations(): Boolean {
val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
return powerManager.isIgnoringBatteryOptimizations(packageName)
}If the app is not excluded yet, open the system dialog that asks the user to exclude it. The dialog requires the following permission in your app manifest:
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />@SuppressLint("BatteryLife")
fun requestIgnoreBatteryOptimizations(context: Context) {
val intent = if (context.isIgnoringBatteryOptimizations()) {
// already excluded - open the system list so the user can review it
Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS)
} else {
Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
.setData(Uri.parse("package:${context.packageName}"))
}
context.startActivity(intent)
}Battery saver (Power saving mode) is a separate, stronger problem. The exemption above only takes your app out of App Standby / Doze restrictions; it does not switch off the system-wide Battery saver that the user can turn on in Quick Settings or that the phone enables automatically at a low battery level. With Battery saver on, Android and the manufacturer's power manager throttle location, activity recognition and background work for every app, and the phone drops back into deep sleep far more aggressively — including while the user is driving. In the field this shows up as trips that are missed entirely or start many kilometres after the real departure, on a phone where the app is correctly excluded from battery optimisation.
- Ask users to keep Battery saver off while they rely on trip recording. Most manufacturers offer no per-app exemption from it — the setting is all or nothing — so this is a user instruction, not something the SDK or your app can fix.
-
Detect it and tell the user. The SDK shows a notification when Battery saver is switched on. In your app, check
PowerManager.isPowerSaveModewhen the app comes to the foreground and offer the settings screen:
fun Context.isBatterySaverOn(): Boolean =
(getSystemService(Context.POWER_SERVICE) as PowerManager).isPowerSaveMode
fun openBatterySaverSettings(context: Context) {
context.startActivity(Intent(Settings.ACTION_BATTERY_SAVER_SETTINGS))
}Important
Treat the battery optimisation exemption as required for dependable trip start detection. Re-check it whenever the app comes to the foreground and show a message when the app is optimised again — users and system updates can re-enable optimisation at any time.
Note
Google Play reviews apps that declare REQUEST_IGNORE_BATTERY_OPTIMIZATIONS. Trip recording is an accepted use case, but explain in your store listing why the app needs it. On some devices the system dialog is not enough: Samsung users should additionally add the app to Never sleeping apps, and Xiaomi / Huawei users should enable Autostart for the app. The SDK logs Battery optimization feature is disabled. Which is good. when the exemption is in place — a quick check when investigating missed trips.
All runtime permission requests follow the standard Android flow — see 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.6.9'
// the following line is needed to send trips to server
implementation 'com.scopetechnology:portal-api-base:1.2.9'
// the following line is needed to access some helper classes.
implementation 'com.scopetechnology:shared-classes:1.1.7'If it is planned to use beacons for trip recording. Following dependency should be added:
implementation 'com.scopetechnology:ble:1.5.6'Or take all of them at matching versions with one dependency, com.scopetechnology:sdk:1.1.9; see the Android Consolidated SDK documentation.
Since SmartDrive 1.6.6 (BLE 1.5.6, shared classes 1.1.7, consolidated SDK 1.1.6) the artifacts are built against API 36 and their AAR metadata requires the consuming app to use compileSdk 36 or later; a lower compileSdk fails the build at checkAarMetadata. targetSdk and minSdk are the app's own choice.
Important
Always confirm that you are using latest version.
Note
Every setting in this section has a typed field on SmartDriveConfiguration when you integrate through the facade; the API mapping table lists them side by side. The code below is for direct SCPSmartDriveManager integrations.
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)SmartDrive associates every recorded trip with a vehicle through its unit serial number. It must be set before the recording service starts (see Section 3.1).
Important
Without a selected vehicle, trip events have no vehicle ID and trips cannot be sent to the backend.
val vehicles = BasePortalApi.getInsuredVehicles()
BasePortalApi.setSelectedVehicle(vehicles.first())Note
PortalBaseApi automatically selects the first vehicle in the InsuredVehicles list during login and caches the selection for subsequent app restarts. An explicit setSelectedVehicle call is only needed when the user switches to a different vehicle.
During SmartDrive configuration — before runRecordTripService() is called — ensure the selected vehicle's unit serial number is set:
BasePortalApi.getLiveSelectedVehicle().value?.let { vehicle ->
SCPSmartDriveManager.getInstance(context).lastSelectedUnitSerialNumber = vehicle.unitSerialNumber
}If PortalBaseApi framework is not configured and the app uses real-time event sending, assign the MProfiler unit id directly:
SCPSmartDriveManager.getInstance(context).lastSelectedUnitSerialNumber = MProfilerUnitIdIf 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 when next successful trip is sent.
SCPSmartDriveManager.getInstance(context).resendFailedTrips(true)Warning
This feature only retries failed trips when the next trip is successfully sent. If no subsequent trip succeeds (e.g., user stops driving, persistent network issues), failed trips will remain in the local database indefinitely. For guaranteed delivery, implement your own retry logic — see Section 4.8. Retry Failed Trips.
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
)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
"OffRoad" // OffRoad
).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).
private fun setupRealtimeTripSending(context: Context) {
val mProfilerConfiguration = MProfilerConfiguration(
"https://test.scopemp.net/Scope.MProfiler.ThirdPartyGateway.Api/api/v1/", // serviceURL
"ServiceProviderName", // serviceProvider
"m7JLq17YtFx7j7HS" // apiKey
)
SCPSmartDriveManager.getInstance(context).setupProfilerConfiguration(mProfilerConfiguration)
}Note
MProfiler config values in the example are just a placeholders but in reality they will look very similar. To get MProfiler Configuration real values, kindly ask Scope support.
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 While a trip is being recorded you can show a live "trip in progress" indicator in your app (status, current location, distance, duration, speed). Everything is exposed by the SDK as LiveData — no additional location client or timer is needed on the app side. There are two kinds of information: the recording status, which changes at trip boundaries, and the live components, which are updated while a trip is active.
| Value | API | Type / unit | Updated |
|---|---|---|---|
| Trip in progress |
liveActiveTripInProgress (top-level val in com.scope.common.utils) |
LiveData<Boolean> |
On trip start / end |
| Trip in progress (synchronous) | SCPSmartDriveManager.activeTripInProgress() |
Boolean |
— |
| Current speed | SCPSmartDriveManager.liveGPSSpeed |
LiveData<Float> — km/h
|
Every GPS fix |
| Current location | SCPSmartDriveManager.liveLocation |
LiveData<Location> |
Every GPS fix |
| Trip distance | TripManagementHelper.tripDistance |
LiveData<Float> — km
|
Every GPS fix while moving |
| Trip duration | TripManagementHelper.tripDuration |
LiveData<Period> (Joda-Time) |
Every second |
| Trip start time | SCPSmartDriveManager.tripStartTime |
DateTime? — null when no trip |
— |
| Trip ended | SCPSmartDriveManager.liveTripEnded |
SingleLiveEvent<Unit> |
On trip end |
Important
tripDistance and tripDuration are only updated after TripManagementHelper.startHelper() has been called (see Section 4.1).
Status — react to changes. Observe liveActiveTripInProgress, or call activeTripInProgress() when you need the value synchronously (for example when a screen is created):
import com.scope.common.utils.liveActiveTripInProgress
liveActiveTripInProgress.observe(this) { inProgress ->
tripStatusView.text = if (inProgress) "Status: RECORDING" else "Status: IDLE"
}
// synchronous check
val recording = SCPSmartDriveManager.getInstance(context).activeTripInProgress()Components — observe while active.
val smartDriveManager = SCPSmartDriveManager.getInstance(context)
val tripHelper = TripManagementHelper.getInstance(context)
// Speed in km/h
smartDriveManager.liveGPSSpeed.observe(this) { speed ->
tripSpeedView.text = "${speed.toInt()}"
}
// Latest GPS fix received by the recorder
smartDriveManager.liveLocation.observe(this) { location ->
location?.let { /* e.g. move a map marker to it.latitude / it.longitude */ }
}
// Distance in kilometres
tripHelper.tripDistance.observe(this) { distance ->
tripDistanceView.text = "${(distance * 10).toInt() / 10.0}"
}
// Duration as Joda-Time Period, refreshed every second
tripHelper.tripDuration.observe(this) { period ->
tripDurationView.text = String.format("%02d : %02d : %02d", period.hours, period.minutes, period.seconds)
}Units and behaviour:
-
liveGPSSpeedis km/h, taken from the GPS fix. It is0when the fix carries no speed or when position updates stall, and it is reset to0when the recording service stops. If you display speed while no trip is in progress, consider treating small values (below 5 km/h) as0to hide GPS drift. -
liveLocationis the latest validated GPS fix; it is reset tonullwhen the recording service stops. -
tripDistanceis kilometres and is reset to0when the trip ends. -
tripDurationis a Joda-TimePeriodcounted from the trip start time. The helper refreshes it once per second, so no app-side timer is needed; it is reset when the trip ends. -
liveActiveTripInProgressistrueonly for active trips. The SDK's internal passive trips (for example the cool-down after a manual trip stop) never set it. - These values live in process memory. If your app is relaunched while a trip is in progress,
startHelper()re-arms the duration timer for the ongoing trip automatically.
Trip boundaries. To react to trip start and end use registerTripEventReceiver (Section 4.7) or observe liveTripEnded.
Trip counters. TripManagementHelper also exposes counters that are refreshed when a trip ends or finishes sending:
with (TripManagementHelper.getInstance(context)) {
tripCount.observe(viewLifecycleOwner) {
//Receive trip count (int)
}
unsentTripCount.observe(viewLifecycleOwner) {
//Receive unsent trip count (int)
}
tripSendingFinished.observe(viewLifecycleOwner) {
//Called when trip sending finished
}
}Tip
Reference implementation: SmartDriveHelper.kt (LiveData accessors) and the status screen in MainActivity.kt in the demo app.
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.
This method checks if sent trips have finished processing on the server and are available via the trip API. It also recovers trips stuck in intermediate states or not properly finalized. It is recommended to call this when the app is opened.
TripManagementHelper.getInstance(this).checkProcessingTrips()Note
This method does not retry trips that are marked as failed to send. For that, see Section 4.8. Retry Failed Trips.
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()
}Trips can fail to send due to server timeouts, network issues, or the app process being killed by Android (e.g., thermal throttling, battery optimization) during transmission. In these cases, trips are marked as FAILED_TO_SEND in the local database.
Note
Through the facade this is TripWrapper.retryFailedTrips() (or ScopeSDK.retryFailedTrips()), which honours the mode-of-transport settings and, as a manual send, ignores the auto-resend setting and quarantine (since 1.6.9); the onTripSent callback plus tripCounts replace the TripManagementHelper observers below. The code in this section is for direct integrations.
The built-in resendFailedTrips feature (see Section 2.1.5) only retries failed trips after the next successful trip send. If no subsequent trip succeeds, failed trips remain unsent indefinitely.
To ensure reliable delivery, it is recommended to implement retry logic when the app comes to foreground:
// In your main Activity's onResume()
override fun onResume() {
super.onResume()
val smartDriveManager = SCPSmartDriveManager.getInstance(this)
val unsentTrips = smartDriveManager.allUnsentTrips
if (unsentTrips.isNotEmpty()) {
smartDriveManager.sendAllTrips()
}
}Tip
sendAllTrips() is safe to call even when there are no unsent trips. It is also recommended to call checkProcessingTrips() alongside retry logic after app restarts to recover any trips stuck in intermediate states.
If your app uses Mode of Transport (MOT) feature, use sendAllUnsentTrips() instead and pass your MOT configuration. This method will postpone sending trips that have incomplete MOT reports — where API calls to validate trip locations may have failed and it is not yet confirmed that the trip was driven by a vehicle rather than another mode of transport.
val motEnabled = true
val motSkipTrips = setOf("Public", "Railway") // MOT types to exclude
val manualSendingDeadline: DateTime? = null // null to send all, or set a cutoff date
smartDriveManager.sendAllUnsentTrips(motEnabled, motSkipTrips, manualSendingDeadline)To monitor unsent trip count and react when sending completes:
with (TripManagementHelper.getInstance(context)) {
unsentTripCount.observe(viewLifecycleOwner) {
// React to unsent trip count changes
}
tripSendingFinished.observe(viewLifecycleOwner) {
// Called when trip sending finishes
}
}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!
- Android Consolidated SDK documentation — one dependency for every Scope SDK; the entry point for new integrations.
- Android Simplified SDK Integration — the facade, step by step.
- Android TripWrapper SDK — the facade's reference, with the mapping from this page's settings to typed fields.
- Android Diagnostics and Health Snapshot — what the SDK reports about an integration at runtime.
- Release Notes — what changed in each SmartDrive version.
- SmartDriveDemo app — reference implementation: permissions, SDK configuration, trip status screen.
- Android PortalApiBase framework — backend API used for login, vehicle selection and trip retrieval.
- Android SBeacon framework — BLE device (beacon) scanning and pairing for beacon mode.
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