Thursday, June 21, 2012

More Bash magic

set to automatically cd into a dir by typing its name:
shopt -s autocd

go back to previous pwd ($OLDPWD):
cd -

rename a path with a new suffix:
mv /var/www/test{,1}

Again all courtesy of my co-worker Ben.M

Tuesday, June 19, 2012

Android SDK Ant bugs

BEWARE: if you are using r15 of the Android SDK and building with a custom Ant post-build target then this bug might bite you! r17 through to r19 is confirmed as working ok.

Monday, June 11, 2012

Ubuntu UI Annoyances

If you find ubuntu new "on hover" osx-envy scrollbars as frustrating and annoying as I do you want to do:

sudo apt-get remove liboverlay-scrollbar*

(thanks to co-worker Ben M. for this super handy tip).

Sunday, May 20, 2012

Tuesday, May 1, 2012

On Android Services, Threads and Exceptions

So it turns out that if you actually read the developer documentation carefully, "Services" in Android are not "background jobs" or "daemons" as you might expect from the name.  No what they are is in fact simply a configuration mechanism to inform the Android OS that your application has work to do that can occur at times when your application Activities are not visible to the user.

Thus Services not only do not have their own separate Thread, but in fact are simply executed by your applications main thread, in response to events based on the service life-cycle. An important result of this is that within a Service or an Activity, all long-running jobs should be performed on a separate background as otherwise they will be run on the main thread.

The main source of confusion comes about because the Android developer documentation talks about Services being "killed" and restarted by the OS. But this actually simply referring to the process (i.e. the Linux process) which hosts each apps Dalvik VM and the fact that the OS can kill the process at anytime such as when memory is low. It's only in this case that Services would be "restarted" by the OS/Framework, but this of course only refers to the Services lifecycle callback methods (e.g. onCreate and onStartCommand) being called by your apps main thread after your app is restarted inside a new VM running within a new process. Once you understand this, the purpose of the "STICKY" flags then becomes obvious, as just being means to inform the framework how it should go about re-calling those callback methods after an app is restarted in a new VM.

An interesting result of all this is that there is no such thing as a Service "dying" in your app, except of course for the case of it throwing an uncaught exception, which would cause your apps main thread to exit and thus your whole app to "quit" bringing up the famous "Force Close" system dialog.  Should you wish however to handle that situation, you have available to you the Thread.setDefaultUncaughtExceptionHandler() method which will allow you to catch unhandled exceptions and doing something useful (like logging them to the device storage or some external service) prior to your current foreground Activity existing.

Sunday, April 15, 2012

Automatic Android Release Builds with CI

So if you are using a CI server (eg. Hudson aka Jenkins) to build your Android app, when you come to release it you'll want to do that automatically too.

All thats required is this kind of stanza in your build.xml:

<property environment="env"/>
<target name="-post-build" >
        <copy todir="bin">
            <fileset dir="bin">
                 <include name="myappname-*.apk"/>
            </fileset>

            <globmapper from="myappname-*.apk" to="myappname-*.${env.BUILD_NUMBER}.apk"/>
        </copy>
</target>


As you can see I'm also naming the final apk file with the Jenkins build number environment variable.  There are a lot more other env vars that Jenkins sets that you can use.

Also note the reason I've used the globmapper is that this will work for both the debug and release build targets that are pre-defined in the standard android project ant build configs. This means you can have Hudson build configs for both debug and release.

If you want your release apk to be properly signed, you need to create a certificate and then point your ant build at it (ant.properties):

key.store=path/to/my.keystore
key.alias=mykeystore

If you don't want to type in the password for each build, you can add the following to your local.properties:

key.store.password=secretpasswd
key.alias.password=secretpasswd

And also add the passwd properties to your Jenkins config (click "Advanced" button in the "Invoke Ant" section of your build config). This way you never have to check your keystore passwords into version control.

Oh as a bonus, if you want to be able to access the build information within your apps code at runtime, you can stash this in a string value by putting something
like this in your build.xml:

<property environment="env"/>
<target name="-pre-build">
        <echo file="res/values/buildtag.xml"><![CDATA[<?xml version="1.0" encoding="utf-8"?> 
            <resources>
                <string name="build_version">ABCXYZ123</string>
            </resources>
            ]]>
        </echo>
                <replace file="res/values/buildtag.xml" token="ABCXYZ123" value="${env.BUILD_TAG}"/>
</target>