≡ Menu

Smart Grids, part dyevit: Android!

It’s time to dive into Android.

Let’s revisit what we have so far:

  1. Part I, definitions of service levels
  2. Part Deux, requirements
  3. Part Tres, data model
  4. Part Vierte, data storage
  5. Part He, managing references to resources
  6. Part 110, read operations of our data
  7. Part Seacht, an HTML-based user interface
  8. Part Bā, write operations for our data

Write operations are fine, but where does our data come from? Based on our requirements, it comes from a light sensor, with Android being targeted as the initial platform in which the light sensor is hosted.

Therefore, it’s time for us to start coding the producer for our application.

We’ve done a decent job of thinking about our requirements before coding for the rest of the application; no need to stop doing that now.

So what do we need?

What the UI needs to allow us to do

First off, it needs to allow us to control whether it’s sending data or not. Sending data from a portable device is taxing for the battery; if it’s not plugged in, we need to allow the user to control whether it’s sending data or not.

We also need to allow control of the consumer for the light levels. In our last portion of this series we received a URL to which we can post data; that URL may change (will change, realistically) and therefore we need to allow the user to define it properly.

We should also respect the user’s privacy. The device ID will normally map to the phone number being used to send data, but that definitely violates privacy – so we allow the UI to override the device ID before sending any data.

It’d be nice to see the light level as detected by the device; you’re presumably using the device, so you know the light levels around you, but the light sensor may or may not reflect your ambient light.

This is a good thing! One reason the platform and sensor were chosen is because you can physically control the input level very easily. I didn’t want to require manual control, but now you are able to wave your hand over the sensor and change the light levels, very easily.

What the UI looks like

Our basic UI looks like this, after designing the layout:

While this looks like it’d fit what we need, we have a problem.

We don’t have a problem with the UI, but with our project setup. I’ve been trying to focus on making sure I discuss tooling before coding, but now I’ve given you an Android screenshot without describing the first thing about setting up Android in a development environment.

There’re reasons for that. One is that I’m a lazy git. The other is that setting up an Android development kit is well-documented and specific to your device and operating system; those two aspects, combined, are pretty good causes for me to avoid detailing a lengthy setup.

However… it is important that you set up the ADK properly, and you want to set $ANDROID_HOME to point to the ADK’s directory.

There are also some pretty important project structures that have to be in place to use Maven for Android.

First is the pom.xml‘s <build/> section:

<plugin>
    <groupId>com.jayway.maven.plugins.android.generation2</groupId>
    <artifactId>android-maven-plugin</artifactId>
    <version>3.1.1</version>
    <configuration>
        <androidManifestFile>
            ${project.basedir}/AndroidManifest.xml
        </androidManifestFile>
        <assetsDirectory>
            ${project.basedir}/assets
        </assetsDirectory>
        <resourceDirectory>
            ${project.basedir}/res
        </resourceDirectory>
        <nativeLibrariesDirectory>
            ${project.basedir}/src/main/native
        </nativeLibrariesDirectory>
        <sdk>
            <platform>
              10
            </platform>
        </sdk>
        <undeployBeforeDeploy>
            true
        </undeployBeforeDeploy>
    </configuration>
    <extensions>true</extensions>
</plugin>

Most of this is pretty standard, but it indicates where things are supposed to be in our project source tree.

One thing of note is the platform node: it has the value 10 in it, which means we’re targeting Android 2.3 (“Gingerbread”). This is a common version; I’d like to target Ice Cream Sandwich (4.0, also known as “ICS”) because it’s what I have on my phone, but we don’t need any ICS features.

Our directory tree needs to have some new entries in it. From tree -d, it looks like this, with some directories ignored in ./src/main/java:

├── res
│   ├── drawable-hdpi
│   ├── drawable-ldpi
│   ├── drawable-mdpi
│   ├── layout
│   └── values
└── src
    ├── main
    │   └── java
    └── test
         └── java

Using tree on the ./res directory gives us this output:

├── drawable-hdpi
│   └── icon.png
├── drawable-ldpi
│   └── icon.png
├── drawable-mdpi
│   └── icon.png
├── layout
│   └── main.xml
└── values
    └── strings.xml

Of these, the icons are simple and static; the main.xml and strings.xml are more interesting.

main.xml is the layout (thus, it’s in res/layout) for our application.

It contains a number of XML nodes such as the following:

<TextView
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/routerUrlLabel"
            />

This is the label that is seen as “URL to which to send data” in the screenshot. Note that it doesn’t have that text in the <TextView />; it uses “@string/routerUrlLabel” instead. This notation tells the build tool to refer to strings.xml to find the value of this widget.

strings.xml contains the resources for the layout. It’s very simple: it has many lines such as:

<string name="routerUrlLabel">URL to which to send data</string>

When the build tool (a resource compiler) sees these references, it builds a series of generated classes and resources that we can use to refer to these values and UI widgets.

One other configuration file needs to be mentioned, and it’s in the root directory of the android-sensor project: AndroidManifest.xml.

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.redhat.osas.sensor"
    android:versionCode="1"
    android:versionName="1.0-SNAPSHOT">

    <uses-feature android:name="android.hardware.sensor.light"/>
    <uses-feature
        android:name="android.hardware.telephony"/>
    <uses-permission
        android:name="android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission
        android:name="android.permission.INTERNET"/>

    <application
        android:icon="@drawable/icon"
        android:label="@string/app_name">
        <activity android:name=".LightSensorActivity">
            <intent-filter>
                <action
                    android:name="android.intent.action.MAIN"/>
                <category
                    android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>

Much of this file is standard boilerplate for application configuration, with the application’s package name and initial activity specified, along with various icon references.

However, the <uses-feature/> and <uses-permission/> nodes are worth a look. They tell the Android system that this application intends to use those features and resources; if the resources or features are not available, the application will not start, and the user has the option of refusing the application based on its declared usages.

The benefit of this is that we know, with this deployment descriptor, that at runtime the application has access to the light sensor, the internet, the device ID (which comes from the voice mail ID), and a geolocation.


And with that, our series comes to a crashing halt. Again.

You see, while we now have a layout described (well, in the source tree, at least), we are missing something important, even though we’ve seen references to it in our UI:

Our broker communication layer.

We’ve described our broker transport, of course; it’s provided as an HTTP endpoint, communicated with via JSON and the HTTP verb.

We’ve also said that this wasn’t exactly optimal, and it might get replaced. (Actually, I said that it would get replaced.)

So! We need to take a detour to figure out a service layer for the client application – which includes our Android application. This service will handle all the gruntwork of communicating to our broker with a supplied URL.

That’s our next article.