Table of Contents

Android Quickstart

This tutorial provides very basic information on how to use HeaRTDrodi in Android application. There however more resources on-line, which were made by the third-party, who used HeaRTDroid in their solutions. Some of them are listed below:

The tutorial below was prepared by Krzysztof Honkisz.

Outline

This tutorial presents a way to create a simple Android application, which utilizes HeaRTDroid - a rule-based inference engine for Android mobile devices, that is based on HeaRT inference engine. Using HeaRTDroid, we will create a simple application, that changes the device audio settings, according to the day of the week and hour.

Source code

Clone the repository with application source code: git clone https://KrzysHon@bitbucket.org/KrzysHon/heartdroid-tutorial.git

Repository has two versions of our application, which can be changed using tag functionality.

Note: to change source code using git tags, type command git checkout <tag-name>

Make sure that the downloaded project has few important files:

HMR file in HWed editor

HeaRTDroid integration mechanisms

HeaRTDroid provides special entities, which allows to bind the HMR models with external data sources, or to provide a way of interaction with the user. Those entities are:

Callbacks and actions are represented as classes, that implements appropriate Java interfaces (Callback and Action respectively). You can read more about them here.

Improving the application

Starting with BASIC version, you will have to add your implementation of some functionalities:

Callbacks

As it was said earlier, callback is a Java class that implements interface Callback. This interface has only one method called “execute”. This method runs every time the attribute value is needed. To bind the attribute with a callback, you need to modify the HMR model:

xattr [name: hour,
    type: hour_type,
    class: simple,
    comm: in,
    callback: 'pl.edu.agh.heartdroid.callbacks.GetSystemHourCallback',
    abbrev: hour1
    ].

In this example, the attribute “hour” is binded with a callback class “GetSystemHourCallback” (remember - you have to provide full name of the class, including the package).

The “execute” method simply reads the current hour and passes the value to given attribute.

    public void execute(Attribute attribute, WorkingMemory workingMemory) {
        Log.i("MYAPP", "Executing GetSystemHourCallback for " + attribute.getName());
        int hour = Calendar.getInstance().get(Calendar.HOUR_OF_DAY);
        try {
            workingMemory.setAttributeValue(attribute, new SimpleNumeric((double) hour), false);
        } catch (AttributeNotRegisteredException e) {
            Debug.debug("CALLBACK",
                    Debug.Level.WARNING,
                    "Callback failed to set value of" + attribute.getName() + ", as the attribute is not registered in the Working Memory.");
        } catch (NotInTheDomainException e) {
            Debug.debug("CALLBACK",
                    Debug.Level.WARNING,
                    "Callback failed to set value of" + attribute.getName() + ", as the obtained value was not in the domain of attribute.");
        }
    }

In BASIC version you will have to add implementation of GetSystemDayOfWeekCallback. We've already provided some helper function for

runTheInference implementation

First thing, we need to create a state object. Thanks to the use of callbacks, we don't have to implicitly create input attributes. The only thing to do is creating a new State.

After that, we can run the inference engine. There are three methods we can use. All of them takes the same types of parameters, but their meaning is a bit different:

In our example we use dataDrivenInference, but you can experiment with other methods. Since inference methods can throw some exceptions, you need to handle them in some way - we suggest to use Android Log class to print information about the error.

//Creating a new XTTState object
state = new State();
try {
    HeaRT.dataDrivenInference(model,
            new String[]{"DayTime", "Today"},
            new Configuration.Builder()
                    .setInitialState(state)
                    .build());
} catch (AttributeNotRegisteredException e) {
    Log.e("MYAPP", "exception", e);
} catch (UnsupportedOperationException e) {
    Log.e("MYAPP", "exception", e);
}

Finally, you can print the inferred state on the console to check the state attributes:

System.out.println("Printing current state (after inference");
state = HeaRT.getWm().getCurrentState(model);
for (StateElement se : state) {
    System.out.println("Attribute " + se.getAttributeName() + " = " + se.getValue());
}

Actions

Similarly to the Callbacks, Actions are binded with rules by HMR model modification. You have to use operator **> to bind rule with actions.

xrule 'Actions'/6:
    [
        daytime eq any,
        today eq any
    ]
    ==>
    [
        action set normal
    ]
    **>
    [
        'pl.edu.agh.heartdroid.actions.SetNormalProfileAction'
    ]
    .#1

In this case, the rule is bound with action SetNormalProfileAction. Let's take a look at the action implementation:

    @Override
    public void execute(State state) {
        Log.i("MYAPP", "Executing SetNormalProfileAction");
        AudioManager myAudioManager = (AudioManager) Config.context.getSystemService(Context.AUDIO_SERVICE);
 
        int systemMaxVolume = myAudioManager.getStreamMaxVolume(AudioManager.STREAM_SYSTEM);
        int notificationMaxVolume = myAudioManager.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION);
        int ringMaxVolume = myAudioManager.getStreamMaxVolume(AudioManager.STREAM_RING);
 
        myAudioManager.setStreamVolume(AudioManager.STREAM_SYSTEM, systemMaxVolume, 0);
        myAudioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION, notificationMaxVolume, 0);
        myAudioManager.setStreamVolume(AudioManager.STREAM_RING, ringMaxVolume, 0);
        myAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
    }

In the first line, an access to AudioManager is obtained. AudioManager class is provided by Android OS to allow audio settings manipulation. Your application also needs to obtain proper security permissions, but we have already set everything in AndroidManifest.xml file.

The rest of the action changes the audio settings to the “normal” profile. Basically, we use those three methods:

In BASIC version, there are two actions, without “execute” method implementation. Using the above implementation as basis, provide the missing implementation.

ScheduledTask class

To wrap everything up, we are gonna create a simple implementation of Runnable interface. ScheduledTask is set to run every hour. It calls the runInference method and updates the information printed on screen.

You just have to read the attributes of a state and print the information on screen:

TextView dayView = (TextView) findViewById(R.id.dayView);
String dayValue = ((SimpleSymbolic) state.getValueOfAttribute("day")).getValue();
dayView.setText("Day of week: " + dayValue);

There are four TextViews in MainActivity layout - dayView, hourView, modeView and volumeView. You can use them to print out all of the information that you find important. Of course, you can add more layout elements if you like.

Final

After that, you can run the application on your device or emulator (note: Android Studio emulator sometimes do not prints all of the TextViews on the first run – just rerun the app and everything should work). You should see that the device audio settings are changed and that the state information is printed on screen. If you use FINAL version of this application, you should see this screen with current information:

And that's it! You've just made your first mobile app that uses the HeaRTDroid library! This simple example was intended to give you some basic information about usage of HeaRTDroid and HMR rules. Feel free to improve it further with your ideas or to create your own project.