Mobility. Behavior. Intelligence.
Open Location and Mobility API/SDK for Rich Driver Behavior Analytics

TL Open API/SDK supports apps to automatically detect the start of a drive, and accurately monitors the driving behavior from any smart phone. Our patented mobility and sensor fusion technology allows reliable drive-data collection with minimal battery impact. The rich mobility data will be pre-computed on the device and uploaded into our backend, allowing for data analytics and comprehensive driver-risk scoring.

Driver Behavior Analytics App

Data points gathered include:

  • Start: date, time, place
  • Braking
  • Acceleration
  • Turning
  • End: date, time, place
  • Direction: North, East, South, West
  • Route
TL Open SDK/API Overview
Mobility SDK location drive analytics
Powerful Features in TL Open SDK/API

Here at Tourmaline Labs, we build powerful, smart, and comprehensive features into our TL Open SDK/API platform. Here you can see how each app delivers total performance features.

TL Mobility
  • 24/7 Location awareness
  • Distance/hours driven/time of day
  • Mobility detection & recording
  • Reverse geocoding - address
  • Start/stop time
  • Trip & activity dashboards
  • Turn-by-turn route
TL Behavior
  • 30-dimensional driver behavior (output)
  • Advanced calibration & normalization
  • Driver behavior events & scoring
  • Driver & phone usage alerts
  • Fleet & driving behavior dashboard
TL Intelligence
  • Contextual mobility behavior intelligence (N)
  • Crash detection intelligence
  • Driver & mobility behavior - benchmarking
  • Intelligence modules & dashboards
  • Mobility environment intelligence
TL Open API/SDK Example #1: Automatic Drive Detection

Do you have an app that would benefit from accurately detecting that your users are driving, what time of day and to where?

Extracting this location and time data from from different devices using different platforms is difficult, costly and typically consumes a lot of battery power.

Driver Behavior Analytics App

TL Open API/SDK provides SDK APIs to receive location and drive information:

  • after the start of a ride (backdated to the startpoint of the ride)
  • after the end of a ride (backdated to the start­ and endpoint of the ride)
  • with route information, including date and time travelled
TL Open API/SDK Example #2: Always On Location

You think location matters? We think so too! Apps often rely on location information to the benefit of the user experience. However, retrieving location data comes at a price - typically it comes with heavy battery consumption. Regardless of the brand and model of the device, minimizing location sampling while providing accurate positioning is difficult, time-consuming, and costly to develop.

Drive Detection App

TL Open API/SDK provides SDK APIs to receive location information

  • Upon request
  • At specified time intervals
  • Once a predefined distance has been travelled
  • Once a predefined time interval has passed with no movement
Why Us and Not Native Location API?

Our SDK is always on, and consumes a fraction of the battery power compared to other products. Power consumption is minimized by using our patent pending sensor calibration. Benefit from our analysis tool and get insights into your user data.

TL Open API/SDK Example #3: Activity Recognition

Automatically recognize and record any driving, walking and periods of no movement done by your users. This ultra low power consumption tool is ready to be integrated in your app. View start and end times; place, duration and route for each activity. The SDK is always on, so there’s no need to start and stop it. End users of your app will benefit from enhanced activity recognition and location data features.

Always On Location SDK

Data points gathered include:

  • Start: date, time, and place
  • End: date, time, and place
  • Route taken
How It Works

Our patent pending technology detects activities within moments of beginning. Setting the smartphone in motion triggers the accelerometer sensors built in the device and the SDK starts recording the activity right away. When the activity ends, the SDK falls back to hibernation waiting to be reawoken. Activity-detection information and location sampling will enable functions and services within your own app.

Why Our SDK?

Our SDK is always on, provides accurate, reliable data, and consumes 80% less battery power compared to other products. You can benefit from our analysis tool and get insights into your user data.

Use Case
Fleet Management
The TL Open API/SDK is the perfect hardware-free, easy-to-integrate solution for fleet management. The ready to use SDK can be integrated in any iPhone or Android app and is ready to operate. Driving activities are automatically recognized and accurate data is uploaded to the backend. This phone based solution helps maximize your vehicle efficiency. Safer, more efficient driving means less miles, less fuel and less downtime. Know where your workers are located for effective work order management. Boost ROI with better utilization, improved security and maintenance.
Technology Approach:
Artificial Intelligence and Sensor Fusion
  • Which sensor should we use to learn what?
  • How noisy is the data, are the sensors calibrated?
  • Which sensor chipset is used, how is it different?
  • Which sensor to use, when and for how long?
  • How much power is consumed by each sensor?
  • How to detect vehicle vs. phone motion?
Platform Model

(Self-learning phone-specific models to enhance battery and accuracy)

Mobility SDK location drive analytics
Uncertainty-based, information gain, decision process (Artificial intelligence, model-based reasoning)
Calibration within & across sensors
Feature Classifiers
(Signal processing, machine learning)
Performance: Phone vs. OBDII Dongle

We compared mobile phone mobility data (from our SDK) with OBDII dongle data.

Test Setup:
  • Phones: 13 different Android smartphones & iPhones 5 and 6
  • App / SDK: Betterways App (available on Goggle-play and Itunes)
  • Dongle: OBDII
  • Vehicles: 9 different vehicles (Ford F150, Sprinter Van, Volvo S40, Range Rover HSE etc).
  • Phone positions: cup holder, center concoul, passenger seat, glove box, pockets etc (normal user behavior simulation)
  • Miles: 6,000 miles with 5 drivers in cities & highways
Mobility SDK location drive analytics
Test Results:
Accuracy Threshold
Phone vs. Hardware
Phone vs. Phone
< 0.06g
95.3%
98.6%
< 0.1g
98.0%
99.1%
Mobility SDK location drive analytics
API

Getting started with TL Open API/SDK for iOS

Integrating TL Open API/SDK framework into a project

Install TL Open API/SDK using CocoaPods

We recommand installing TL Open API/SDK using CocoaPods, which provides a simple dependency management system that automates the error-prone process of manually configuring libraries. First make sure you have CocoaPods installed (you will also need to have Ruby installed):

sudo gem install cocoapods
pod setup
      

Now create an empty file in the root of your project directory, and name it Podfile or just run the following command:

pod init
      

Open and edit the Podfile as follow:

source 'https://github.com/CocoaPods/Specs.git'
source 'https://github.com/tourmalinelabs/iOSTLKitSDK.git'

platform :ios, '9.0'

use_frameworks!

pod 'TLKit'
...
            

Finally, save and close the Podfile and run pod install to setup your CocoaPods environment and import TLKit into your project. Make sure to start working from the .xcworkspace file that CocoaPods automatically creates, not the .xcodeproj you may have had open.

That’s it! You can start coding!

Using TL Open API/SDK

The heart of the TL Open API/SDK is the Context Engine. The engine needs to be initialized with a registered user in order to use any of its features.

Registering and authenticating users.

TL Open API/SDK needs to be initialized in order to use any of its features and starting TL Open API/SDK requires passing an CKAuthenticationManagerDelegate instance to the engine which handles authenticating against the TL Server.

In a production environment authentication should be done between the Application Server and the TL Open API/SDK server. This will prevent the API key from being leaked out as part of SSL proxying attack on the mobile device. See the Data Services api on how to register and authenticate a user.

For initial integration and evaluation purposes or for applications that do not have a server component we the CKDefaultAuth class which will provide registration and authentication services for the TL Server.

Initialization with the CKDefaultAuth is covered in the next section.

Starting, Stopping CKContextKit

An example of initializing the engine with the CKDefaultAuth is provided here:

#import 
...

[CKContextKit initWithApiKey:@"bdf760a8dbf64e35832c47d8d8dffcc0"
                             authMgr:[[CKDefaultAuth alloc]
                                 initWithApiKey:API_KEY
                                         userId:USERNAME
                                           pass:PASSWORD]
                       launchOptions:nil
                   withResultToQueue:dispatch_get_main_queue()
                         withHandler:^(BOOL successful, NSError *error) {
                             if (error) {
                                 NSLog(@"Failed to start TLKit with error: %@",
                                     error);
                                 return;
                             }
                         }];

CKContextKit attempts to validate permissions and see other necessary conditions are met when initializing the engine. If any of these conditions are not met it will fail with an error that can be used to debug the issue.

One example of where a failure would occur would be location permissions not being enabled for the application.

Once initialized there is no reason to destroy the engine unless you need to set a new CKAuthenticationManagerDelegate for a different user or password. In those cases, the engine can be destroyed as follows:

CKContextKit can be destroyed as follows:

[CKContextKit destroyWithResultToQueue:dispatch_get_main_queue()
                           withHandler:^(BOOL successful, NSError *error) {
                            if (error) {
                                NSLog(@"Stopping Contextkit Failed: %@", 
                                    error);
                                return;
                            }
                            NSLog(@"Stopped ContextKit!");
                        }];

Pre-authorize Location Manager access

CKContextKit utilizes GPS as one of it’s context sensor. As such it is best practice to request “Always” authorization from the user for accesssing location prior to initializing the engine.

Monitoring API

By default monitoring is disabled when the Engine is initialized. It needs to be explicitly enabled to track drives and locations. Enabling is done as follows:

CKContextKit.isMonitoring = YES;

Monitoring can be disabled at any time as follows:

CKContextKit.isMonitoring = YES;

If monitoring is enabled at any point during a drive that drive will be recorded.

Drive Monitoring

Drive monitoring functionality is accessed through the CKActivityManager

self.actMgr = [CKActivityManager new];

Starting, Stopping drive monitoring

Register a listener with the drive monitoring service as follows:

[self.actMgr 
    startDriveMonitoringToQueue:dispatch_get_main_queue()
                    withHandler:^(CKActivityEvent *evt, NSError * err) {
                                // Update UI
                                [weakSelf updateDataSource];
                                NSLog(@"Drive event: %@", evt);
                              }];

Note: multiple drive events may be received for the same drive as the drive progresses and the drive processing updates the drive with more accurate map points.

Drive events can be stopped as follows:

[self.actMgr stopDriveMonitoring];

Querying previous drives

Once started all drives will be recorded for querying either by date:

#import 
...

[self.actMgr queryDrivesFromDate:[NSDate distantPast]
                          toDate:[NSDate distantFuture]
                       withLimit:100
                         toQueue:dispatch_get_main_queue()
                     withHandler:^(NSArray *drives, NSError *error) {
                         if (!error) {
                             NSLog(@"Got drives: %@", drives);
                         }
                     }];

or by id:

NSUUID *driveId = ...;
[actMgr queryDriveById:driveId
               toQueue:dispatch_get_main_queue() 
           withHandler:^(NSArray *drives, NSError *err) {
               if (!error) {
                   NSLog(@"Found drive %@", drives[0]);
               }
           }];

Getting started with TL Open API/SDK for Android

Integrating TL Open API/SDK into a project

Add the TL Open API/SDK library to a gradle project as follows:

repositories {
    maven{ url 'https://raw.githubusercontent.com/tourmalinelabs/AndroidTLKitSDK/master'}
}

Modify the build.gradle file as follows:

Add libs as a repository

Add the SDK as a dependency as well as it’s dependencies.

dependencies {
    compile "com.tourmalinelabs.android:TLKit:7.0.17032300@aar"

    compile 'com.android.support:appcompat-v7:25.3.0'
    compile 'com.google.android.gms:play-services-base:8.1.0@aar'
    compile 'com.google.android.gms:play-services-location:8.1.0'
}

Add user permissions to the manifest

Add the following the following permissions to the Manifest.xml.

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
...
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
....
</manifest>

Using TL Open API/SDK

The heart of the TL Open API/SDK is the Context Engine. The engine needs to be initialized with a registered user in order to use any of its features.

Registering and authenticating users

TL Open API/SDK needs to be initialized in order to use any of its features and starting TL Open API/SDK requires passing an AuthMgr instance to the engine which handles authenticating against the TL Server.

In a production environment authentication should be done between the Application Server and the TL Open API/SDK server. This will prevent the API key from being leaked out as part of SSL proxying attack on the mobile device. See the Data Services api on how to register and authenticate a user.

For initial integration and evaluation purposes or for applications that do not have a server component we the DefaultAuthMgr class which will provide registration and authentication services for the TL Server.

Initialization with the DefaultAuthMgr is covered in the next section.

Initializing and destroying the engine

An example of initializing the engine with the DefaultAuthMgr is provided here:

Engine.Init( getApplicationContext(),
             ApiKey,
             new DefaultAuthMgr( this,
                                ApiKey,
                                "example@tourmalinelabs.com",
                                "password"),
             new CompletionListener() {
                 @Override
                 public void OnSuccess() { Engine.Monitoring(true); }

                 @Override
                 public void OnFail( int i, String s ) {}
             } );

Once initialized there is no reason to destroy the Engine unless you need to set a new AuthMgr for a different user or password. In those cases, the engine can be destroyed as follows:

Engine.Destroy(getApplicationContext(), 
               new CompletionListener() {
                    @Override
                    public void OnSuccess() {
                        Log.d(TAG, "Engine destroyed.");
                    }
                    @Override
                    public void OnFail( int i, String s ) {
                        Log.e(TAG, "Engine destruction failed.");
                    }
             });

Listening for Engine state changes

In addition to the completion listeners the engine also locally broadcasts lifecycle events which can be subscribed to via the Engine.ACTION_LIFECYCLE action as shown below.

LocalBroadcastManager mgr = LocalBroadcastManager.getInstance(this);
mgr.registerReceiver(
        new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent i) {
                int state = i.getIntExtra("state", -1);
                if (state == Engine.INIT_SUCCESS) {
                    Log.w(TAG, "Registering listeners on eng start");
                    tryToRestart = false;
                } else if (state == Engine.INIT_FAILURE) {
                    // Handle case of failure after the app is killed
                    // and restarted by the OS
                    String msg = i.getStringExtra("message");
                    int reason = i.getIntExtra("reason", 0);
                    if(!tryToRestart) {
                        Log.i( TAG,"Engine is trying to restart.");
                        tryToRestart = true;
                        StartEngine( );
                    } else {
                        Log.e( TAG, "Engine start KO after trying"
                               + " to restart -> nothing to do");
                        tryToRestart = false;
                    }
                    Log.w(TAG, "Eng start failed eng w/ reason "
                            + reason + ": " + msg);
                }
            }
        },
        new IntentFilter(Engine.ACTION_LIFECYCLE));

It is recommended to use this intent to register any listeners with the engine. This is because in event of an unexpected application termination the lifecycle registered listeners will be lost. When the engine automatically restarts with the app the intent will be the only notification that the engine is running.

Monitoring API

By default monitoring is disabled when the Engine is initialized. It needs to be explicitly enabled to track drives and locations. Enabling is done as follows:

Engine.Monitoring( true );

Monitoring can be disabled at any time as follows:

Engine.Monitoring( true );

If monitoring is enabled at any point during a drive that drive will be recorded.

Drive monitoring API

Listeners can be registered to receive Drive events. Note: They will only receive these events when monitoring is enabled. There is also an API for querying past drives.

Registering for drive events

Register a drive listener can be done as follows:

ActivityListener l = new ActivityListener() {
    @Override
    public void OnEvent( ActivityEvent e ) { Log.d(TAG, "Evt: " + e ); }

    @Override
    public void RegisterSucceeded() { Log.d(TAG, "Reg succeeded" ); }

    @Override
    public void RegisterFailed( int e ) { Log.w(TAG, "Reg err:" + e ); }
};
ActivityManager.RegisterDriveListener(l);

Multiple listeners can be registered via this API and all listeners will received the same events.

Note: Multiple events may be received for the same drive as the drive progresses and the drive processing updates the drive with more accurate map points.

To stop receiving drive monitoring unregister the listener as follows:

ActivityManager.UnregisterDriveListener(l);

Querying drive history

Some amount of drives are available for querying as follows:

ActivityManager.GetDrives( new Date( 0L),
                           new Date(),
                           new QueryHandler>() {
    @Override
    public void Result( ArrayList drives ) {
        Log.d("DriveMonitor", "Recorded drives:");
            for (DriveEvent e  : evts) {
                Log.d("DriveMonitor", e.toString());
            }
    }

    @Override
    public void OnFail( int i, String s ) {
        Log.e("DriveMonitor", "Query failed with err: " + i );
    }
});