# 1.15.x -> 1.16

## Breaking Changes

### SDK Configuration

SDK 1.16 changes the way the SDK is configured and initialized.

In summary,

1. Once the SDK is configured it automatically initializes itself using Android Initializers.\
   **There is no longer any need to initialize the SDK during `Application.onCreate()`.**
2. The core SDK is controlled through the new `ImsSdkManager` using `ImsSdkConfiguration`.
3. The trip manager `DsTripManager` is replaced with `ImsTripManager` using the new `ImsTripConfiguration`.
4. Trip manager configuration now uses explicit configuration for detectors, validators, and telemetry.

### Other Changes

1. The scoring service no longer supports fetchDrivingSummaryAggregate

## Migrating Your Code

### Module Dependencies and Obfuscation

These changes apply only if your app is using Bluetooth devices

1. **Remove** the dependency on the "**provider-devices**" module. This module is no longer available; the functionality is now part of trip detection.
2. If you are using the IMS Wedge device, **change** the dependency on the "**devices-ble-nordic**" module **to** "**devices-wedge**".

If you are using distracted driving telemetry for trip recording, add the following additional line to the app's proguard-rules.pro:

```
-keep class com.intellimec.mobile.android.distracteddriving.DistractedDrivingRecordProvider
```

The class name for your custom [token signer](https://sdk.ims.tech/readme/android/initialize-the-sdk#configuration) must not be obfuscated (see below):

```
-keep class [MyTokenSigner].** { *; }
```

If you are using the trip recorder, then the name of the [trip notification factory](https://sdk.ims.tech/migration/android/broken-reference) must not be obfuscated (see below):

```
-keep class [MyNotificationFactory].** { *; }
```

### SDK Configuration

Previous versions required the SDK to be configured and initialized during the `Application.onCreate()` method.

The following shows typical code from SDK 1.15:

<pre class="language-kotlin"><code class="lang-kotlin"><strong>// SDK 1.15
</strong><strong>com.intellimec.mobile.android.common.initialize(
</strong>    application,
    Directories(File(application.filesDir, "sdk")),
    tokenSignerFactory = MyTokenSigner()
)

// The trip manager must be initialized every time the app starts.
// If trip detection is used this method MUST be called from Application.onCreate()
DsTripManager.initializeTripManager(
    application,
    DsTripManager.Builder()
        .setTripFeatures(Feature.FEATURE_ACTIVITY_MONITOR, Feature.FEATURE_GEOFENCE_MONITOR,
                         FEATURE_PHONE_VALIDATION, FEATURE_DEVICE_VALIDATION)
        .setTripTelemetry(TelemetryEvent.GPS, TelemetryEvent.SPEED)
        .addTripDetectors(DsDeviceDetectionMonitor())
        .addTripProviders(DistractedDrivingRecordProvider(application))
        .setTripNotification(SimpleNotificationFactory(application))
        .setUploadWiFiOnly(false)
)
// This must be called IMMEDIATELY after DsTripManager.initializeTripManager.
// This method does NOT initialize the file uploader, instead it sets the Identity callback.
// The application parameter is not used.
DsTripManager.initializeFileUploader(application, object : DsTripManager.DsIdentityCallback {
    override fun getIdentity(): Identity? {
        return authentication.getIdentity()
    }
})
// Enable DsHeartbeat if you want to monitor the trip manager status independently of recorded trips
DsHeartbeat.startHeartbeat(context, identity, HEARTBEAT_INTERVAL)
</code></pre>

Most of that code is used to configure the SDK and trip manager. The SDK now saves its configuration and automatically initializes itself from that saved configuration; the only requirement is that you initialize the SDK before using it.

We recommend configuring the SDK using an [`Initializer`](https://developer.android.com/topic/libraries/app-startup), such as with the `SdkInitializer` class in the sample app, but you can still do this during `Application.onCreate()` if desired.

The following 1.16 configuration code corresponds to the 1.15 version code above.

<pre class="language-kotlin"><code class="lang-kotlin"><strong>// SDK 1.16
</strong><strong>if (!ImsSdkManager.isConfigured) {
</strong>    ImsSdkManager.setSdkConfiguration( context,
        ImsSdkManager.Builder()
            .setApiKey(MY_SAMPLE_API_KEY)
            .setSdkFolder(File(context.filesDir, "sdk"))
            .setTokenSigner(MyTokenSigner::class.java)
            .setUploadWiFiOnly(false)
            .setHeartbeatInterval(HEARTBEAT_INTERVAL)
            .setIdentity(authentication.getIdentity())
            .build()
    )
}

// The trip manager must be initialized before it's used
if (!ImsTripManager.isConfigured) {
    ImsTripManager.configureTripManager(context,
        ImsTripManager.Builder()
            .setTripDetectors(TripDetector.ACTIVITY, TripDetector.GEOFENCE, TripDetector.DEVICE)
            .setTripValidators(TripValidator.PHONE, TripValidator.DEVICE)
            .setTripTelemetry(TripTelemetry.LOCATION, TripTelemetry.SPEED, TripTelemetry.DISTRACTED_DRIVING)
            .setTripNotification(SimpleNotificationFactory::class.java)
            .build()
    )
}
</code></pre>

Note that some of the previous DsTripManager and DsHeartbeat methods have moved to ImsSdkConfiguration, and the trip manager configuration itself has changed.

{% hint style="info" %}
**The SDK no longer uses default detectors and validators when none are specified. If you were relying on the previous defaults you must now specify them explicitly.**
{% endhint %}

* Unless your app starts trip recording explicitly, you must specify at least one of GEOFENCE, ACTIVITY, and/or DEVICE, or else no trips will be recorded.
* Unless your app stops trip recording explicitly, you must specify PHONE and/or DEVICE, or else no trips will be recorded.

| 1.15 Defaults           | 1.16 Equivalent Parameters                   |
| ----------------------- | -------------------------------------------- |
| No detectors specified  | TripDetector.GEOFENCE, TripDetector.ACTIVITY |
| No validators specified | TripValidator.PHONE                          |

The following section lists the old and new configuration parameters

<table><thead><tr><th width="201">1.15</th><th width="222">1.16</th><th>Description</th></tr></thead><tbody><tr><td>(none)</td><td>ImsSdkManager.Builder<br>setApiKey(String)</td><td>This is the API key used in the Identity class.</td></tr><tr><td>initialize()<br>Directories(folder)</td><td>ImsSdkManager.Builder<br>setSdkFolder(File)</td><td>The folder where the SDK stores its files. We recommend that this folder be excluded from Auto Backup.</td></tr><tr><td>initialize()<br>tokenSignerFactory</td><td>ImsSdkManager.Builder<br>setTokenSigner(Class)</td><td>Instead of passing a TokenSigner object, you pass the Class for the token signer. This will let the SDK create the class as required rather than requiring the app to initialize it every time.<br><br><strong>The token signer class must now have a no-parameter (empty) constructor.</strong></td></tr><tr><td>DsTripManager<br>.setUploadWiFiOnly</td><td>ImsSdkManager.Builder<br>-or- ImsSdkManager<br>setUploadWifiOnly</td><td>The WiFi-only upload setting is now saved by the SDK and does not need to be set unless it changes</td></tr><tr><td>DsHeartbeat<br>.startHeartbeat</td><td>ImsSdkManager.Builder<br>-or- ImsSdkManager<br>setHeartbeatInterval</td><td>Set the heartbeat update interval in hours, or use 0 (default) to disable it.</td></tr><tr><td>DsTripManager<br>.initializeFileUploader<br>(identityCallback)</td><td>ImsSdkManager.Builder<br>-or- ImsSdkManager<br>setIdentity</td><td>The previous requirement for the app to supply a <code>getIdentity</code> callback function is replaced with the <code>setIdentity</code> method. The last identity is now persisted so the last specified Identity is automatically used when the SDK restarts.</td></tr><tr><td>DsTripManager<br>setTripFeature<br>FEATURE_GEOFENCE_MONITOR</td><td>ImsTripManager.Builder<br>-or- ImsTripManager<br>setTripDetectors<br>TripDetector.GEOFENCE<br></td><td>Trip detectors are used to detect the possible start of a trip: geofence</td></tr><tr><td>DsTripManager<br>setTripFeature<br>FEATURE_ACTIVITY_MONITOR</td><td>ImsTripManager.Builder<br>-or- ImsTripManager<br>setTripDetectors<br>TripDetector.ACTIVITY</td><td>Trip detectors are used to detect the possible start of a trip: activity recognition</td></tr><tr><td>DsTripManager<br>setTripFeature<br>FEATURE_AWARENESS_API_MONITOR</td><td>ImsTripManager.Builder<br>-or- ImsTripManager<br>setTripDetectors<br>TripDetector.AWARENESS</td><td>Trip detectors are used to detect the possible start of a trip: awareness</td></tr><tr><td>DsTripManager<br>setTripFeature<br>FEATURE_PHONE_VALIDATION</td><td>ImsTripManager.Builder<br>-or- ImsTripManager<br>setTripValidators<br>TripValidator.PHONE</td><td>Trip validators are used to distinguish a valid trip from a false detection. The PHONE validator checks phone sensors such as location, speed, and activity.</td></tr><tr><td>DsTripManager<br>setTripFeature<br>FEATURE_DEVICE_VALIDATION</td><td>ImsTripManager.Builder<br>-or- ImsTripManager<br>setTripValidators<br>TripValidator.DEVICE</td><td>Trip validators are used to distinguish a valid trip from a false detection. The DEVICE validator verifies that the device is present during the trip.</td></tr><tr><td>DsTripManager<br>setTripTelemetry<br>GPS</td><td>ImsTripManager.Builder<br>-or- ImsTripManager<br>setTripTelemetry<br>LOCATION</td><td>The <code>TelemetryEvent</code> enum has been renamed to <code>TripTelemetry</code>, and <code>GPS</code> to <code>LOCATION</code>.</td></tr><tr><td>DsTripManager<br>setTripTelemetry<br>SPEED</td><td>ImsTripManager.Builder<br>setTripTelemetry<br>TripTelemetry.SPEED</td><td></td></tr><tr><td>DsTripManager<br>addTripDetectors<br>DsDeviceDetectionMonitor()</td><td>ImsTripManager.Builder<br>-or- ImsTripManager<br>setTripDetectors<br>TripDetector.DEVICE</td><td>Device-based trip detection is now specified using the <code>TripDetector.DEVICE</code> flag instead of by creating and passing a <code>DsDeviceDetectionMonitor</code> class.</td></tr><tr><td>DsTripManager<br>addTripProviders<br>DsVehicleDetectionProvider()</td><td>ImsTripManager.Builder<br>-or- ImsTripManager<br>setTripTelemetry<br>TripTelemetry<br>.VERIFIED_VEHICLE</td><td>Identifying the vehicle associated to a device is now specified using the <code>TripTelemetry.VERIFIED_VEHICLE</code> flag instead of by creating and passing a class.</td></tr><tr><td>DsTripManager<br>addTripProviders<br>DistractedDrivingRecordProvider()</td><td>ImsTripConfiguration<br>-or- ImsTripManager<br>setTripTelemetry<br>TripTelemetry<br>.DISTRACTED_DRIVING</td><td>Distracted driving is now activated using the <code>TripTelemetry.DISTRACTED_DRIVING</code> flag instead of by creating and passing a <code>DistractedDrivingRecordProvider</code> class.</td></tr><tr><td>DsTripManager<br>setTripNotification<br>NotificationFactory()</td><td>ImsTripManager.Builder<br>setTripNotification<br>Class</td><td>The notification factory is specified by its class rather than an instance. Note that the <code>TripNotificationFactory</code> <strong>interface has changed (see below), and this class must now have a no-parameter (empty) constructor.</strong></td></tr></tbody></table>

The trip notification factory has changes to make the methods more explicit and to let the SDK create the class as required instead of requiring the app to initialize it every time.

| Old TripNotificationFactory                | New TripNotificationFactory                                                                                                                                                                                                                                                                                                                                                       |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `val tripRecordingStartedNotification`     | <p><code>fun createPotentialTripNotification(context)</code><br>The SDK now uses a method call to create the notification, and the name has been changed to make it more explicit.<br>This notification is shown the SDK has detected the probably start of a trip but is waiting to verify that it's actually a moving vehicle.</p>                                              |
| `val tripStartedNotification`              | <p><code>fun createValidatedTripNotification(context)</code><br>The SDK now uses a method call to create the notification, and the name has been changed to make it more explicit.<br>This notification is shown once vehicle motion has been verified, and is shown for the remainder of the trip.</p>                                                                           |
| Constructor `NotificationFactory(context)` | <p>Constructor <code>NotificationFactory()</code><br><strong>The SDK now requires a no-argument constructor</strong>.<br>Previous versions typically used a "Context constructor" so the Context would be available when the actual notifications were created. The new version passes Context as part of the getNotification() call so it's not required in the constructor.</p> |

### Runtime Initialization

Depending on how you use the SDK, additional initialization may be required at runtime.

We recommend initializing the SDK using an [`Initializer`](https://developer.android.com/topic/libraries/app-startup), such as with the `SdkInitializer` class in the sample app, but you can still do this during `Application.onCreate()` if desired.

For example, the SDK sample app sets up a local log recorder and specifies supported Bluetooth devices, then sets up a trip manager status listener.

{% code title="SDK 1.15" %}

```kotlin
// SDK 1.15
// Sample file-based log writer
logFileWriter = ImsSdkLogFileWriter(DsLogLevel.DEBUG, File(application.filesDir, "drivesync/log"), 7, 100000L)
DsLogManager.addListener(logFileWriter)

// Device support is optional. If you use it, register the supported device types here.
DsDeviceManager.initialize(application, 
	listOf( HeadsetProfileProvider(), AudioProfileProvider(),
        WedgeProvider(Regex("^IMS-.*"), false) // Filter wedge devices by name
    )
)

// The trip manager must be initialized every time the app starts.
// If trip detection is used this method MUST be called from Application.onCreate()
DsTripManager.initializeTripManager(application,
    DsTripManager.Builder()
        // ...
        .setTripStatusListener(object : DsTripManager.TripStatusListener {
            override fun onTripStatusUpdate(tripStatus: DsTripStatus) {
                tripStatusData.value = tripStatus
                when (tripStatus.tripState) {
                    DsTripStatus.TripState.ENABLED -> {}
                    DsTripStatus.TripState.STARTED -> Log.d(LOG_TAG, "Trip Started.")
                    DsTripStatus.TripState.STOPPED -> Log.d(LOG_TAG, "Trip Ended.")
                    DsTripStatus.TripState.DISABLED -> {}
                }
            }
        })
)
```

{% endcode %}

In SDK 1.16 the log listener is set using `ImsSdk.addLogListener()` and the trip manager listener through `ImsTripManager.addTripStatusListener()`. Device initialization has not changed.

{% code title="SDK 1.16" %}

```kotlin
// SDK 1.16
// The SDK log manager does not require any additional initialization. These examples show ways to integrate SDK logs with your app.
//ToDo You can add your own log listener. This example writes to local log files
logFileWriter = ImsSdkLogFileWriter(DsLogLevel.DEBUG, File(context.filesDir, "drivesync/log"), 7, 100000L)
ImsSdkManager.addLogListener(logFileWriter)

// Device support is optional. If you use it, register the supported device types here.
DsDeviceManager.blockingInitialize(context, 
	listOf( HeadsetProfileProvider(), AudioProfileProvider(),
        WedgeProvider(Regex("^IMS-.*"), autoConnect = false) // Filter wedge devices by name
    )
)

// Listen for trip manager status updates
ImsTripManager.addTripStatusListener(object : ImsTripManager.TripStatusListener {
    override fun onTripStatusUpdate(tripStatus: ImsTripStatus) {
        tripStatusData.value = tripStatus
        when (tripStatus.tripState) {
            ImsTripStatus.TripState.ENABLED -> {}
            ImsTripStatus.TripState.STARTED -> Log.d(LOG_TAG, "Trip Started.")
            ImsTripStatus.TripState.STOPPED -> Log.d(LOG_TAG, "Trip Ended.")
            ImsTripStatus.TripState.DISABLED -> {}
        }
    }
})
```

{% endcode %}
