Skip to content

The lighting example in Android

Alvaro Fides edited this page Jul 8, 2015 · 8 revisions

This is a tutorial about how to unviersAALize an existing Android Application (or create a new universAALized one) based on the Lighting example, which is commonly used to teach universAAL.

Table of Contents

The Lighting Example as Android Apps

The Lighting Example of universAAL consists of 3 parts: ontology, server and client. In this case, for Android, the server and client will be considered regular Android applications, and in this tutorial you will see what it takes to make them universAAL-aware. The ontology will not suffer any changes, since it is the "shared knowledge" in universAAL, and remains the same.

First of all, consider the Lighting Example Android applications: The server is an Android app showing 4 "virtual" lamps that can be turned on or off. The client is another Android app that allows to execute 3 options: getting a list of lamps, and turning on or off a selected lamp. It is out of scope of this tutorial how to create such Android apps and how they work, here we only deal with how to universAALize them. This is how they look like:

The source code is available at https://github.com/universAAL/nativeandroid/tree/master/LightingSamples/UniversAALized. Take into account that if you import them in your IDE you may have to fix the dependency to the AppCompat library (Right-click project > Properties > Android > Add library).

UniversAALizing the Apps

We will consider that the Lighting apps started as non-universAALized, and for universAALizing we would need to do 3 steps (as described in Adapting or developing your app for uAAL): 1) Modifying the manifest, 2) including universAAL metadata, and 3) modify the code. Because the Lighting apps already relied on Intent-based communication, there is no need to change the code - but we'll show how it's done as well.

Lighting Server

First of all, consider the interactions that the Lighting Server will have in universAAL. It will provide 3 services: Getting the list of controlled lights, turning on a selected light, and turning off a selected light. This will require that the app has 3 Android receivers, or just one but responding to 3 different intents. The server will also provide context information by sending an event when the status of a light changes.

The Manifest

Let's start by having a look at the Android manifest. We will focus on just the relevant sections for universAAL. First is the metadata declaration:

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

This will instruct the universAAL middleware application that it must look for metadata in the file uaal.xml, that will be in the resources of the app. Then you can take a look at the declaration of the receivers:

 <receiver
   android:name=".LightCallGetReceiver"
   android:enabled="true"
   android:exported="true" >
   <intent-filter>
     <action android:name="org.universaal.nativeandroid.light.CALL_GETLAMPS" />
     <category android:name="android.intent.category.DEFAULT" />
   </intent-filter>
 </receiver>

Unlike the metadata declaration, this was already there before universAALizing the app. This is because the app relied on intent-based communication for interacting with the client. This however might not be the case of other apps, so in those cases the manifest will have to be modified for this purpose. Each of the service callees will be executed when calling these receivers with one of the declared intents, CALL_ON, CALL_OFF (both handled by the same) and CALL_GETAMPS. Remember these for the metadata file.

The Metadata

Next up is the metadata file. In this tutorial we will focus on each separate section for service and context bus. In the server there will be 3 service advertisements (or service callees) and 1 context advertisement (or context publisher). Let´s take a look at the first service callee:

 <advertisement>
   <title>Get controlled lamps</title>
   <description>SERVICE CALLEE PROFILE: Get controlled lamps</description>
   <action>org.universaal.nativeandroid.light.CALL_GETLAMPS</action>
   <category>android.intent.category.DEFAULT</category>
   <replyAction>org.universaal.nativeandroid.light.REPLY_GETLAMPS</replyaction>
   <replyCategory>android.intent.category.DEFAULT</replycategory>
   <output>
     <key>http://ontology.igd.fhg.de/LightingServer.owl#controlledLamps</key>
     <value>http://ontology.igd.fhg.de/LightingServer.owl#{lamps}@http://ontology.universaal.org/Lighting.owl#LightSource</value>
   </output>
   <serialization>
               <![CDATA[
 @prefix ns: <http://www.daml.org/services/owl-s/1.1/Service.owl#> .
 @prefix ns1: <http://www.daml.org/services/owl-s/1.1/Process.owl#> .
 @prefix ns2: <http://www.daml.org/services/owl-s/1.1/Profile.owl#> .
 @prefix : <http://ontology.igd.fhg.de/LightingServer.owl#> .
 <http://ontology.igd.fhg.de/LightingServer.owl#sp1> ns:presentedBy :getControlledLamps ;
  a ns2:Profile ;
  ns2:has_process :getControlledLampsProcess ;
  ns2:hasResult [
    ns1:withOutput [
        a ns1:OutputBinding ;
        ns1:toParam :controlledLamps ;
        ns1:valueForm """
          @prefix : <http://ontology.universAAL.org/Service.owl#> .
          _:BN000000 a :PropertyPath ;
            :thePath (
              <http://ontology.universaal.org/Lighting.owl#controls>
            ) .
          """^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral>
      ] ;
    a ns1:Result
  ] ;
  ns2:hasOutput :controlledLamps .
 :controlledLamps a ns1:Output ;
  ns1:parameterType "http://ontology.universaal.org/Lighting.owl#LightSource"^^<http://www.w3.org/2001/XMLSchema#anyURI> .
 :getControlledLamps a :LightingService ,
    <http://ontology.universaal.org/Lighting.owl#Lighting> ;
  ns:presents _:BN000000 .
 ]]>
   </serialization>
 </advertisement>
 

It is a good idea to have a clear name and description. Now, look at the serialization. This is the serialized form of a universAAL service profile. You must have learnt how to code service profiles in advance, we are not going to explain these now. Just know that this service profile in particular represents a Lighting service that takes no inputs and returns an output which is a list of LightSource. If you know how to code such service profile but are wondering how to obtain the serialized form, you have several options: write it in turtle directly, write a OSGI-based app that passes the ServiceProfile object to the unviersAAL serializer and prints it, or copy it from the universAAL functional manifest of an OSGi-based app that provides it.

Now look at the other tags. Action and category are the same as one of the intent filters of the Android receiver declared in the manifest (see previous section). This means that when a universAAL service request comes from the service bus that matches the serialized service profile, an intent will be sent to that Android receiver.

The "reply" action and category is where the response of the call will be sent. In this case the response is the list of lights. It will be sent to a broadcast receiver that listens to intents with these action and category. This receiver is in the universAAL middleware, and will relay the response through the service bus (It may also be, like in this case, that the Android Lighting Client implements a receiver for such intent, where it will receive the list of lights. See the section at the end of the page for details on this dichotomy).

Lastly, the output key-value pair does the mapping between the output as declared in the serialized service profile and the output as handled by Android. In this case, the output defined in the serialization as http://ontology.igd.fhg.de/LightingServer.owl#controlledLamps will be built as a Resource of type http://ontology.universaal.org/Lighting.owl#LightSource with the URI http://ontology.igd.fhg.de/LightingServer.owl#{lamps}, where {lamps} is filled with the value of the intent extra "lamps" that the app will embed in the response intent. In this particular case that will be an array of numbers, so instead of just one Resource, the output will be list of Resources, each with a different name in its URI.

Now focus on the second service callee, the one for turning off a light. This is how its metadata looks:

 <advertisement>
   <title>Turn light off</title>
   <description>SERVICE CALLEE PROFILE: Turn off a specific light source.</description>
   <action>org.universaal.nativeandroid.light.CALL_OFF</action>
   <category>android.intent.category.DEFAULT</category>
   <replyAction>org.universaal.nativeandroid.light.REPLY_OFF</replyaction>
   <replyCategory>android.intent.category.DEFAULT</replycategory>
   <input>
     <key>http://ontology.igd.fhg.de/LightingServer.owl#lampURI</key>
     <value>http://ontology.igd.fhg.de/LightingServer.owl#{lamp}</value>
   </input>
   <serialization>
               <![CDATA[
 @prefix ns: <http://www.daml.org/services/owl-s/1.1/Profile.owl#> .
 @prefix pvn: <http://ontology.universAAL.org/uAAL.owl#> .
 @prefix owl: <http://www.w3.org/2002/07/owl#> .
 @prefix ns1: <http://ontology.igd.fhg.de/LightingServer.owl#> .
 @prefix ns2: <http://www.daml.org/services/owl-s/1.1/Service.owl#> .
 @prefix ns3: <http://ontology.universaal.org/Lighting.owl#> .
 @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
 @prefix psn: <http://ontology.universAAL.org/Service.owl#> .
 @prefix : <http://www.daml.org/services/owl-s/1.1/Process.owl#> .
 <http://ontology.igd.fhg.de/LightingServer.owl#sp2> ns2:presentedBy ns1:turnOff ;
  a ns:Profile ;
  ns:has_process ns1:turnOffProcess ;
  ns:hasResult [
    a :Result ;
    :hasEffect [
        psn:affectedProperty [
          a psn:PropertyPath ;
          psn:thePath (
            ns3:controls
            ns3:srcBrightness
          )
        ] ;
        a psn:ChangeEffect ;
        psn:propertyValue "0"^^xsd:int
      ]
  ] ;
  ns:hasInput ns1:lampURI .
 ns1:turnOff a ns1:LightingService ,
    ns3:Lighting ;
  pvn:instanceLevelRestrictions [
      owl:hasValue [
        :fromProcess :ThisPerform ;
        a :ValueOf ;
        :theVar ns1:lampURI
      ] ;
      a owl:Restriction ;
      owl:onProperty ns3:controls
    ] ;
  ns2:presents _:BN000000 ;
  pvn:numberOfValueRestrictions "1"^^xsd:int .
 ns1:lampURI psn:parameterCardinality "1"^^xsd:int ;
  a :Input ;
  :parameterType "http://ontology.universaal.org/Lighting.owl#LightSource"^^xsd:anyURI .
 :ThisPerform a :Perform .
 ]]>
   </serialization>
 </advertisement>
 

It works like the previous callee, but in this case there are no outputs but an input. The input defined in the serialization as http://ontology.igd.fhg.de/LightingServer.owl#lampURI will be given the value http://ontology.igd.fhg.de/LightingServer.owl#{lamp}, where {lamp} will be filled with the value of the extra "lamp" included in the intent to the Android service. In this case, because no output is expected, there should be no "reply" action and category, but one is added to let the callee send a "succeeded" response and avoid timeouts.

The service for turning on a light works in the same manner, but with a different brightness value. Finally, let's see the metadata for the context publisher:

 <advertisement>
   <title>Publish light source brightness</title>
   <description>CONTEXT PUBLISHER EVENT: Publish changes in brightness of a light source.</description>
   <action>org.universaal.nativeandroid.light.EVENT_LIGHTCHANGE</action>
   <category>android.intent.category.DEFAULT</category>
   <input>
     <key>var1</key>
     <value>lamp</value>
   </input>
   <input>
     <key>var2</key>
     <value>brightness</value>
   </input>
   <serialization>
               <![CDATA[
 @prefix ph: <http://ontology.universaal.org/PhThing.owl#> .
 @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
 @prefix tst: <http://ontology.igd.fhg.de/LightingServer.owl#> .
 @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
 @prefix light: <http://ontology.universaal.org/Lighting.owl#> .
 @prefix ctxt: <http://ontology.universAAL.org/Context.owl#> .
 @prefix owl: <http://www.w3.org/2002/07/owl#> .
 <urn:org.universAAL.middleware.context.rdf:ContextEvent#_:c043cf9e99c148f8:be9> ctxt:hasProvider tst:LightServer ;
  a ctxt:ContextEvent ;
  rdf:subject tst:&var1;controlledLamp1&var1; ;
  ctxt:hasTimestamp "1384864157846"^^xsd:long ;
  rdf:predicate light:srcBrightness ;
  rdf:object "&var2;100&var2;"^^xsd:int .
 tst:&var1;controlledLamp1&var1; a light:LightSource ,
    ph:Device ,
    ph:PhysicalThing ;
  light:srcBrightness "&var2;100&var2;"^^xsd:int .
 ctxt:gauge a ctxt:ContextProviderType .
 tst:LightServer a ctxt:ContextProvider ;
  ctxt:hasType ctxt:gauge ;
  ctxt:myClassesOfEvents [
      a ctxt:ContextEventPattern ;
      <http://www.w3.org/2000/01/rdf-schema#subClassOf> [
          a owl:Restriction ;
          owl:allValuesFrom light:LightSource ;
          owl:onProperty rdf:subject
        ]
    ] .
 ]]>
   </serialization>
 </advertisement>
 

The serialization represents a context event, and the action and category are where the app has to send an intent when it wants to send the event. The inputs are mappings used to give specific values to fields of the event (the serialized event has some default values). Here, &var1;controlledLamp1&var1 will be replaced with the value of the intent extra "lamp", and &var2;100&var2; with the value of the extra "brightness".

The Code

In the end, the app has to "do" something, whether it is called from Android or universAAL. When the app is being invoked to execute a service call, the onReceive method of the broadcast receiver will be called. In the end what matters is that, if you expect an input (like with CALL_ON intent action) you can take it with something like:

 String lamp = intent.getStringExtra(LightServerActivity.EXTRA_LAMP);

This is the LightCallTurnReceiver class. When the app has to send a response with outputs, as is the case with CALL_GETLAMPS, this can be done with an intent, but where to send it? If you don't know the destination intent filter in advance (in this case you know because you have both the server and client code) you can get it from the calling intent extras org.universAAL.android.action.META_REPLYTOACT and META_REPLYTOCAT, which are set by uAAL. In LightCallGetReceiver class this looks like this:

 Intent reply = new Intent(intent.getStringExtra(LightServerActivity.EXTRA_REPLYACTION));
 reply.addCategory(intent.getStringExtra(LightServerActivity.EXTRA_REPLYCATEGORY));
 reply.putExtra(LightServerActivity.EXTRA_LAMPS, LightServerModel.getInstance(context).getLamps());
 context.sendBroadcast(reply);

Sending a Context Event is done similarly, by sending an intent to the right filter with the right extras for the values. This is done in LightServerModel when there is a change in a lamp:

 Intent intent = new Intent(LightServerActivity.ACTION_EVENT);
 intent.putExtra(LightServerActivity.EXTRA_LAMP, lamp);
 intent.putExtra(LightServerActivity.EXTRA_BRIGHTNESS, i);
 mContext.sendBroadcast(intent);

Lighting Client

Whereas the server is about providing services and sending events, the client is about requesting that. The Lighting Client app will call each of the three services provided by the server, and will receive the events it sends. When calling services, you just need a broadcast receiver only if you expect something in response. Another broadcast receiver is needed for getting context events in any case.

The Manifest

As always, the metadata file must be declared in the manifest as an XML file in the resources:

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

For receiving the context events, a broadcast receiver is declared with the right action and category as filter, and the same is true for when you need to receive the response from the CALL_GETLAMPS service:

 <receiver
   android:name=".LightChangeReceiver"
   android:enabled="true"
   android:exported="true" >
   <intent-filter>
     <action android:name="org.universaal.nativeandroid.light.EVENT_LIGHTCHANGE" />
     <category android:name="android.intent.category.DEFAULT" />
   </intent-filter>
 </receiver>

Remember that receivers can also be registered programatically, instead of in the manifest, so they don't stay always active.

The Metadata

The client only contains requirements sections, which are service callers for the service bus, and context subscribers for the context bus. The first service caller is for getting the list of lamps:

 <requirement>
   <title>Get all light sources</title>
   <description>SERVICE CALLER REQUEST: Get a list of all light sources.</description>
   <action>org.universaal.nativeandroid.light.CALL_GETLAMPS</action>
   <category>android.intent.category.DEFAULT</category>
   <replyAction>org.universaal.nativeandroid.light.REPLY_GETLAMPS</replyaction>
   <replyCategory>android.intent.category.DEFAULT</replycategory>
   <output>
     <key>http://ontology.igd.fhg.de/LightingConsumer.owl#controlledLamps</key>
     <value>http://ontology.igd.fhg.de/LightingServer.owl#{lamps}</value>
   </output>
   <serialization>
               <![CDATA[
 @prefix ns: <http://ontology.igd.fhg.de/LightingConsumer.owl#> .
 @prefix pvn: <http://ontology.universAAL.org/uAAL.owl#> .
 @prefix : <http://www.daml.org/services/owl-s/1.1/Process.owl#> .
 _:BN000000 a pvn:ServiceRequest ;
  pvn:requiredResult [
    :withOutput [
        a :OutputBinding ;
        :toParam ns:controlledLamps ;
        :valueForm """
          @prefix : <http://ontology.universAAL.org/Service.owl#> .
          _:BN000000 a :PropertyPath ;
            :thePath (
              <http://ontology.universaal.org/Lighting.owl#controls>
            ) .
          """^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral>
      ] ;
    a :Result
  ] ;
  pvn:requestedService [
    a <http://ontology.universaal.org/Lighting.owl#Lighting>
  ] .
 ns:controlledLamps a :Output .
 ]]>
   </serialization>
 </requirement>
 

The serialization represents a service request that requires a Lighting service with an output for several LightSources. This will match the service profile defined in the equivalent service callee in the server (but remember that matches don't need to be exact, they are semantic). The action and category tags are where the intent must be sent by the app. They equal those in the server because these apps were already communicating to each other. If they had different values, the would still communicate thanks to universAAL matchmaking, but not directly through Android (more on this on the last section). The "reply" action and category is where the response will be sent. The app must have a broadcast receiver for those.

Thanks to the output mappings, the output defined as http://ontology.igd.fhg.de/LightingConsumer.owl#controlledLamps in the serialization will be found in the extra identified by "lamps" when the response comes to the "reply" receiver. Because the output values are ontology Resources, they are represented by their URI. By defining the output value as http://ontology.igd.fhg.de/LightingServer.owl#{lamps}, it means you only want the URI suffixes in the "lamps" extra (an array of these, actually, remember?).

Now look at the service caller for turning off (which works like the one for turning on):

 <requirement>
   <title>Turn light source off</title>
   <description>SERVICE CALLER REQUEST: Turn off a specific light source.</description>
   <action>org.universaal.nativeandroid.light.CALL_OFF</action>
   <category>android.intent.category.DEFAULT</category>
   <input>
     <key>var1</key>
     <value>lamp</value>
   </input>
   <serialization>
               <![CDATA[
 @prefix owl: <http://www.w3.org/2002/07/owl#> .
 @prefix ns: <http://ontology.universaal.org/PhThing.owl#> .
 @prefix ns1: <http://ontology.igd.fhg.de/LightingServer.owl#> .
 @prefix ns2: <http://ontology.universaal.org/Lighting.owl#> .
 @prefix pvn: <http://ontology.universAAL.org/uAAL.owl#> .
 @prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
 @prefix ns3: <http://www.daml.org/services/owl-s/1.1/Process.owl#> .
 @prefix : <http://ontology.universAAL.org/Service.owl#> .
 _:BN000000 a pvn:ServiceRequest ;
  pvn:requiredResult [
    a ns3:Result ;
    ns3:hasEffect [
        :affectedProperty [
          a :PropertyPath ;
          :thePath (
            ns2:controls
            ns2:srcBrightness
          )
        ] ;
        a :ChangeEffect ;
        :propertyValue "0"^^xsd:int
      ]
  ] ;
  pvn:requestedService [
    a ns2:Lighting ;
    pvn:instanceLevelRestrictions [
        owl:hasValue <http://ontology.igd.fhg.de/LightingServer.owl#&var1;controlledLamp0&var1;> ;
        a owl:Restriction ;
        owl:onProperty ns2:controls
      ] ;
    pvn:numberOfValueRestrictions "1"^^xsd:int
  ] .
 <http://ontology.igd.fhg.de/LightingServer.owl#&var1;controlledLamp0&var1;> a ns2:LightSource ,
    ns:Device ,
    ns:PhysicalThing .
 ]]>
   </serialization>
 </requirement>
 

In this case there are input mappings instead of outputs. These work by replacing &var1;controlledLamp0&var1; in the serialized request with the value in the extra "lamp_number" that the app inserts in the intent it sends. Notice it covers the URI suffix, so the value has to be the name of the lamp.

Finally, take a look at the context subscriber metadata:

 <requirement>
   <title>Subscribe to light sources</title>
   <description>CONTEXT SUBSCRIBER PATTERN: Receive all changes of light source brightness</description>
   <action>org.universaal.nativeandroid.light.EVENT_LIGHTCHANGE</action>
   <category>android.intent.category.DEFAULT</category>
   <output>
     <key>http://www.w3.org/1999/02/22-rdf-syntax-ns#subject</key>
     <value>http://ontology.igd.fhg.de/LightingServer.owl#{lamp}</value>
   </output>
   <output>
     <key>http://www.w3.org/1999/02/22-rdf-syntax-ns#object</key>
     <value>brightness</value>
   </output>
   <serialization>
               <![CDATA[
 @prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
 @prefix ns: <http://ontology.universaal.org/Lighting.owl#> .
 @prefix : <http://www.w3.org/2002/07/owl#> .
 <http://ontology.igd.fhg.de/LightingServer.owl#cep1> a <http://ontology.universAAL.org/Context.owl#ContextEventPattern> ;
  <http://www.w3.org/2000/01/rdf-schema#subClassOf> [
      a :Restriction ;
      :allValuesFrom ns:LightSource ;
      :onProperty rdf:subject
    ] ,
    [
      :hasValue ns:srcBrightness ;
      a :Restriction ;
      :onProperty rdf:predicate
    ] ,
    [
      a :Restriction ;
      :allValuesFrom <http://www.w3.org/2001/XMLSchema#int> ;
      :onProperty rdf:object
    ] .
 ns:LightSource a :Class .
 ]]>
   </serialization>
 </requirement>
 

The serialization here is a context event pattern, describing the events that will be received. When this happens the receiver will be called with the action and category of this metadata. The output mappings describe that the subject of the context event will be found in the "lamp" intent extra, and will have the value encased by the brackets in the <value></value> tag. For instance, if the Resource value of the Subject has the URI http://ontology.igd.fhg.de/LightingServer.owl#controlledLamp3, the "lamp" intent extra will have the value "controlledLamp3". The same happens with the object of the event, but in this case, because instead of a Resource it will be an Integer, the number itself will be stored in the "brightness" intent extra.

The Code

For requesting a service, you just need to send an intent with the action and category defined in the metadata. In the Lighting Client this is done in LightClientActivity. For instance for turning off a lamp:

 Intent intent = new Intent(ACTION_CALL_OFF);
 intent.addCategory(Intent.CATEGORY_DEFAULT);
 intent.putExtra(EXTRA_LAMP, mSelectedLamp);
 sendBroadcast(intent);

Remember that when calling the service to get the list of lamps, a receiver has to get the response. In its onReceive method the interesting part is getting outputs, which is simply getting the right extras from the incoming intent, like in LightReplyReceiver class:

 intent.getStringArrayExtra(LightClientActivity.EXTRA_LAMPS)

When receiving an event, in LightChangeReceiver class onReceive method, the subject and object are extracted with:

 String lamp = intent.getStringExtra(LightClientActivity.EXTRA_LAMP);
 Integer brightness = intent.getIntExtra(LightClientActivity.EXTRA_BRIGHTNESS, -1);

Running the Example

You can launch these example Android apps and they should work on their own, even without universAAL. But the fun is in having them communicate through universAAL and also with a PC instance. For that, in addition to having installed the universAAL middleware application into your Android device, you will also need the Lighting Server and Client APKs. You can build the APKs yourself from the sources, or get the APKs directly from https://github.com/universAAL/nativeandroid/tree/master/Files . Then you must include the Lighting ontology "dexed" jar file in the ontologies folder of the Android device. You can dex the file yourself or use directly the one in https://github.com/universAAL/nativeandroid/tree/master/Files/Configurations/felix/ontologies .

Connecting to PC

When everything is installed, you can then also connect the Android instance and the PC instance. You can combine the Lighting Example in the PC instance with the Android instance. For that you need as well the Lighting ontology, server and client in the PC instance (how to do that is out of scope here). But be careful! Because the Android Lighting Server has been built with the exact same profiles as the PC version, they shouldn't be run at the same time! Otherwise only one would be called (this behaviour can be changed by setting your request call mode, but we won't get into that here).

Once the PC and Android instances are successfully connected, you can start the Lighting client (either in Android or PC) and control the lights of the remaining server, in whichever instance it is. You should also see the context events pop up with every change. One note: because of some security constraints in Android, the Lighting server and client must have been started manually at least once (or after a manual force close is performed) to work properly.

Native Android communication vs. universAAL communication

With what you have read until now you may have noticed that there is a risk of duplication of calls or events: If the Lighting Client can call the Lighting Server through Android intents natively, without universAAL, wouldn't that mean that when universAAL is running, the Server will get a duplicated intent, one from Android and one from universAAL?

That would be the theory, yes, because the intent filter is the same both in the receiver declared in the Server manifest and in the Client metadata declaration of the caller. This means both the Server and the universAAL middleware receive that intent. However the middleware is prepared for this, and if the intent filter is the same in these two ends of the flow, the call will be propagated to universAAL, but not to Android (Android itself will deliver it on its end). This scenario applies to both service calls and context events. This is to allow for existing communicating apps to still behave the same way.

You could however force the apps to communicate only through uAAL, for which you just need to make sure the intent filters are different in the Client and the Server. For instance, you can simply change the Client prefix used in intent filters "org.universaal.nativeandroid.light" for something different like "org.universaal.nativeandroid.lightclient" in all its occurrences: in uaal.xml, AndroidManifest.xml and LightClientActivity.java.