HeaRTDroid

HeaRTDroid is a rule-based inference engine both for Android mobile devices, and desktop solutions

User Tools

Site Tools


pub:software:heartdroid:tutorials:android_quickstart

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.

  • BASIC – this version omits the implementation of a few application parts. We strongly encourage you to use this version and learn how to use HeaRTDroid. We will provide some helpful hints to guide you.
  • FINAL – this version provides a full example of application. If you want to see a fully functional application you can use this version.

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

Make sure that the downloaded project has few important files:

  • AndroidManifest.xml – the most important file in application. The manifest file provides essential information about your app to the Android system. It also defines what kind of permissions the application requires. We already provided all required permission settings for our app, but if you want to improve the basic app with some new functionality (for example something involving locations), make sure that your app has all required permissions.
  • MainActivity.java – this file includes all the source code of our example. If you use BASIC tag version, you will have to implement some parts of applications, to get a feeling how HeaRTDroid works.
  • layout/activity_main.xml – this file defines the graphical layout of main activity. If you want to add some more visual elements, this is the file you need to modify.
  • profile_change_rules.hmr – this file consists the rules used by HeaRTDroid inference engine. If you want to learn more about HMR be sure to check out this page (HMR language quickstart). You can load the file using HWed editor (http://glados.kis.agh.edu.pl/hwed) and analyse this simple decision model.

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 - an entity associated with an attribute. Callback allows to obtain the value of the attribute, when it is needed.
  • actions - an entity associated with a rule. Actions are executed whenever the rule is fired. Each rule may be associated with several actions.

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 and actions - we've already provided an implementation of single Callback and Action to show you how you can use this mechanisms,
  • runTheInference – this method creates an XTT state and calls rule inference engine to deduce the final state,
  • run method of ScheduledTask class – this method schedules the use of runTheInference method in given time intervals and updates the application view to provide information about inferred state and audio settings.

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:

  • fixedOrderInference - we provide all tables names, in an order in which they should be fired,
  • dataDrivenInference - we provide only the starting tables names. The algorithm crawls the table network and fires only the necessary tables
  • goalDrivenInference - we only give the table which produces the attribute value that we are interested in. The algorithm crawls the table network and fires only the necessary tables.

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:

  • obtaining the max volume value:
    int ringMaxVolume = myAudioManager.getStreamMaxVolume(AudioManager.STREAM_RING);
  • setting the stream volume value:
    myAudioManager.setStreamVolume(AudioManager.STREAM_RING, ringMaxVolume, 0);
  • setting the ringer mode:
    myAudioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);

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.

pub/software/heartdroid/tutorials/android_quickstart.txt · Last modified: 2019/04/10 08:54 (external edit)