Skip to content

Android SmartDrive framework

Mārtiņš edited this page Jan 10, 2024 · 27 revisions

SmartDrive SDK Documentation - v1.2.1 (10 Jan, 2024)

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).

Release Notes

1. Installation Guide

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.

1.1. Overview

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.

1.2. Requirements

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_LOCATION

Tip

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_RECOGNITION

While 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.

1.3. Integration

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.

Step 1. Configure gradle.properties file

github_username=<GITHUB_USERNAME>
github_key=<PERSONAL_ACCESS_TOKEN>

Step 2. Add repository to your project in gradle.build (top-level) file

repositories { 
    maven { 
        url "https://maven.pkg.github.com/scopetech/Frameworks-Mobile" 
        credentials { 
            username = github_username 
            password = github_key 
        } 
    } 
}

Step 3. Add dependecies to your project in gradle.build (module-level) file

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.

2. SmartDrive Initialization

2.1. Configuration

2.1.1. Initial Configuration

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)
}

2.1.2. Record Only - Beacon Trips / Smart Trips

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)

2.1.3. Auto Sending

If enabled true trip auto sending happens automatically, no additional code needed.

SCPSmartDriveManager.getInstance(context).isTripAutoSendingEnabled = true

2.1.4. Auto Resend Failed Trips

If enabled true framework will try to send failed trips automatically.

SCPSmartDriveManager.getInstance(context).resendFailedTrips(true)

2.1.5. End Trip Timer

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
)

2.1.6. Extreme Battery Saver

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
)

2.1.7. Mode of Transport (MOT)

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
}

2.1.8. Real Time Trip sending

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
)

2.1.9. Accident Detection

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()
)

2.2.0. Distracted Driving

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
)

3. Trip Recording

3.1. Start SmartDrive

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()
    }
}

3.2. Stop SmartDrive

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.

4. Trip Management

Trip management is handled using TripManagmentHelper class.

4.1. Start/Stop Helper

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.

4.2. Trip List

If you want to retrieve local trip data, use:

SCPSmartDriveManager.getInstance(context).allTrips // all finished trips
SCPSmartDriveManager.getInstance(context).allUnsentTrips // all finished unsent trips 

4.3. Current Trip Info

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
    }
}

4.4. Delete Trip

If your logic requires to delete specific trip, you can do so using:

SCPSmartDriveManager.getInstance(this).deleteTrip(trip)

4.5. Send Trips

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.

4.6. Update Processing Trips

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()

4.7. Observe Trip Start/Stop

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()
}

5. Utilities

5.1. Unsent Trip Notifications

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)

5.2. Mock IN_VEHICLE state (for testing)

If you want to mock IN_VEHICLE state use:

SCPSmartDriveManager.getInstance(context).sendFakeInVehicleActivityUpdate(context)

Note

Used for smart (no BLE devices) solution only!

Clone this wiki locally