Implementing inter-app communication

Your app and the EIDU app communicate in two ways:

  • EIDU launches learning units in your app, and your app returns the result to EIDU.

  • Your app may retrieve any required assets from EIDU.

We provide a helper library that makes it easy for your app to implement this.

Using the integration library

In the following sections, you will learn how to use the library in your app. Note that the code examples below are in Kotlin, but the library is written in plain Java and can be used by Java code as well.

Consult the Javadoc documentation of the library or its source code for details. The library is available on Maven Central. The easiest way to obtain it is to add a dependency (assuming you use Gradle):

repositories {

mavenCentral()

}

dependencies {

implementation("com.eidu:integration-library:<version>")

}

Launching learning units

The EIDU app will attempt to launch learning units available in your app through an activity you made known to it in the metadata defined in the learning package. This activity must define an Intent Filter with the action and category set as shown here:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="...">
<application ...>
<activity
android:name="[Fully Qualified Class Name of your Activity]"
android:exported="true"
...>
<intent-filter>
<action android:name="
com.eidu.integration.LAUNCH_LEARNING_UNIT" />
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
...
</application>
</manifest>

EIDU will start this activity using an Intent that contains the necessary information to allow you to identify the unit to be launched, as well as some additional information that further specifies the desired behavior. The easiest way to retrieve this information is to let the integration library parse the intent that launched your activity, like this:

class MainActivity : ComponentActivity() {

...

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)


val request: RunLearningUnitRequest? = RunLearningUnitRequest.fromIntent(intent)

...

}

...

}

The resulting request will include the following information:

  • request.learningUnitId: String → The unique ID of the learning unit to be launched. This will be one of the IDs that you provided in your learning package's unit list.

  • request.remainingForegroundTimeInMs: Long → The maximum amount of time that this run may take before being automatically terminated by your app. Note that the sample learning app contains an example of a good way of measuring the foreground time.

  • request.inactivityTimeoutInMs: Long → This is the maximum time the learner may be idle (i.e. not create any input) before the unit must be automatically terminated by your app.

When the launched unit is terminated for whatever reason, you must send a result back to the EIDU app in order for it to update the learner's progress. This is done by passing a RunLearningUnitResult instance to Activity.setResult and then finishing the activity:

class MainActivity : ComponentActivity() {

...

private fun finishWithSuccess(

request: RunLearningUnitRequest,

score: Float,

foregroundDurationInMs: Long,

items: List<ResultItem>

) {

setResult(

RESULT_OK,

RunLearningUnitResult.ofSuccess(score, foregroundDurationInMs, null, items)

)

finish()

}

...

}

Depending on the reason why the unit was terminated, you should create a RunLearningUnitResult instance by using one of the following methods:

  • ofSuccess

  • ofAbort

  • ofTimeoutInactivity

  • ofTimeUp

  • ofError

Learning apps are also strongly encouraged to include a list of ResultItem instances that describe the learning unit run in more detail.

Please consult the Javadoc documentation for details.

Retrieving assets

While you are free to bundle any assets required by your app with your APK, we would like to encourage you to load as many assets as possible dynamically through the integration library. This will reduce the size of your APK and will allow us to optimize downloads and memory usage. Through the library, you can retrieve assets you made available to us in your learning package. The library provides a way to retrieve every asset based on its relative path. For example, your learning package may contains asset files at the following path:

assets/folder-01/audio.ogg

assets/folder-01/image.png

You may then retrieve the file audio.ogg using one of the following methods:

val request: RunLearningUnitRequest = ...


// Get asset as a 'content://' Uri, e.g. for use with Android's MediaPlayer:

val audioUri: Uri = request.getAssetAsUri("folder-01/audio.ogg")


// Get asset as binary InputStream (you are responsible for closing it):

val audioStream: InputStream = request.getAssetAsStream(context, "folder-01/audio.ogg")


// Get asset as read-only FileDescriptor, for some special use cases (you are responsible for closing it):

val audioFileDescriptor: FileDescriptor = request.getAssetAsFileDescriptor(context, "folder-01/audio.ogg")

In this example, context is the current Android Context (your activity or application context). The method will return a File object, or null if no asset could be found for the specified path. In general, the EIDU app will ensure that all required assets (as per your declaration in your learning package) are available before a learning unit is launched. In case you attempt to access an asset that was not declared as required by the current learning unit, getAssetAsStream and getAssetAsFileDescriptor will throw a FileNotFoundException, which should be handled gracefully by your app, for example by finishing with a result of RunLearningUnitResult.ofError. Whether the Uri returned by getAssetAsUri is valid will only become apparent once your app actually attempts to open that Uri.

Assets may be zip files or other containers that contain many asset files. However, we encourage you to provide assets in the smallest possible units, such as individual images, to allow us to optimize downloads and disk usage. We also encourage you not to cache asset files, again, to allow us to optimize disk usage. However, if you need to process asset files extensively before using them in your learning unit, caching the resulting data might make sense to accelerate the startup of your learning units.

In order to reduce downloads and disk usage further, we also encourage you to compress any media files - such as images, sounds, and videos - aggressively and use a low resolution; the devices EIDU is used on usually have small screens and limited disk capacity.

Your app should now be able to allow EIDU to launch learning units. To test your implementation, please have a look at the documentation of the integration test app. Next, let’s take a look at what adjustments need to be made to your app’s behavior.