VisTracks Library Integration Guide

Introduction

VisTracks provides a powerful and comprehensive solution for managing the movements and activities of mobile workers in general, and drivers subject to federal “hours of service” regulations in particular.

The full solution comprises a front-end app typically running on a tablet form-factor device, an administrative portal providing access to information about a fleet of vehicles, and a “back-end” cloud-resident platform that monitors and manages the real-time information transmitted from the tablets and other telematics devices.

This document focuses specifically on adding our front-end application to an existing application. This is provided by incorporating four android libraries into the application. An android library is a way of bundling code fragments into an easily accessible format.1

Prerequisites

Download VistracksApplicationIntegration.zip

Release Notes:

- vtlib-release.aar

Version: 1.0.15

Refer changes on application from http://developer.vistracks.com/releaseNotes/april2021_android_app_release_notes.pdf

- pt-sdk-release.aar

Version: 6.5.0

- wvalib-release.aar

Version: 1.0

- EldBleLib-release.aar

Version: 1.0.15

- hos-mobile-interface.aar

Version: 3.0.210323

- vehicle-interface.aar

Version: 1.1.0

- suntech-api.aar

Version: 2.1

- terminalio-debug.aar

Version: 3.2

Note: Dependencies versions updated (please review the steps)

How to Integrate Our Application

Step 1. In your project build.gradle file, add these repositories and dependencies

repositories {
    google()
    jcenter()
    maven { url 'https://maven.fabric.io/public' }
}

dependencies {
    classpath 'com.android.tools.build:gradle:4.1.2'
    classpath 'com.google.gms:google-services:4.3.5'
    classpath 'com.google.firebase:perf-plugin:1.3.4'
    classpath 'com.google.firebase:firebase-crashlytics-gradle:2.5.0'
    classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.72'
    classpath 'org.jetbrains.kotlin:kotlin-serialization:1.3.72'
    // Your other dependencies here 
}

Step 2. Add these values to your project build.gradle after your buildscript {…} tag as follows. This ensures that the application is receiving the correct versions of it’s dependencies

buildscript {...}

allprojects {
    repositories {
       google()
       maven { url 'https://jitpack.io' }
       jcenter()

       maven {
          name = "kotlinBintray"
          url = "https://kotlin.bintray.com/kotlinx/"
       }
    }
}

// Version numbers in single place
ext.v = [
    // SDK and tools
    minSdkVersion      : 19,
    targetSdkVersion   : 29,
    compiledSdkVersion : 29,
    buildToolsVersion  : '29.0.2',

    // App dependencies
    androidXActivityVersion    : '1.2.0',
    androidXAppCompatVersion   : '1.0.2', // NOTE: do not upgrade to 1.1.0, It has issue with language translation https://issuetracker.google.com/issues/140602653
    androidXCoreVersion        : '1.3.2',
    androidXEspressoVersion    : '3.1.0',
    androidXFragmentVersion    : '1.3.0',
    androidXLifecycleVersion   : '2.3.0',
    androidXPreferenceVersion  : '1.1.1',
    androidXRecyclerViewVersion: '1.1.0',
    androidXSqliteVersion      : '2.1.0',
    androidXTestVersion        : '1.3.0',
    androidXTestExtJUnitVersion: '1.1.2',
    androidXTransitionVersion  : '1.4.0',
    androidXVersion            : '1.0.0',
    commonsNetVersion          : '3.6',
    constraintLayoutVersion    : '2.0.4',
    daggerVersion              : '2.32',
    espressoVersion            : '3.3.0',
    eventBusVersion            : '3.2.0',
    exifinterfaceVersion       : '1.3.2',
    expandableRecyclerviewVersion: '1.3',
    fabVersion                 : '1.6.4',
    firebaseAnalyticsVersion   : '18.0.2',
    firebaseCrashlyticsVersion : '17.3.0',
    firebaseMessagingVersion   : '21.0.1',
    firebasePerfMonVersion     : '19.1.1',
    flexBoxVersion             : '1.1.1', //NOTE: do not upgrade, default values for alignItems and alignContent have been changed from stretch to flex_start starting from 2.0.0
    geometrisVersion           : '1.0.8',
    grpcVersion                : '1.34.0',
    gsonVersion                : '2.8.6',
    guavaVersion               : '24.1-jre',
    httpmimeVersion            : '4.2.2',
    jodaTimeVersion            : '2.10.6',
    jtsVersion                 : '1.13',
    junitJupiterVersion        : '5.7.0',
    junitVersion               : '4.13.1',
    klockVersion               : '1.12.0',
    kotlinxVersion             : '1.4.31',
    kotlinxDateTimeVersion     : '0.1.0',
    kotlinSerializationVersion : '1.0.0-RC2',
    kotlinCoroutinesVersion    : '1.4.1',
    materialVersion            : '1.3.0',
    mockitoVersion             : '3.7.7',
    multidexVersion            : '2.0.1',
    nordicsemiLogVersion       : '2.2.0',
    nordicsemiScannerVersion   : '1.4.2',
    nordicsemiBleVersion       : '2.2.4',
    obdJavaApiVersion          : '1.0',
    okHttpVersion              : '3.12.13', //NOTE: Version 3.13+ only supports Android 5+ so do not upgrade until minSdkVersion is 21+
    okIoVersion                : '2.10.0',
    playServicesMapsVersion    : '17.0.0',
    reactiveStreamsVersion     : '1.0.3',
    roboElectricVersion        : '4.5.1',
    roomVersion                : '2.2.6',
    rxAndroidVersion           : '3.0.0',
    rxBindingVersion           : '4.0.0',
    rxJavaVersion              : '3.0.10',
    squareOkHttpVersion        : '2.0.0',
    truetimeVersion            : '3.4',
    workVersion                : '2.5.0'
]

Step 3. In your app module build.gradle file, add

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'com.google.firebase.firebase-perf'
apply plugin: 'com.google.firebase.crashlytics'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlinx-serialization'

android {
    compileSdkVersion v.compiledSdkVersion
    buildToolsVersion v.buildToolsVersion
    defaultConfig {
        applicationId [your application id]
        minSdkVersion v.minSdkVersion
        targetSdkVersion v.targetSdkVersion
        versionCode 442
        // Have your other configuration code here
    }

    buildTypes {
        release {
            multiDexEnabled true
            // Have your other configuration code here
        }
    }

    compileOptions {
       coreLibraryDesugaringEnabled true
       sourceCompatibility JavaVersion.VERSION_1_8
       targetCompatibility JavaVersion.VERSION_1_8
    }

    kotlinOptions {
       jvmTarget = '1.8'
    }

    buildFeatures {
       viewBinding true
    }
}

Step 4. Add these configurations and dependencies in your application module

configurations.all {
    resolutionStrategy {
       force "androidx.legacy:legacy-support-v4:${v.androidXVersion}"
       force "org.reactivestreams:reactive-streams:${v.reactiveStreamsVersion}"
    }
    // currently required to get project to compile with android.arch.work:work-runtime-ktx dependency
    all*.exclude group: 'com.google.guava', module: 'listenablefuture'
}

dependencies {
    // includes all jar files in libs directory
    implementation fileTree(dir: 'libs', include: '*.jar')
    implementation fileTree(dir: 'libs', include: '*.aar')

    coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.1'

    // required here to avoid a warning complaining about the firebase or play services version not being specified.
    implementation "com.google.firebase:firebase-analytics-ktx:${v.firebaseAnalyticsVersion}"
    implementation "com.google.firebase:firebase-perf-ktx:${v.firebasePerfMonVersion}"

    // for wvalib
    implementation "com.squareup.okhttp:okhttp:${v.squareOkHttpVersion}"

    // Required to avoid build error similar to "Duplicate class com.google.common.util.concurrent.ListenableFuture found in modules jetified-guava-26.0-android.jar (com.google.guava:guava:26.0-android) and jetified-listenablefuture-1.0.jar (com.google.guava:listenablefuture:1.0)"
    // https://github.com/firebase/firebase-android-sdk/issues/1320#issuecomment-601159166
    implementation "com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava"

    // for pacific track sdk
    implementation "no.nordicsemi.android:log:${v.nordicsemiLogVersion}"
    implementation "no.nordicsemi.android.support.v18:scanner:${v.nordicsemiScannerVersion}"
    implementation "no.nordicsemi.android:ble-common:${v.nordicsemiBleVersion}"
    implementation "commons-net:commons-net:${v.commonsNetVersion}"
    implementation "com.google.guava:guava:${v.guavaVersion}"

    //Geometris sdk
    implementation "com.github.geometris:GeometrisMobile:${v.geometrisVersion}"

    //Barcode Scanning
    implementation 'com.google.zxing:android-integration:3.3.0'

    //RxJava
    implementation "com.jakewharton.rxbinding4:rxbinding:${v.rxBindingVersion}"
    implementation "io.reactivex.rxjava3:rxandroid:${v.rxAndroidVersion}"
    implementation "io.reactivex.rxjava3:rxjava:${v.rxJavaVersion}"

    // dagger
    annotationProcessor "com.google.dagger:dagger-compiler:${v.daggerVersion}"
    annotationProcessor "com.google.dagger:dagger-android-processor:${v.daggerVersion}"
    kapt "com.google.dagger:dagger-compiler:${v.daggerVersion}"
    kapt "com.google.dagger:dagger-android-processor:${v.daggerVersion}"
    implementation "com.google.dagger:dagger:${v.daggerVersion}"
    implementation "com.google.dagger:dagger-android-support:${v.daggerVersion}"
    compileOnly 'javax.annotation:jsr250-api:1.0'

    // OkHttp
    implementation "com.squareup.okhttp3:okhttp:${v.okHttpVersion}"
    implementation "com.squareup.okhttp3:logging-interceptor:${v.okHttpVersion}"
    implementation "com.squareup.okio:okio:${v.okIoVersion}"

    // Green Robot's Eventbus
    api "org.greenrobot:eventbus:${v.eventBusVersion}"

    // androidx libraries
    api "androidx.appcompat:appcompat:${v.androidXAppCompatVersion}"
    implementation "androidx.multidex:multidex:${v.multidexVersion}"
    implementation "androidx.work:work-runtime-ktx:${v.workVersion}"
    implementation "androidx.work:work-gcm:${v.workVersion}"
    implementation "androidx.core:core-ktx:${v.androidXCoreVersion}"
    implementation "androidx.fragment:fragment-ktx:${v.androidXFragmentVersion}"
    implementation "androidx.sqlite:sqlite-ktx:2.1.0"
    implementation "androidx.cardview:cardview:${v.androidXVersion}"
    implementation "androidx.gridlayout:gridlayout:${v.androidXVersion}"
    implementation "androidx.preference:preference-ktx:${v.androidXPreferenceVersion}"
    implementation "androidx.recyclerview:recyclerview:${v.androidXRecyclerViewVersion}"
    implementation "androidx.transition:transition:${v.androidXTransitionVersion}"
    implementation "androidx.constraintlayout:constraintlayout:${v.constraintLayoutVersion}"
    implementation "androidx.exifinterface:exifinterface:${v.exifinterfaceVersion}"
    api "com.google.android.material:material:${v.materialVersion}"

    // architecture components
    implementation "androidx.lifecycle:lifecycle-common-java8:${v.androidXLifecycleVersion}"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:${v.androidXLifecycleVersion}"
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:${v.androidXLifecycleVersion}"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:${v.androidXLifecycleVersion}"
    api "androidx.lifecycle:lifecycle-reactivestreams-ktx:${v.androidXLifecycleVersion}"

    // room
    implementation "androidx.room:room-runtime:${v.roomVersion}"
    kapt "androidx.room:room-compiler:${v.roomVersion}"
    // Kotlin Extensions and Coroutines support for Room
    implementation "androidx.room:room-ktx:${v.roomVersion}"
    testImplementation "androidx.room:room-testing:${v.roomVersion}"

    // used for fancier floating button that shows more options when pressed.
    implementation "com.github.clans:fab:${v.fabVersion}"

    // google play services
    implementation "com.google.android.gms:play-services-maps:${v.playServicesMapsVersion}"
    api "com.google.firebase:firebase-analytics-ktx:${v.firebaseAnalyticsVersion}"
    api "com.google.firebase:firebase-messaging-ktx:${v.firebaseMessagingVersion}"
    implementation("com.google.firebase:firebase-crashlytics-ktx:${v.firebaseCrashlyticsVersion}") {
        transitive = true
    }

    api "com.google.code.gson:gson:${v.gsonVersion}"
    implementation "joda-time:joda-time:${v.jodaTimeVersion}"
    implementation "com.github.pires:obd-java-api:${v.obdJavaApiVersion}"
    api "com.google.android:flexbox:${v.flexBoxVersion}"
    api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:${v.kotlinxVersion}"
    implementation "org.jetbrains.kotlinx:kotlinx-datetime:${v.kotlinxDateTimeVersion}"

    //coroutines
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:${v.kotlinCoroutinesVersion}"
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:${v.kotlinCoroutinesVersion}"
    testImplementation "org.jetbrains.kotlinx:kotlinx-coroutines-test:${v.kotlinCoroutinesVersion}"

    // serialization
    implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:${v.kotlinSerializationVersion}"

    // Testing libraries
    testImplementation "junit:junit:${v.junitVersion}"
    testImplementation "org.junit.jupiter:junit-jupiter:$v.junitJupiterVersion"
    testImplementation "org.mockito:mockito-core:${v.mockitoVersion}"
    // Needed to mock certain classes
    // https://stackoverflow.com/questions/14292863/how-to-mock-a-final-class-with-mockito/40018295#40018295
    testImplementation "org.mockito:mockito-inline:${v.mockitoVersion}"
 testImplementation "com.squareup.okhttp3:mockwebserver:${v.okHttpVersion}"

    // Geospatial library
    api 'com.vividsolutions:jts:1.13'

    //ExpandableRecyclerView
    implementation "com.thoughtbot:expandablerecyclerview:${v.expandableRecyclerviewVersion}"

    //Truetime for Timing Compliance Malfunctions
    implementation "com.github.instacart.truetime-android:library-extension-rx:${v.truetimeVersion}"

    //Instrumented tests
    androidTestImplementation "androidx.test.ext:junit:${v.androidXTestExtJUnitVersion}"

    implementation "com.soywiz.korlibs.klock:klock-android:${v.klockVersion}"

    // grpc
    implementation "io.grpc:grpc-core:${v.grpcVersion}"
    implementation "io.grpc:grpc-api:${v.grpcVersion}"
    implementation "io.grpc:grpc-netty-shaded:${v.grpcVersion}"
    implementation "io.grpc:grpc-okhttp:${v.grpcVersion}"
    implementation "io.grpc:grpc-protobuf-lite:${v.grpcVersion}"
    implementation "io.grpc:grpc-stub:${v.grpcVersion}"

    // gRPC uses these annotations
    implementation 'javax.annotation:javax.annotation-api:1.3.2'

    // Timber (logging)
    api 'com.jakewharton.timber:timber:4.7.1'
}

apply plugin: 'com.google.gms.google-services'
apply plugin: 'com.google.firebase.crashlytics'

Step 5. Import all .aar files as new modules from an AAR.

Then add them as dependencies in your app module build.gradle

dependencies {
    // Previous dependencies here

    implementation project(':vtlib-release')
    implementation project(':EldBleLib-release')
    implementation project(':hos-mobile-interface')
    implementation project(':suntech-api')
    implementation project(':terminalio-debug')
    implementation project(':vehicle-interface')
    implementation project(':pt-sdk-release')
    implementation project(':wvalib-release')
}

Step 6. Have your application class extend VtApplication.

import com.vistracks.vtlib.app.VtApplication;

    public class TestApplication extends VtApplication {
    // Insert your application code here
}

Step 6.5 Add tools:replace=“android:name” in your application tag in your manifest

Step 7. Add this code snippet which adds AppTheme to your styles.xml (Typically found at [Root]/src/main/res/values/styles.xml). App theme must not extend *.NoActionBar or some activities will fail to launch.

<!-- Customized theme for branding -->
<style name="AppTheme" parent="AppBaseTheme">
    
    <!-- Colors -->
    <item name="colorPrimary">@color/default_colorPrimary</item>
    <item name="colorPrimaryDark">@color/default_colorPrimaryDark</item>
    <item name="colorAccent">@color/default_colorAccent</item>
    <item name="colorLight">@color/blue50</item>
    <item name="colorButtonNormal">@color/grey300</item>

    <item name="dayNightTintColor">@color/grey600</item>
    <item name="hosBigButtonThemeOverlay">@null</item>

    <!-- Default font style sizes -->
    <item name="font_small">@dimen/appbase_text_size_small_material</item>
    <item name="font_medium">@dimen/appbase_text_size_medium_material</item>
    <item name="font_large">@dimen/appbase_text_size_large_material</item>
    <item name="font_xlarge">@dimen/appbase_text_size_headline_material</item>
    <item name="font_display3">@dimen/appbase_text_size_display_1_material</item>

    <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item>

 </style>

Step 8. If you are using an app theme, or want to integrate your theme with our’s or want to customize the default theme, have that theme extend AppTheme.

Step 9. Add this code snippet on your AndroidManifest.xml to replace the launcher activity of HOS app. Also add the provider inside application tag to replace workmanager.

<!-- Replace launcher from library -->
<activity
 android:name="com.vistracks.vtlib.authentication.StartMainActivity"
 android:label="@string/app_name"
 tools:node="replace">
  <intent-filter>
    <action android:name="android.intent.action.MAIN" />
    <category android:name="android.intent.category.LAUNCHER" />
  </intent-filter>

  <intent-filter>
    <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
  </intent-filter>

  <meta-data
 android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
 android:resource="@xml/accessory_filter" />

</activity>

<provider
    tools:replace="android:authorities"
    android:name="androidx.work.impl.WorkManagerInitializer"
    android:authorities="[your application id].work_manager.provider.v1"
    android:enabled="false" />

Step 10. Make sure to add this DeveloperAPI.setHosAsLibrary(true) on your application to prevent exiting appliction when logging out from HOS screen.

Step 11. Use the DeveloperAPI.getVtApplication(Context c) to get the context for our application. Start it from an activity to launch our application.

 

Activity Classes

Job Sites JobSiteListActivity.class Intent i = new Intent(context, JobSiteListActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
Work Orders WorkOrderListActivity.class Intent i = new Intent(context, WorkOrderListActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
Roadside Inspection RoadsideInspectionStartActivity.class Intent i = new Intent(context, RoadsideInspectionStartActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
Documents DriverDocumentListActivity.class Intent i = new Intent(context, DriverDocumentListActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
Fuel Receipts DriverDocumentListActivity.class Intent i = new Intent(context, DriverDocumentListActivity.class);
i.putExtra(DriverDocumentListFragment.ARG_IS_FUEL_RECEIPT, true);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
Settings AppPreferencesActivity.class Intent i = new Intent(context, AppPreferencesActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);
Help & Support UserHelpActivity.class Intent i = new Intent(context, UserHelpActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(i);