Paul Bourke

Notes, tips, photos, and code.

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.

Experts Exchange Annoyances

Google have just released a nice extension for Chrome for filtering or blocking certain sites from appearing in search results.

What makes this different from just a hosts file or adblock is that it takes the most blocked sites and sends them back to Google for analysis.

The first thing that came to my mind was the numerous crappy one click hoster “link” sites that seem to consistently manage to make it into the top search results as long as you search rapidshare+anything.

Most people however seem to be glad that this might finally mean the end of sites such as experts-exchange.com. This seems to appear in a surprisingly frequent number of programming related searches, only to infuriate the answer seeker with a subscription fee for the answer.

What a lot of people still don’t know though, is if you scroll right down to the bottom on these pages, the answer was there all a long for free :)

TL;DR version: Scroll down to the bottom on experts-exchange for the answer.

Hello World

Welcome to my blog. I like the thought of putting some of my thoughts/experiences down in writing, not so sure about the making it public part!

As I continually begin to get drawn in to use more and more services on the web, I hope I can also use this to amalgamate my various profiles into one place.

I’m already quite impressed with some of the fun things people are doing with bloggerjekyll so will see how it goes :)