Paul Bourke

Notes, tips, photos, and code.

GDG Dublin, Speaking, and reveal.js

Last night I attended my second ever Google Developer Groups (GDG) event, and was fortunate enough to be given the opportunity to speak about my Android apps. It was a really great experience and something I hope I can continue to practice and improve.

My talk was titled “Adventures in Android Development, from hobby to play store”, in which I walked through some of the things I considered and learnt during the development and release of RoidRage and Glimmr.

For fun and to try something different, I looked into some HTML5 solutions for my slides, starting with impress.js and settling on reveal.js. Anyone who knows me will know I’m a fan of the console, and text based solutions. If it can be written in Vim and stored in Git, that’s generally all I need to hear. Unfortunately though I’ll be going back to Google Docs in the future.

The effects and styling you get out of the box with something like reveal are cool, and it’s a novelty to create something as institutionalised as the typical slidedeck using web technologies. Sometimes though it’s just a case of the right tool for the right job, and using these libraries felt more like a hack then a help.

For me the following points lead me to conclude Google Docs is the better tool for the job:

  • Drag/drop creation
    Unless you want your slides to look identical to every other person using the framework, you’re going to want to do at least some customisation. With Google Docs you can drag/rotate/scale images and text around the page very quickly. I’m not adverse to writing CSS rules etc., but it feels entirely overkill for something that will be a one off.

  • Export to different formats
    While both solutions are in the cloud, I would never want to rely on a network for the big event, or even assume there will be one available. This means you will either need to use your own laptop, or preferably export the slides to common format. GDocs allows me to do seamless export to a number of formats including PPTX, PDF, and even SVG. With a JS solution you better hope the presenter has a working browser, that their screen res plays nice with your CSS, etc. reveal.js has a process for printing to pdf that unfortunately didn’t work very well for me, garbled my slides, and lost some transitions.

Overall though it still worked out well, and worked just fine on the night. I’ll be interested to revisit HTML5 slidedecks in the future to see if they mature some more or are just a passing fad.

Thanks to all who attended my talk and gave kind feedback.

Migrating to Gradle

Tonight I just had another go at migrating my Android project from Maven to Gradle, this time successfully.

Because Gradle is still relatively new to the Android ecosystem, there still seems to be a shortage of blog posts and info out there on how to go about doing this.

Here is the process I went through if it helps anyone looking to do the same.

Why move to Gradle?

Apparently there are many benefits to Gradle over Maven, which I hope to experience over the coming weeks now I’ve made the switch. But that aside, Gradle is the tool the Android team have decided to support going forward, and is now standard in Android Studio. Most of the major library authors have switched on Github, which means if you don’t switch you begin to find yourself left behind.

The thing that had stopped me last time I tried to migrate was the fact that some of my favorite libraries did not yet offer ‘aar’ packages. This is something you will want to check before making the move (traditional jars work in Gradle fine, it’s Android library projects packaged in android-maven’s ‘apklib’ format that’s a problem).

Procedure

Firstly, you would assume there’s an automated way that can at least make a go of converting your project automatically. Those Googling will likely find maven2gradle near the top of their results, though it seems the same functionality has been moved into Gradle itself.

As a Gradle newbie, scanning this page didn’t lead me to what command to run, so I ended up creating a blank project in Android Studio, and copying my code into it. The only thing to keep in mind here is that your src directory now needs to reside under app/, and AndroidManifest.xml, assets/, res/ and related directories now go under app/src/.

After this, it was a simple case of running ‘gradle build’ and the dependencies I needed to gradle.build one by one.

Hurdles

One thing that took some major time was a host of errors around invalid XML namespaces (xmlns). I don’t have the error to put here as it’s gone from my console buffer as typing this, but it’s a pretty standard error when the resource parser can’t recognise a namespace. In my case removing some instances of ‘xmlns:tools’ from my resource files got around this, which I had in place to silence some lint warnings. Curiously, when re-adding them in an attempt to reproduce the error for this post, they worked fine.

Summary

It feels good to be up to date tool wise, not to mention not having Android Studio complain every time I open it that I’m using an unrecommended build system.

Since some library authors actually skipped Maven and went straight to aar, I have less libs I need to maintain locally, and can drop a script I had to maintain to install these.

Next steps are to figure out how to do release builds with Gradle, as well as read some docs to see how else it can make my life easier.

Glimmr is Open Source on Github, you can find it’s gradle.build here.

Installing/Upgrading Ubuntu 13.04

It’s that time of the year again, another Ubuntu upgrade.

I wanted to document some of the things I find myself repeatedly having to do on a fresh install of Ubuntu, as the unfortunately the upgrade process can be very hit and miss. (Thankfully if you keep /home mounted on a separate partition reinstalling is fairly painless).

Packages

Basic dev, and some old favorites

1
2
sudo apt-get install vim git screen ctags nautilus-dropbox gnome-do pidgin \
maven unity-tweaktool deluge gitk

Remove malware, and indicators I don’t use

1
sudo apt-get remove unity-lens-shopping indicator-sync indicator-messages

Tweaks

Move window buttons back to the right

1
2
gsettings set org.gnome.desktop.wm.preferences button-layout \
":minimize,maximize,close"

Set the power button to suspend

1
gsettings set org.gnome.settings-daemon.plugins.power button-power 'hibernate'

I also like to:

  • Swap Esc and Capslock
  • Set the ‘lid close’ action to ’Do Nothing
  • Add a ‘hotedge’ using unity-tweak-tool (previously ccsm) to spread windows.
  • Set my open terminal shortcut to Ctrl-F12

Issues this time round

13.04 doesn’t seem to like my HP ProBook 6555b’s Mobility Radeon HD 4225/4250. On booting I was met with a garbled display, the mouse moved but that was it (radeon driver).

Strangely, booting into recovery, then selecting continue boot from there seemed to bring up the desktop ok.

My solution to this has been to move back to 12.10’s kernel, 3.5.0-17. Update, kernel 3.9 fixes it!

A KISS* Approach to Android Localisation

Here’s a short write up on the method I use to localise my Android apps.

* this, not this

The problem

With the help of some kind contributers, both Glimmr and Roidrage are each translated into 11 languages between them, including German, Finnish, Japanese, Dutch, Russian, Sweedish, Danish, Spanish, Portugese, Polish, and Slovenian.

Managing these isn’t the easiest job in the world. Some people mention services such as http://www.getlocalization.com/, which seem decent, but come with two problems as far as I can see:

  1. They’re not free, which for a low/no profit app isn’t very ideal.
  2. They require sign up, and have somewhat of a learning curve.

Point 2. is the main problem for me. I don’t want to assume a level of expertise on my translator. They may speak 5 languages flawlessly, but haven’t a clue about xml, or have the time to create an account on a new site and learn it’s ins and outs.

A solution

What you can safely assume about most people however, is that they have used some form of a spreadsheet before. If they are offering to translate an Android app, it’s likely they already have a Google account.

So what I do is create a Google Doc, and invite them to update it with their translations.

You can view the doc for Glimmr here.

Step 1) Generating your doc
I’ve put together a couple of Python scripts to help manage these. The first thing you’ll want to do is ‘seed’ your spreadsheet with the source language (English in most cases).

1
2
3
$ git clone git://github.com/brk3/android-scripts.git
$ cd android-scripts
$ ./get_strings.py your-project/res/values/strings.xml

This will parse the strings from your default strings.xml and dump them stdout. You can then copy these to your doc.

Step 2) Importing a new set of translations back into your app
Once someone has added a column by translating the first one into their language, you can generate a strings.xml for that using the following steps:

  • Copy the column into a file, say /tmp/german.txt
1
$ ./strings_generate.py your-project/res/values/strings.xml /tmp/german

This will write a file called /tmp/output.xml. The script will also perform some basic checks and fixups on the translations vs. the source strings, including:

  • Missing linebreak characters
  • Swaps 2-3 dots for the ellipses unicode character (as recommended by Android lint guidelines)
  • Will bail if there are an uneven number of source strings vs. translated ones. (Missing translations are acceptable but there must be a blank line present to indicate this. Otherwise it’s likely there’s a mismatch.)

Inspect it to make sure you’re happy with the results, then copy it to res/values-de/strings.xml.

Summary

Obviously this process leaves a lot to be desired. There’s still way too many manual steps. The above scripts were put together out of necessity and not much else. I definitely think there’s room for a good project here, to somehow interact with Google docs from Python and generate all languages automatically.

So far I’ve preferred to put the time into app code rather than extend this kind of tooling. If you like the general idea though and would like to add improvements no matter how small, please submit a pull request to the android-scripts github.

Making Flickr Awesome Again (or at Least the Android Part)

A while back, around the time Marissa Mayer took over Yahoo, a site popped up with the message:

“Dear Marissa Mayer, PLEASE MAKE flickr AWESOME AGAIN”.

I’ve got into photography lately, and awesome or not, Flickr still seems to be the go to place for hobbyist photographers. Unfortunately the official Android app for Flickr was disappointing. Sure, it’s fairly functional, but it’s execution of a lot of this felt dated, the interface is slow and just not what I look for in an Android app.

I had been working on a Twitter app for about 3 months for much the same reasons as above, and it seems I wasn’t the only one to feel this way as recently the surge of new holo themed Twitter apps has been massive. Some of these already far surpassed my vision for my app, and so rather than trying to play catch up, I gave up. Shortly after, I took some of the work that had gone into my Twitter app and morphed it into Glimmr.

I’m really thrilled to say so far the reaction has been pretty great. Thanks for reading, enjoy the app!

Cleaning Your Java Imports in Vim

The JavaImp plugin for Vim can add and organise imports in Java files at the press of a button. One thing that it’s missing however, is a way to find and remove redundant imports.

Here’s one solution I’ve come up with and would like to share; there may be neater ways but as a first pass I’ve found this works quite well.

First install the ‘checkstyle’ package:

1
$ sudo apt-get install checkstyle

Secondly, download the following script and save it under ~/bin/clean_imports.sh

Finally, add the following to your .vimrc:

1
2
3
4
5
6
7
" F7 to call clean redundant Java imports and sort them
function JavaImpClean()
    %!~/bin/clean_imports.sh %
    :JavaImpSort
endfunction
:command JavaImpClean exec JavaImpClean()
:nnoremap <F7> :JavaImpClean<CR>

Just hit F7 when editing any Java and have your imports cleaned and sorted. I’m sure with some more time this could be adapted to use a variety of code checkers to work with different languages.

Now all I need is a way to pull in all missing imports without having to go through each one…

Enjoy!

An Intro to Updating Your App for Ice Cream Sandwich

I recently managed to procure myself a Galaxy Nexus, and so started looking into how much it takes to apply 4.0 stylings to my app.

Surprisingly this can be easier than you think! Read on to find out how.

Before and after:

The easy way:

If you’re lucky, it can be as easy as changing one line, and rebuilding with the latest sdk. Provided you don’t have too much custom styling applied, try adding the following to your AndroidManifest.xml:

1
<uses-sdk android:targetsdkversion="15" />

If you leave the minSdkVersion as is, it should still work as always on pre ICS devices, but automatically apply ‘Holo’ theme on devices running 4.0.

If you’re unlucky / things to watch out for:

Getting a successful build after the above change is the ideal scenario. If you’re unlucky, your app may require a little more work to port.

As an example, I’ve recently ported the open source market app ‘Kitchen Timer’. This presented two problems:

1. The NumberPickers:
The current version of Kitchen Timer uses NumberPicker widgets, which were not officially available pre-ICS. These are now available since api 11, but in order to get these to update their style, I had to swap out each use of the custom NumberPicker instances and replace them with android.widget.NumberPicker, as well as update a couple of api calls.

An unfortunate effect of a change like this is that the app is now no longer compatible with pre-ICS.

2. The ActionBar
As I’ve quickly found out, there are no option menus in ICS, which have been since replaced by either a items on an ActionBar, or an overflow button on the button bar for backwards compatibility reasons. This is fine, except that the ActionBar can take up layout space that your original design may not have accounted for.

I ended up removing two buttons from the Kitchen Timer to allow all three timers to be controlled with one button.

Summary:

That’s about it, if you’re lucky, just increasing your targetSdkVersion and rebuilding with the latest sdk will be enough to instantly modernise your app.

Hopefully by having read the above you can save time by jumping over some of the more common pitfalls associated with this process.

Extra Reading:

You can also look at taking ports further with some of Jake Wharton’s fantastic backwards compatible libraries such as ActionBarSherlock, and ViewPagerIndicator.

Updated KitchenTimer source

Writing Multitouch Applications on Android

Like many things in Java/Android, writing multitouch enabled applications in Android can require quite a bit boilerplate code. It also requires quite a bit of knowledge of the workings of multitouch, and how the points are tracked by the api. This can make it tedious for new developers to get started with implementing this kind of functionality.

Much of the above can be avoided by using Luke Hutchison’s android-multitouch-controller.

It still requires some boilerplate, however it takes care of a lot of the headaches around properly implementing operations such as pinch-to-zoom, pinch-to-scale, pinch-to-rotate, etc., and lets you get on with the rest of your app.

I’ve found it quite extendable, and it provides a good basis for those needing to implement a more advanced multitouch tracking. I’ve also made use of it extensively for my app RoidRage, so thought I could share some examples on how to get started with using this library.

Overview:

First, grab the latest source from github:

1
$ git clone git://github.com/brk3/android-multitouch-controller.git

This is my fork from Luke’s original repository on Google code. It contains some extras and refinements, which I’ll get into another time.

I may get round to making it into a library project but until then it’s relatively easy to just drop into your own code:

1
$ cp -r android-multitouch-controller/src/org $MYPROJECT/src

You then need to implement the MultiTouchObjectCanvas interface from the View you want to be multitouch enabled, and override a couple of methods:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import org.metalev.multitouch.controller.MultiTouchController;
import org.metalev.multitouch.controller.MultiTouchController.MultiTouchObjectCanvas;
import org.metalev.multitouch.controller.MultiTouchController.PointInfo;
import org.metalev.multitouch.controller.MultiTouchController.PositionAndScale;
import org.metalev.multitouch.controller.MultiTouchController.MultiTouchEntity;
import org.metalev.multitouch.controller.MultiTouchController.ImageEntity;
 
public class DemoView extends View
        implements MultiTouchObjectCanvas<MultiTouchEntity> {
 
    private MultiTouchController<Object> multiTouchController =
        new MultiTouchController<Object>(this);
 
    public DemoView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
 
    @Override
    public void selectObject(MultiTouchEntity e, PointInfo touchPoint) {
 
    }
 
    @Override
    public boolean setPositionAndScale(MultiTouchEntity e,
            PositionAndScale newImgPosAndScale, PointInfo touchPoint) {
        return true;
    }
 
    @Override
    public void getPositionAndScale(MultiTouchEntity e,
            PositionAndScale objPosAndScaleOut) {
    }
 
    @Override
    public MultiTouchEntity getDraggableObjectAtPoint(PointInfo pt) {
        return null;
    }
 
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return multiTouchController.onTouchEvent(event);
    }
 
    // rest of my code..
}

The first thing you’ll probably notice about the above is the template type T given to the MultiTouchObjectCanvas. This can be any class you want, depending on how you want to interact with your canvas. In most cases, people will probably be interested in manipulating images, so my fork of this library contains two new classes, MultiTouchEntity, and a subclass called ImageEntity.

ImageEntity is a small subclass of MultiTouchEntity, which can be used to hold an image to be managed by multitouch.

Let’s see how we can add some images to our above example using ImageEntity:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
import org.metalev.multitouch.controller.MultiTouchController;
import org.metalev.multitouch.controller.MultiTouchController.MultiTouchObjectCanvas;
import org.metalev.multitouch.controller.MultiTouchController.PointInfo;
import org.metalev.multitouch.controller.MultiTouchController.PositionAndScale;
import org.metalev.multitouch.controller.MultiTouchController.MultiTouchEntity;
import org.metalev.multitouch.controller.MultiTouchController.ImageEntity;
 
public class DemoView extends View
        implements MultiTouchObjectCanvas<MultiTouchEntity> {
 
    private MultiTouchController<MultiTouchEntity> multiTouchController =
        new MultiTouchController<MultiTouchEntity>(this);
 
    private ArrayList<MultiTouchEntity> mImages =
        new ArrayList<MultiTouchEntity>();
 
    private static final int[] IMAGES = { R.drawable.m74hubble, R.drawable.catarina,
        R.drawable.tahiti, R.drawable.sunset, R.drawable.lake };
 
    public DemoView(Context context, AttributeSet attrs) {
        super(context, attrs);
 
        Resources res = context.getResources();
        for (int i = 0; i < IMAGES.length; i++) {
            mImages.add(new ImageEntity(IMAGES[i], res));
            mImages.get(i).load(context, 50.0f, 50.0f);
        }
    }
 
    @Override
    public void selectObject(MultiTouchEntity e, PointInfo touchPoint) {
        if (img != null) {
            // Move image to the top of the stack when selected
            mImages.remove(img);
            mImages.add(img);
        } else {
            // Called with img == null when drag stops.
        }
        invalidate();
    }
 
    @Override
    public boolean setPositionAndScale(MultiTouchEntity e,
            PositionAndScale newImgPosAndScale, PointInfo touchPoint) {
        boolean ok = ((ImageEntity)img).setPos(newImgPosAndScale);
        if (ok)
            invalidate();
        return ok;
    }
 
    @Override
    public void getPositionAndScale(MultiTouchEntity e,
            PositionAndScale objPosAndScaleOut) {
        objPosAndScaleOut.set(img.getCenterX(), img.getCenterY(),
            (mUIMode & UI_MODE_ANISOTROPIC_SCALE) == 0,
            (img.getScaleX() + img.getScaleY()) / 2,
            (mUIMode & UI_MODE_ANISOTROPIC_SCALE) != 0,
            img.getScaleX(), img.getScaleY(),
            (mUIMode & UI_MODE_ROTATE) != 0, img.getAngle());
    }
 
    @Override
    public MultiTouchEntity getDraggableObjectAtPoint(PointInfo pt) {
        float x = pt.getX(), y = pt.getY();
        int n = mImages.size();
        for (int i = n - 1; i >= 0; i--) {
            ImageEntity im = (ImageEntity) mImages.get(i);
            if (im.containsPoint(x, y))
                return im;
        }
        return null;
    }
 
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        return multiTouchController.onTouchEvent(event);
    }
 
    // rest of my code..
}

Again for simple purposes it’s possible that the amount of boilerplate could be stripped down further, but if you have a read through it’s fairly self explanatory.

The above code has been mostly extracted from the demo application that ships with the library, ‘MTPhotoSorter’, which I recommend at least building and installing this to get a feel for what’s possible with the library.

That’s about it for now, I can follow up this post with a few more tips and examples if anyone finds it useful.

First App

It’s been about two and a half months since I started work on my first Android app, and I’m proud to say I’ve finally managed to get it out.

Have to say I’ve really enjoyed it from start to finish, and hope it will be the first of many :) Here’s hoping it actually works for people and at least someone manages to have some fun with it.

If you’re reading this for the first time thanks for stopping by, I’ll try to keep update here a little more frequently with news of any updates. For the dev interested folk I may also try and find time to write up on some of the trickier issues I encountered along the way.

That’s all for now, check out my app and leave it 5 stars, you know you want to ;)

The Importance of Uniform UIs

It’s a little ironic that given Android is one of the easier platforms to pirate software, it’s also one of the platforms I don’t mind paying for software. An app I’ll pay for generally meets the following criteria:

  • I use it multiple times a day, and will continue to over a long period.
  • The developer appears responsive to users regarding features/support.
  • It’s a reasonable price (in my opinion this is generally less than €1.99).
  • It looks good and has an intuitive interface.

The last point is probably the main one and something I think is unfortunately lost on a lot of developers. It’s fair to say many programmers aren’t good graphic designers. Good is obviously also a subjective term.

Enter the Android UI Guidelines. Google have taken the time to concisely write up guidelines on how an app should look and feel, the benefits of which should be obvious. Do they stifle creativity or prevent an app from looking distinct? No. But what they will do is help users feel at ease using your app from the get go, and help them run great on as many different devices as possible.

It really frustrates me to see people recommending an app so highly only to download it on my Desire HD to be met with stretched out low res icons, ignoring the use of the dedicated Android hardkeys with ever present settings menus etc.

Apple have a very similar set of guidelines for developing iOS apps, yet they seem to suffer far less from this issue. I don’t think the old cliche of fragmentation is at fault here at all, more developers not wishing to follow standards.

Perhaps Google could be a little better at regulating the marketplace also, particularly as the Android tablets start to launch.