David's Web Repository David Boddie - Projects David Boddie - Updates

Making Friends with Robots

I arrived very late to the Android party. Although this wasn't directly a result of my job at the time of Android's first release, it didn't help that we were actively discouraged from using the SDK at work. Working with Qt during the day and doing things with PyQt and embedded Linux at home, Android wasn't really all that interesting, especially since it has a heavy Java legacy, both on and off devices.

In 2007 I upgraded from the ultra-low-end Nokia phone my employer gave me in 2004 to a Sony Ericsson K750i feature phone. I didn't really plan on getting a smartphone. I turned down the phones that Nokia were handing out when they bought Trolltech – the choice was between something fairly chunky (the N8, perhaps) and something with a keyboard, and only a few people were happy with their choice after a couple of months. Sadly, the closest thing to a smartphone, the Greenphone I borrowed from work, went back to Nokia when I left – one of the things I regret not walking out of there with.

In 2014, when taking a trip to the other side of the planet, I felt I needed a smartphone to be able to get access to the Web while travelling. I was also mindful of the possibility that it could get lost, damaged or stolen, so I chose one that cost less than 1000 NOK (£100, more or less). After initial research into unlocking the bootloader, and accessing the device over the debug USB connection, I realised that I wasn't going to be installing anything new on it before my trip, and I didn't really think too much more about doing any kind of development for it.

All Aboard the Bandwagon

At the beginning of this year I thought I'd take a look at Android development since I already had the SDK installed – and the NDK, too, because I had hoped to play with the Python language on my phone. Being more interested in getting tools running rather than making things with them, I had hoped to do something useful towards making it easier to deploy a Python interpreter on Android, but there seems to be so much in the way of actually getting a useful solution accepted into the official CPython distribution that I realised it was probably a battle for someone else to fight. Everyone who really feels that they need to run Python code on Android eventually finds all the recipes they need to build CPython, so maybe there isn't really a problem to be solved.

Still, there's a gap between running a Python interpreter and doing something useful with it. Existing solutions do various things to gain access to the Android API: PyQt exposes them via the Qt API, Kivy provides its own API, and Pyjnius exposes the API using Java's reflection mechanisms. Which of these seems most appealing probably depends on your taste in APIs more than anything else. Having worked with Qt for a number of years, only recently looking at the Android API, I think I would prefer to use Qt's, but there's something to be said for removing layers of abstraction if you don't feel you need them.

I figured that using some of the above solutions would be interesting, but that maybe I wouldn't really be learning about Android development if I used them. It's nice to be insulated from the platform but not so nice if there isn't a demand for people with experience of those solutions. It would be good if the skills I learned could be reused in a work environment, for example. So, I decided to try and get to grips with Java and the Android API.

The Android API itself is nothing special. The Qt API is more familiar to me and I find Android's a bit alien, relying as it does on the core Java API. Just as Python programmers using PyQt can be a bit overwhelmed by the different style of code that they have to write, and noting that C++ purists probably also find Qt's API a bit strange, Android's API has an unfamiliar style. If anything, it seems to reflect its Java heritage even more than Qt shows that it is primarily for C++ developers.

I found Java to be a less-than-expressive language. I can see that people might disagree if they learned it as a first language or encountered it after C or C++, but after learning Python it seems like a step back. I would rather write C++ code for a living, and have done so recently; writing Java in order to create applications just seems like an unnecessary hurdle. The API is there to use, the code is compiled to run on a virtual machine (so the programming language is not completely set in stone), why not write code in another language to use the API directly. You could even write bytecode to do this, or use an assembler like smali to help. There are some restrictions on the sort of code that can run on the Dalvik virtual machine, but perhaps some compromises can be made.

Thought Experiments

What kind of alternative language could we use that would map nicely to the architecture of the Dalvik virtual machine? You could ask a similar question about any CPU architecture. Dynamic languages like Python don't map directly onto these architectures, which is why we have the CPython and Jython interpreters, but what would a language like Python look like if it was adapted to the architecture we want to write code for?

To understand how a language like Python might be adapted, we need to look at the constraints it will face when adapted for a particular architecture. The Dalvik virtual machine executes bytecode it obtains from Dalvik Executable format (DEX) files, and the instructions provided by the bytecode constrain what kind of operations can be performed by the code, but there's more information in those files than just the bytecode. The file contains a number of sections that provide different levels of information about the interfaces used by the code and those that the code implements. Of these, the only generic section is the string section which contains a collection of string constants. Others, such as the types and method prototypes sections, are much more oriented around declaratively typed language concepts and Java's paradigms in particular.

One of the things that constrains the kind of code we could compile is the restriction that we represent all our callable functions as class methods and define classes to hold them. However, since many GUI applications typically define subclasses in which their methods are used to respond to events from the operating system, this just means that the code we might write is just a subset of the code we could write in a more general language. The fact that methods need to define their input and output types to interface correctly with the underlying frameworks is just a consequence of writing code to run on a well-defined platform. It helps us to think about the types of data that we will need to handle as well as making the virtual machine simpler to implement.

__package__ = "com.example.hello"

from android.app import Activity
from android.widget import TextView

# Application classes

class HelloActivity(Activity):

    __interfaces__ = []

    def __init__(self):

        Activity.__init__(self)

    @args(void, [android.os.Bundle])
    def onCreate(self, bundle):

        Activity.onCreate(self, bundle)

        view = TextView(self)
        view.setText("Hello world!")
        self.setContentView(view)

We can think about reimagining Python in terms of a language with the above constraints. Since Python's syntax doesn't support explicit type declarations, and we need to be able to define interfaces to match those of the platform API, we need to create conventions that programmers can use without too much trouble. Let's take a look at an example piece of code that shows how this might be done.

Apart from the initial package declaration, the code looks fairly normal for Python code. The __init__ method calls its corresponding base class implementation without using the super function that many people are fond of, but I started writing Python before that was introduced and I doubt I'll change my style now.

The unusual feature is the use of the @args decorator to declare the types of the arguments expected by the onCreate method. It's not unheard of to use decorators in this way: PyQt uses decorators to declare slot argument types and the Python Wiki's PythonDecorators page contains examples of proposed type declaration syntaxes that failed to be approved for inclusion as part of the standard language conventions.

The differences between Python and Java reveal themselves in these declarations. Python methods return None by default instead of void, so perhaps there is a chance that we are losing information by treating them as the same in this case.

There are other differences that this example doesn't show: we use a string to set the text in the TextView class, but it's not a Python string. If we were using integers, they would be limited to 32-bit values unless we made them long integers. You could introduce Python-like handling of numbers but it would require more code to be generated and more processing of values at run-time.

class CameraActivity(Activity):

    __interfaces__ = [SurfaceHolder.Callback]

    def __init__(self):

        Activity.__init__(self)

    @args(void, [android.os.Bundle])
    def onCreate(self, bundle):

        Activity.onCreate(self, bundle)

        self.has_camera = False
        preview = SurfaceView(self)

        self.holder = preview.getHolder()
        self.holder.addCallback(self)

        self.setContentView(preview)

It is easy to describe types for method arguments and return values. We can use these to implicitly declare types for other objects in the application, such as local variables that are assigned the values of arguments. When we instantiate a class, as in the case of the TextView in the above example, we can determine the type of the variable at that point, though we probably don't want to allow a value of a different type to be assigned to it later, as is possible in Python.

Where things get interesting is the case of class or instance attributes. Unlike with methods, we can't use decorators to annotate assignments in class bodies, so there needs to be a way to express the types of these, though we can try to determine these on demand, as in the code opposite where the has_camera attribute is set for the first time and the type of the holder attribute is determined from the return type of the SurfaceView.getHolder method. However, sometimes these attributes – actually instance fields in the Java/Dalvik world – need to be declared in advance, and one possible solution is hinted at earlier in the class definition.

Unlike Python, Java only allows a class to inherit from a single base class, but it allows classes to express that they implement interfaces which are, to all intents and purposes, non-Object-based classes. Expressing this in a Python-like language could be done in a number of ways – for example, by including interfaces as part of the list of base classes. The example shows one way we could express them: by declaring them in a magic __interfaces__ attribute of the class.

This approach also works for fields. We can declare their names and types in a dictionary that can be processed by the compiler before any method code is handled, and refer to them later in methods. The SensorEvent class, which is part of the android.hardware package, can be described in the following way.

class SensorEvent(java.lang.Object):

    __fields__ = {
        "accuracy": int,
        "sensor": Sensor,
        "timestamp": long,
        "values": [float]
        }

Here, the magic __fields__ attribute tells the compiler about the names and types of instance fields. Static fields can be similarly described by the __static_fields__ attribute and these would correspond to class attributes in Python.

Why can't we just define static fields directly in the class body by using assignments? Because some fields might describe types of instances, and while Java classes can provide a <clinit> method to create these, we may not be able to do so for all types – TextView objects need to be instantiated with a parent Context, for example – and, besides, we also need to reserve a syntax for representing constant declarations in classes.

So, we can represent a lot of the things that you might need if you were writing classes for loading into the Dalvik virtual machine. Perhaps even more importantly, since applications need to work with the platform API, we can represent the most important parts of the standard class definitions that the compiler will need to get information from, even if that means we have to rewrite that information in Python syntax. Note that we have lost all the access declarations that come with Java (and C++). That may turn out to be a problem in the future but we can hopefully deal with that using some of the conventions described above.

Categories: Free Software, Android

Copyright © 2016 David Boddie
Published: 2016-04-27 00:00:00 UTC
Last updated: 2016-10-14 11:14:08 UTC

This document is licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International license.