The MOPRIM TMD Sdk for Android when install and properly configured will analyze data streams for the mobile device’s motion sensors to capture how its owner moves. Once the Moprim TMD service is started, the SDK automatically process the data and synchronize its results with our cloud. The final outputs of the TMD will be served through our cloud.
Pre-requisite: the MOPRIM TMD Sdk works on all versions of the Android Sdk >= 16 (Android 4.1, Jelly Bean)
Before you start to use the MOPRIM TMD Sdk in your Android application, you will need to add the SDK as a dependency. The MOPRIM Sdk is already minimized and obfuscated to limit its size but it requires some runtime dependency to function. If you do not have the MOPRIM TMD Sdk, you can contact us to get a quote and developer API key.
You need to copy the file tmd-sdk-0.3.5.arr
to the libs
folder in the root folder of your application.
Then you must do these changes to your build.gradle
file:
dependencies {
// TMD SDK dependency
implementation files('libs/tmd-sdk-0.3.5.aar')
// SDK minimal runtime dependencies
runtimeOnly 'com.amazonaws:aws-android-sdk-core:2.7.7'
runtimeOnly 'com.amazonaws:aws-android-sdk-apigateway-core:2.7.7'
runtimeOnly 'com.google.android.gms:play-services-gcm:16.0.0'
runtimeOnly 'com.google.android.gms:play-services-location:16.0.0'
runtimeOnly 'org.greenrobot:eventbus:3.1.1'
runtimeOnly 'com.evernote:android-job:1.2.6'
runtimeOnly 'org.apache.commons:commons-math3:3.6.1'
runtimeOnly 'com.mkobos:pca_transform:1.0.2'
}
The SDK requires an API key and an API enpoint configuration. Configuration of the TMD is best done in the Application class. If you don’t already have an Application class, then create one. Apply the configuration to your Application class.
import android.app.Application;
import android.content.Context;
import android.util.Log;
import fi.moprim.tmd.sdk.TMD;
import fi.moprim.tmd.sdk.TmdCoreConfigurationBuilder;
import fi.moprim.tmd.sdk.model.TmdInitListener;
public class MyApplication extends Application {
// TAG for logging
private static final String TAG = MyApplication.class.getSimpleName();
@Override
public void onCreate() {
super.onCreate();
TmdCoreConfigurationBuilder builder = new TmdCoreConfigurationBuilder(this)
.setSdkConfigEndPoint("MY_SDK_CONFIG_END_POINT")
.setSdkConfigKey("MY_SDK_CONFIG_KEY");
// Init the TMD
TMD.init(this, builder.build(), new TmdInitListener() {
@Override
public void onTmdInitFailed(TmdError tmdError) {
Log.e(TAG, "Initialisation failed: " + tmdError.name());
}
@Override
public void onTmdInitSuccessful(String s) {
Log.d(TAG, "TMD successfully initiated with resulting application ID " + s);
}
});
}
}
If you cannot create or access the application class, be sure to use the TMD#init
or TMD#init
functions before you do any other operation with the SDK.
The TMD service is currently only available in foreground, and should be called by:
TMD.startForeground(context, NOTIFICATION_ID, notification);
where the NOTIFICATION_ID and the notification are the communication medium for foreground application.
Alternatively, you can stop the TMD with:
TMD.stop(context);
Applications using the TMD may be killed upon reboot or application updates. In order to keep the TMD service running, one must do the following:
public final class MyBroadcastReceiver extends BroadcastReceiver {
/**
* Checks if the action provided by the intent is relevant to boot complete
* or a app update
*
* @param action the string action
* @return true if the action if relevant to boot complete or an app update
*/
private boolean checkActionIsValid(String action) {
return "android.intent.action.BOOT_COMPLETED".equals(action) ||
"android.intent.action.QUICKBOOT_POWERON".equals(action) ||
"android.intent.action.MY_PACKAGE_REPLACED".equals(action);
}
/**
* Called when intent are being received by the receiver
*
* @param context the context
* @param intent the intent
*/
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null && checkActionIsValid(intent.getAction()) {
TMD.startForeground(context, NOTIFICATION_ID, notification);
}
}
}
AndroidManifest.xml
file<application>
<receiver android:name=".MyBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
</application>
Also add the following permission:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
TMD metadata contains information about the information that our cloud knows about a user:
More information about TmdCloudMetadata can be found in the javadoc.
In order to get the TMD Cloud metadata, please run the TmdCloudApi#fetchMetadata in a background thread.
Result<TmdCloudMetadata> result = TmdCloudApi.fetchMetadata(this);
if (result.hasMessage()) {
Log.i(TAG, result.getMessage());
}
if (result.hasResult()) {
Log.d(TAG, result.getResult());
}
if (result.hasError()) {
Log.e(TAG, result.getError());
}
This function requires a network call, thus cannot be execute on the main thread. It also requires the TMD to be initialized beforehand.
TMD Activities contains information about the recognized means of transport of the mobile phone carrier:
More information about TmdActivity can be found in the javadoc.
In order to get the list of TMD activities, please run the [TmdCloudApi#fetchData](/javadoc/v0.3.5/reference/fi/moprim/tmd/sdk/TmdCloudApi.html#fetchData(android.content.Context, java.util.Date)) or alike in a background thread.
Result<List<TmdActivity>> result = TmdCloudApi.fetchData(this, date);
if (result.hasMessage()) {
Log.i(TAG, result.getMessage());
}
if (result.hasResult()) {
Log.d(TAG, Arrays.toString(result.getResult()));
}
if (result.hasError()) {
Log.e(TAG, result.getError());
}
This function requires a network call, thus cannot be execute on the main thread. It also requires the TMD to be initialized beforehand.
In the event, the TMD recognized a wrong activity or the discovered activity is not precise enough (e.g., motorized/road/car instead of motorized/road/car/electric for an electric car), it is possible to manually change the label of this activity by using the TmdCloudApi#correctActivity function.
Example:
Result<TmdActivity> result = TmdCloudApi.correctActivity(context, tmdActivity, newLabel);
if (result.hasMessage()) {
Log.i(TAG, result.getMessage());
}
if (result.hasResult()) {
Log.d(TAG, result.getResult());
}
if (result.hasError()) {
Log.e(TAG, result.getError());
}
The Android SDK is configured via the MOPRIM Cloud. Therefore, the number of TMD activities that can be recognized (e.g., motorized/road/car, non-motorized/bicycle) can change everytime the TMD is reconfigured with the latest models. Please refer to the list of current activities.
The TMD SDK enables you to annotate an activity with more information than the one provided by the SDK natively. You can set the metadata for this activity by using the TmdCloudApi#annotateActivity function.
Example:
Result<TmdActivity> result = TmdCloudApi.annotateActivity(context, tmdActivity, myMetadata);
if (result.hasMessage()) {
Log.i(TAG, result.getMessage());
}
if (result.hasResult()) {
Log.d(TAG, result.getResult());
}
if (result.hasError()) {
Log.e(TAG, result.getError());
}
It is possible to update the label and add metadata at the same time by using the TmdCloudApi#updateActivity function.
TMD statistics contains information about a list of statistics for each type of activity and during a specific time period (weekend vs. weekdays and last X days vs. overall. For each value we provide the combined sum of CO2 emissions, the distance and duration of these activities.
Check the javadoc for more information.
Result<TmdStats> result = TmdCloudApi.fetchStats(context, nbOfDays);
if (result.hasMessage()) {
Log.i(TAG, result.getMessage());
}
if (result.hasResult()) {
Log.d(TAG, result.getResult());
}
if (result.hasError()) {
Log.e(TAG, result.getError());
}
For more information about TmdStats, check out the javadoc.
This function requires a network call, thus cannot be execute on the main thread. It also requires the TMD to be initialized beforehand.
Our system usually upload itself the data to our cloud periodically (default interval is every hour), but it is possible for the application developer to force upload the data to our cloud.
The current modality is never synchronized with the cloud as it is not considered as completed.
To force upload the data to our cloud, use the following method:
Result<TmdUploadMetadata> result = TmdCloudApi.uploadData(context);
if (result.hasMessage()) {
Log.i(TAG, result.getMessage());
}
if (result.hasResult()) {
Log.d(TAG, result.getResult());
}
if (result.hasError()) {
Log.e(TAG, result.getError());
}
TmdUploadMetadata contains information about timestamp and number of locations uploaded to the Cloud with the call as well as the information for TMD activities.
For more information about TmdUploadMetadata, check out the javadoc.
This function requires a network call, thus cannot be execute on the main thread. It also requires the TMD to be initialized beforehand.
As the TMD periodically uploads the data to the cloud, we enabled to possibility for application developers to react to these uploads using PendingIntent from the Android SDK.
Registering a pending intent with:
// If you want to do trigger some process when the data is periodically uploaded to the cloud
Intent intent = new Intent(MyApplication.this, MyUploadIntentService.class);
PendingIntent callbackIntent = PendingIntent.getService(MyApplication.this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
TmdCloudApi.setUploadCallbackIntent(callbackIntent);
You can check out the javadoc
The list of possible errors returned by any TMD function is available in the javadoc
Contact us for getting a quote for the SDK.