Skip to content

Adapting or developing your app for uAAL

Alvaro Fides edited this page Oct 6, 2017 · 12 revisions

This page explains how to develop or modify an Android application so that it communicates with the Native Android universAAL Middleware Application (a.k.a. the uAAL app), and consequently, with the rest of applications connected to universAAL. This process is also called "universAALizing" an application.

Table of Contents

Basic Concepts and Design

Before you starting coding you must first understand how the adaptation works and what you will need. It is assumed that you already understand the concepts of universAAL. For what matters to Android applications, you can basically do 4 things: Providing services, requesting services, sending context events and receiving context events.

Providing services

"Providing a service" to universAAL means you expose some "operation" that can be semantically requested by other universAAL applications. These can contain inputs and outputs. If your application is going to provide a service, you will need an Android Broadcast Receiver, that will be called whenever your service is called from universAAL. If your service has to return outputs, it will then have to send an intent containing them.


Requesting services

This means you semantically request the universAAL service bus to execute a certain service (if it exists). To do this you will need to send an intent with a specific action and category. If you also need some output from the executed service, you will need to have a broadcast receiver, where the middleware will send the response.


Sending events

Sending an event to the context bus will broadcast it to all universAAL applications that are listening to that type of events. To do so, you just need to send an intent with a specific action and category.


Receiving events

On the other hand, if you expect to receive events, you will need to implement a broadcast receiver, where the middleware will send an intent when a matching event appears.


Summarizing, these are the Android components you need depending on the kind of universAAL features you want:

  • Providing service > Have an Android Broadcast Receiver (+Optional if outputs: sending an Intent)
  • Requesting service > Sending Intent (+Optional if outputs: have a Broadcast Receiver)
  • Sending event > Sending an Intent
  • Receiving event > Have a Broadcast Receiver

Setting up the application manifest

First of all you must note that the middleware application works on Android 2.3.3 (API 10) and above. Your own app may have a lower requirement, but since uAAL needs 2.3.3, it will only work with uAAL in that Android version.

Your next step is declaring the universAAL metadata file in your application manifest. You do this by including the following tag:

 <meta-data android:name="org.universAAL.android.metadata" android:resource="@raw/uaal"/>

In your < application > section. Look at the android:resource part of the tag. It identifies the XML file in your "res/raw" application resources folder that will contain the universAAL metadata. You can change the name to whatever you want, without extension (always a XML file).

Writing Metadata

Writing the metadata document is the though part of universAALizing an Android application. It is how you set the equivalence between universAAL messages and Android interactions. The tricky thing is having to deal with RDF Turtle language and setting the variable mappings.

The metadata file is a XML file, which structure is not controlled by an schema, but is based on the universAAL "functional manifest". The functional manifest is originally used for managing permissions, and is automatically generated for universAAL OSGi-based applications. A trick is to develop a universAAL OSGi-based application with the callers, publishers, etc, you want to include in your app and use its functional manifest as a starting point for the metadata file. However the metadata changes a bit the required content and adds some tags. Another alternative is coding that same mock-up OSGi application but use the MessageContentSerializerEx OSGi interface from mw.data.serialization to obtain the Turtle serializations you need.

This is the basic structure of the metadata XML file:

 <?xml version="1.0" encoding="iso-8859-1"?>
 <application>
    <permissions>
        <mw.bus.service>
            <advertisement>
                <! -- SERVICE CALLEE SECTION -->
            </advertisement>
            <! -- YOU CAN ADD MORE ADVERTISEMENT SECTIONS -->
            <requirement>
                <! -- SERVICE CALLER SECTION -->
            </requirement>
            <! -- YOU CAN ADD MORE REQUIREMENT SECTIONS -->
        </mw.bus.service>
        <mw.bus.context>
            <advertisement> 
                <! -- CONTEXT PUBLISHER SECTION -->
            </advertisement>
            <! -- YOU CAN ADD MORE ADVERTISEMENT SECTIONS -->
            <requirement>
                <! -- CONTEXT SUBSCRIBER SECTION -->
            </requirement>
            <! -- YOU CAN ADD MORE REQUIREMENT SECTIONS -->
        </mw.bus.context>
    </permissions>
 </application>

You can use encoding "iso-8859-1" or "utf-8". The file has just two sections, one for service bus and another for context bus (UI bus is out of scope in Android). Each of which can have several (or none) advertisements and requirements.

In the service bus, advertisements are Service Callees, and requirements are Service Callers. In context bus, advertisements are Context Publishers and requirements are Context Subscribers.

Service Callee

The following is the structure of a Service Callee section, which goes into the service bus advertisement section. (WARNING: Because of Wiki editing issues, replyAction and replyCategory tags appear closed in lower case. The right way is to use upper case A and C respectively)

 <advertisement>
    <title> <! -- SHORT TITLE OF THE CALLEE --> </title>
    <description> <! -- DESCRIPTION OF THE CALLEE --> </description>
    <action> <! -- INTENT ACTION TO THE APP --> </action>
    <category> <! -- INTENT CATEGORY TO THE APP --> </category>
    <replyAction> <! -- INTENT ACTION TO THE MW FOR THE REPLY --></replyaction>
    <replyCategory> <! -- INTENT CATEGORY TO THE MW FOR THE REPLY--> </replycategory>
    <input>
        <key> </key>
        <value> </value>
    </input>
    <output>
        <key> </key>
        <value> </value>
    </output>
    <serialization>
        <![CDATA[
        <! -- THE TURTLE SERIALIZATION OF THE SERVICE PROFILE -->
        ]]>
    </serialization>
 </advertisement>

The <serialization> section in this case contains the Turtle-serialized form of the universAAL service profile you are providing. Attention: Make sure the serialized ServiceProfile has a URI of its own, not being a blank node!.

The <action> and <category> are used to build the service intent that will be sent by universAAL to your app when your provided service is requested.

Inputs

If the universAAL service profile you serialized requires inputs, you can obtain the values of these inputs from the intent received by your app. The mapping is made thanks to the <input> section:

The <key> tag must contain the fully qualified (namespace included) URI of the input you want to map, as it appears in the serialization. The <value> tag is the name of the intent extra where the value of that input will be stored. From your app you can get the intent extra with the name you specified in <value>, and you will obtain the input object. If it was a native type (Boolean, Integer...) it will be a class of that type. If it was an ontological Resource, you will get the URI String. If your are not interested in handling URIs, you can use bracket delimiters to get only the part of the URI you are interested in. For instance, if you know you will receive a URI like http://ontology.igd.fhg.de/LightingServer.owl#controlledLamp12home but you are just interested in the number (12 in this case), you can write the value tag as follows: <value>http://ontology.igd.fhg.de/LightingServer.owl#controlledLamp{lamp_number}home</value>. This way you will get the number as a String in the extra identified by the word in brackets (in this case, you will get "12" in the extra identified as "lamp_number").

Outputs

When your app has an output declared in the serialized service profile, you have to send a Broadcast Intent with the <replyAction> and <replyCategory>. If your profile does not include outputs, do not declare these fields in the metadata! [1]. You must include the outputs as extras in that intent, according to the <output> mapping in your metadata:

The <key> tag must contain the fully qualified (namespace included) URI of the output you want to map, as it appears in the serialization. If the output is a native type or an array of those, then you just need to put a String in the <value> tag. That will be the extra ID where you must put the output in your response intent. If the output however has to be an ontological Resource, you have to define the <value> as the following example: <value>http://ontology.igd.fhg.de/LightingServer.owl#controlledLamp{lamp_number_array}home@http://ontology.universaal.org/Lighting.owl#LightSource</value>. The string in brackets is the extra ID where you will put the output value as a String. The string after "@" is the Type URI of the Resource that is expected in the output. If you put "12" in the extra "lamp_number_array", this will result in a LightSource object with URI http://ontology.igd.fhg.de/LightingServer.owl#controlledLamp12home.

By default your returned call status will always be considered successful. You can change that by adding another Intent extra, with key http://ontology.universAAL.org/uAAL.owl#CallStatus, and the value of your resulting status (one of the names of CallStatus.

Service Caller

The following is the structure of a Service Caller section, which goes into the service bus requirement section.

 <requirement>
    <title> <! -- SHORT TITLE OF THE CALLER --> </title>
    <description> <! -- DESCRIPTION OF THE CALLER --> </description>
    <action> <! -- INTENT ACTION TO THE MW --> </action>
    <category> <! -- INTENT CATEGORY TO THE MW --> </category>
    <replyAction> <! -- INTENT ACTION TO THE APP FOR THE REPLY --> </replyaction>
    <replyCategory> <! -- INTENT CATEGORY TO THE APP FOR THE REPLY--> </replycategory>
    <remote> <! -- CODE OF REMOTE IMPORT THROUGH GATEWAY --> </remote>
    <input>
        <key> </key>
        <value> </value>
    </input>
    <output>
        <key> </key>
        <value> </value>
    </output>
    <serialization>
        <![CDATA[
        <! -- THE TURTLE SERIALIZATION OF THE SERVICE REQUEST -->
        ]]>
    </serialization>
 </requirement>

In this case the <serialization> is of the Service Request you want to execute.

The <action> and <category> in this case are for the broadcast intent that your app has to send, and will be handled by the middleware.

Notice the <remote> tag. It is an optional tag only used for callers that need to access service callees in a remote uSpace when the connection is being established through the uSpace Gateway, REST or Remote API. To enable it, the content must be in the form: URIofthecalledservice@NAMESPACEofthecalledserver for the Gateway, or just be present for the Remote API or REST API.

Inputs

Because Service Request are not generic, if the request contains inputs, the serialization will contain actual values. You can replace them with the help of the <input> section:

The <key> tag is just a "variable" ID. The <value> tag is an extra ID. You will use the variable ID to delimit a section of the input URI in your request that will be replaced with the string content of the extra. For instance, in a serialization with a specific input like this: ...owl:hasValue <http://ontology.igd.fhg.de/LightingServer.owl#controlledLamp&var1;00&var1;home> ;..., you can use <key>var1</key> and <value>lamp_number</value> to set the input to <http://ontology.igd.fhg.de/LightingServer.owl#controlledLamp12home> if you put "12" in the "lamp_number" intent extra (Notice that the variable ID is escaped with "&" at the beginning and ";" at the end). The URI of the input may appear in several places in the serialization, make sure it appears the same everywhere.

Outputs

If your service request requires outputs, you will receive them in a Broadcast intent with the action and category specified in <replyAction> and <replyCategory>. The outputs will be embedded as intent extras, mapped as defined in the <output> sections:

In the <output> section the <key> tag must contain the fully qualified URI of the output you desire, as written in the serialization. The <value> tag contains the intent extra ID you can use to get the value of the output from the intent. If the object is a native type or array, you will get it directly. If it is an ontological Resource, you will get the URI. You can use the brackets to get only the part of the URI you want, just like in the <input> section of Service Callee.

If a response arrives to your app, it usually means it succeeded. Otherwise you can get the call status by getting, from the response intent, the extra with key http://ontology.universAAL.org/uAAL.owl#CallStatus. The value is the name of the CallStatus.

Context Publisher

The following is the structure of a Context Publisher section, which goes into the context bus advertisement section.

 <advertisement>
    <title> <! -- SHORT TITLE OF THE PUBLISHER --> </title>
    <description> <! -- DESCRIPTION OF THE PUBLISHER --> </description>
    <action> <! -- INTENT ACTION TO THE MW --> </action>
    <category> <! -- INTENT CATEGORY TO THE MW --> </category>
    <input>
        <key> </key>
        <value> </value>
    </input>
    <serialization>
        <![CDATA[
        <! -- THE TURTLE SERIALIZATION OF THE CONTEXT EVENT-->
        ]]>
    </serialization>
 </advertisement>

The serialization is of the Context Event to send. Because Context Events are not generic, this serialized event must contain specific values, that will be changed according to the input mapping. The serialization of the context event MUST also include the serialization of its hasContextProvider property, and this ContextProvider must also serialize its providedEvents property.

The <action> and <category> are the ones you must put in the broadcast intent that your app has to send when you want to send the event. To change the values of the event to what you want, you have to include those values as extras in the intent, following the input mappings.

Inputs

You define a "variable" ID in the input <key> tag, and an extra ID in the <value> tag. The text delimited by the variable in the serialization will be substituted by the string content of the intent extra. [2].

Context Subscriber

The following is the structure of a Context Subscriber section, which goes into the context bus requirement section.

 <requirement>
    <title> <! -- SHORT TITLE OF THE SUBSCRIBER --> </title>
    <description> <! -- DESCRIPTION OF THE SUBSCRIBER--> </description>
    <action> <! -- INTENT ACTION TO THE APP --> </action>
    <category> <! -- INTENT CATEGORY TO THE APP --> </category>
    <remote> <! -- CODE OF REMOTE IMPORT THROUGH GATEWAY --> </remote>
    <output>
        <key> </key>
        <value> </value>
    </output>
    <serialization>
        <![CDATA[
        <! -- THE TURTLE SERIALIZATION OF THE CONTEXT EVENT PATTERN-->
        ]]>
    </serialization>
 </requirement>

The serialization is of a Context Event Pattern, indicating which events you are interested in.

The <action> and <category> are those of an intent that will be sent to your app, which must implement a Broadcast receiver for those. These are sent every time a matching event is sent from the middleware.

There is also the optional <remote> tag. In this case it identifies that context events should also be received from the remote uSpace when the uSpace Gateway, REST or Remote API are active. To activate this, the tag has to be present, with any value.

Outputs

You can extract values of the event from the received intent thanks to the <output> mappings: The <key> must contain the URI of the context event property you are interested in. You should just limit yourself to the subject, predicate and object properties of the event [3], but you can access deeper resources by specifying the property path (properties URIs separated by blank spaces)[4]. The <value> tag identifies the intent extra where the value of the property can be retrieved. You can get native types as objects, and ontological Resources as string URIs. And in the latter case you can use the brackets to get only pieces of the URI.

Writing Code

Until now, everything has been modifying auxiliary files, but now you are going to write some (small, tiny) code. Perhaps you will not even have to write code at all if your app already relies on intents for communication.

Service Callee

If you want to provide a service callee you will need an Android Broadcast Receiver. You must make sure that the receiver definition in your manifest includes an intent filter which matches the <action> and <category> defined in the metadata. Something like this:

 <receiver android:name=".service.LightService" android:enabled="true" android:exported="true" >
    ...
    <intent-filter>
        <action android:name="org.universaal.nativeandroid.lightserver.GET_CONTROLLED_LAMPS" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
 </receiver>

Notice that "enabled" determines that the receiver is working, and "exported" that it is reachable by other applications. Which is the case of universAAL. You can also register broadcast receivers programatically.

Then in that Android receiver class you will receive the intent when the service is requested from universAAL. You can extract the inputs from the intent extras:

 @Override
 public void onReceive(Context context, Intent intent) {
    String lampAsStr = (String) intent.getExtras().get("lamp_number");
 }

If you need to send back some response outputs, you will have to send (from wherever in your app, but please make it as quick as possible) an intent to the middleware with the action and category specified in the <replyAction> and <replyCategory> metadata. And adding the outputs themselves as extras:

 Intent reply = new Intent("org.universaal.nativeandroid.lightserver.REPLY_GET_CONTROLLED_LAMPS");
 reply.addCategory("android.intent.category.DEFAULT");
 reply.putExtra(lamp_number_array, "12");
 sendBroadcast(reply);

Service Caller

For requesting a service you just need to send a broadcast intent. This is done like in the last code shown above, but changing the extras (which in this case will be input mappings) and the action and category as appropriate, depending on the metadata.

For getting the output results you will need to register an Android broadcast receiver. When the response arrives from the middleware to your receiver, you will be able to extract outputs:

 @Override
 public void onReceive(Context context, Intent intent) {
    String[] lampsArr = intent.getStringArrayExtra(lamp_number_array);
    ...
 }

In this example notice how the return output is an array.

Context Publisher

To send a context event you just need to send a broadcast intent to the action and category specified in the metadata, and including the extras needed for the mapping. The code to use is the same as for sending a service request in the Service Caller, or sending the response from the Service Callee. And there is no result to handle.

Context Subscriber

You will need another broadcast receiver for this. You can extract values from the event once you receive the intent in the receiver. This is done with the same type of code as shown in the Service Caller above.

Notes

  1. ^ You can also choose not to add these fields even if your profile does have outputs, in which case you will receive the reply action and category included in the call: the intent you first received will contain the extras "replyToAction" and "replyToCategory", indicating where you should send your response.
  2. ^ When you embed an extra that is a native type, like Boolean, when substituted in serialization, it will be in the string form returned by its toString() method.
  3. ^ Their URIs are: http://www.w3.org/1999/02/22-rdf-syntax-ns#subject , http://www.w3.org/1999/02/22-rdf-syntax-ns#predicate and http://www.w3.org/1999/02/22-rdf-syntax-ns#object
  4. ^ For instance, if an event has a BloodPressureMeasurement object, but you want the numeric value of the systolic pressure, you can navigate to it with this output definition: <output> <key>http://www.w3.org/1999/02/22-rdf-syntax-ns#object http://ontology.universaal.org/HealthMeasurement.owl#systolicBloodPreassure http://ontology.universaal.org/Measurement.owl#value</key> <value>sys</value> </output> Take into account that the availability of deeper resources depends on the sender of the event. Only Subject, predicate and Object are guaranteed to be always present.