How to start an Android app at boot time

I wanted to have my custom Android ROM boot up and start an application specific to my needs start immediately. This is the way to accomplish it:

In your AndroidManifest.xml document (application part):

<receiver android:enabled="true" android:name=".BootUpReceiver"
        android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
        <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
</receiver>

You also need to set up a permission with

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

and then create the BootUpReceiver class to handle it

public class BootUpReceiver extends BroadcastReceiver{
        @Override
        public void onReceive(Context context, Intent intent) {
                Intent i = new Intent(context, MyWhateverActivity.class);  
                i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(i);  
        }
}

Android Intent to install app dependencies

I finally find myself actually having to learn Android app development properly now, and came up against an issue where I need my app to [optionally] install another app form my F-Droid repo or the Google Play store.

Luckily, either way, you should be covered as the Android framework is clever enough to parse the market:// URI’s as “generic package manager” so if you have a Free ROM that does NOT include Google Play services, you should still be OK with this code.

I have set a button click event to go and check if the app is installed, and then install it with an alert.

Button boButton = (Button) findViewById(R.id.bo_button);

        boButton.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View arg0) {

                try{
                    Intent intent = new Intent("com.dstv.boxoffice.android.SCAN");
                    intent.setPackage("com.dstv.boxoffice.client.android");
                    startActivityForResult(intent, 0);
                } catch (Exception e) {
                    createAlert("BoxOffice Application not installed!", "This application uses " +
                            "the BoxOffice application by DStv, you need to install " +
                            "this before you can use this functionality!", true, "market://search?q=pname:com.dstv.boxoffice.client.android");
                }

            }
        });

The intent above will fire off an alert (see code below) and prompt the user to install the required package.

private void createAlert(String title, String message, Boolean button, final String marketURL) {
        AlertDialog alertDialog;
        alertDialog = new AlertDialog.Builder(this).create();
        alertDialog.setTitle(title);
        alertDialog.setMessage(message);
        if ((button == true)) {
            alertDialog.setButton("Download Now",
                    new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface arg0, int arg1) {
                            Intent browserIntent = new Intent(
                                    Intent.ACTION_VIEW,
                                    Uri.parse(marketURL));
                            startActivity(browserIntent);
                        }
                    });
        }
        alertDialog.show();
    }

Simple!

Setting up a private Android appstore with FDroid

Introduction

There are a number of use cases to create an appstore with private data. As we create and release more devices and products, we are able to create matching AppStores to support them.
Appstores can be a way of controlling the software on the devices accurately, providing speed of update via a local store as opposed to Google Play, and also allows us a lot more flexibility in what we push to devices (agility). Our own curated appstores will also allow us to generate an income stream if we so desire, as well as create a dev community ecosystem for creation of apps for devices.

F-Droid server

FDroid is an Open Source package of server and client applications to deploy an app ecosystem similar to Google Play. The server scripts are written in Python language and the client is written in Java using Android SDK.

The FDroid Repository is an easily-installable catalogue of FOSS applications for the Android platform. The server contains the details of multiple versions of each application, and the Android client makes it easy to browse, install them onto your device, and keep track of updates.

Detailed installation instructions can be found in the official manual.

Prerequisites

Python

You will need a server, with a Python runtime installed. The python runtime should have the following prerequisites installed:
* PIL
* pip
* Python buildtools

Remember to install PIL with JPEG and Zlib support for reading APK files! I.e. install libjpeg and zlib1-dev packages for your OS BEFORE installing PIL with pip!

Android SDK

The Android SDK is used throughout the server to manage and read metadata from the APK files. It is also used for signing, compiling source and numerous other tasks
* Grab the SDK from http://developer.android.com/sdk/index.html
* Update the SDK once unpacked on the server with android sdk update –no-ui
* export ANDROID_HOME to the pwd

FDroid source

Grab the fdroid-server source from Gitorious
* git clone git://gitorious.org/f-droid/fdroidserver.git

Nginx installation

I used Nginx to serve the repo files, as nginx is very well suited to serving static content very quickly. There will be little modifications and no dynamic content as we proceed, so nginx is a good choice. You may use other web servers, but you will be on your own.
* sudo apt-get install nginx (on Ubuntu flavours)
* edit /etc/nginx/nginx.conf to suit your setup
* service nginx start/restart
* The nginx docroot is in /usr/share/nginx/www
* You may need to edit /etc/nginx/sites-enabled and allow directory listing of index.xml too.

Browsing to the IP/hostname of the server should now bring up an nginx placeholder page.

FDroid setup

* Create a directory to hold your repo.
* Copy the file config.py from fdroid. Edit the two following propertis in config.py with appropriate values:
* sdk_path = “/tools/android-sdks” (This should reflect the path of your Android SDK installation)
* repo_url = “http://localhost/fdroid” (this should be your server IP/hostname)
* repo_icon = “icon.png” (this must exist as a 48x48px png)
* Run fdroid update -c This will create a repo and aerchive directory
* Place all APK’s inside the repo directory
* Run fdroid update again. This will unpack and parse all of the APK files and make entries for them
* Done!

You should now be able to browse your repo via a web browser!

Next steps will be to customize the client, which will be on a seperate post

Using QEMU to emulate ARM devices

This post will show you how to set up a QEMU virtual device to play with your ARM code on an x86_64 host. It is quite simple, and you should be able to simply copy and paste into a terminal and get going relatively quickly.

As an example, we will be installing a debian build (wheezy) into your VM.

First off, we need to install the QEMU packages. I use Ubuntu/Mint, so this post will be somewhat biased towards that.

Let’s start off getting the packages we need:

sudo apt-get install qemu-kvm
sudo apt-get install qemu-system-arm
sudo apt-get install qemu-utils

Now we can check that everything is installed OK and ready to go with:

qemu -version

Make a directory to work with and then grab some files off your local debian mirror. Remember, we need the ARM based distro.

mkdir ~/arm-emul
cd ~/arm-emul
wget ftp://ftp.debian.org/debian/dists/wheezy/main/installer-armel/current/images/versatile/netboot/initrd.gz
wget ftp://ftp.debian.org/debian/dists/wheezy/main/installer-armel/current/images/versatile/netboot/vmlinuz-3.2.0-4-versatile

Remember now that depending on your board/device, you may want to check if it supports ARM EL or ARM HF. As you can probably guess from the above filenames, we are working with ARM EL. There are a number of differences between the way (and efficiency) of the two device types, but if you don’t know, then you are probably using an ARM EL device. Also, it is worth checking with your manufacturer if you haven’t built your device yourself, as ARM HF is a way better buy!

Let’s create a virtual HDD now to host the code/OS:

qemu-img create -f raw hda.img 8G

I like to create a drive as big as my devices flash ROM. In this case, it is 8GB. Yours may vary.

Now, lets get the system up and running:

qemu-system-arm -m 256 -M versatilepb -kernel ~/arm-emul/vmlinuz-3.2.0-4-versatile -initrd ~/arm-emul/initrd.gz -hda ~/arm-emul/hda.img -append “root=/dev/ram”

Should get you started with the Debian installer. Do the installation and then close your VM.

Once complete, mount your filesystem, and then copy the relevant files around. You need to do this step as debian will not be able to install the bootloader, so you kind of have to do it manually.

mkdir mount

sudo losetup /dev/loop0 hda.img
sudo kpartx -a /dev/loop0
sudo mount /dev/mapper/loop0p1 mount

cp ~/arm-emul/mount/boot/initrd.img-3.2.0-4-versatile ~/arm-emul/
sudo umount ~/arm-emul/mount

Now you can start up your brand new debian ARM VM with:

qemu-system-arm -M versatilepb -kernel ~/arm-emul/vmlinuz-3.2.0-4-versatile -initrd ~/arm-emul/initrd.img-3.2.0-4-versatile -hda ~/arm-emul/hda.img -append "root=/dev/sda1"

Great! Now off to make your custom OS and flash it to your board! Good luck!

Is SA ready for a “Tech tipping point” in 2014?

TL;DR – No, not unless we work together.

Marissa Meyer posted an article last night about 2014 being a tech tipping point. I would like to outline a few points related to this that I think may be important in 2014 for South Africa, as well as Africa as a whole.

1. At the base of it all is that devs in South Africa (especially really good ones) are few and far between. There are some notable exceptions, however, they do not really talk to each other much and would rather see each other as competition as opposed to peers. This is a poisonous attitude that has been reinforced by the fact that most of them come from a proprietary background and are used to keeping secrets close instead of sharing everything.

Co-opetition would largely solve this. Sure, be competitive as a company (we all need to make a living) but share more. Express yourselves better and seek help. There is no shame in asking, even if you are a top shelf developer! Share issues and successes, so that everyone learns from it and as a community we can improve things incrementally.

2. Consultants are on average paid better than developers. Why? Consultants are supposed to have a very wide knowledge of a number of products that will actually add benefit to the organization. In my experience, consultants in Africa are little more than highly paid salespeople for certain software suites that are installed with a few clicks of a mouse and then “supported” at exorbitant rates.

We need to move away from the consultant based architecture and ensure that software is written or customized for the organizational business needs. Off the shelf software normally comes with a lot of additional bloat (that still needs to be maintained) that is never used and presents a liability to the org in the form of additional security attack vectors, as well as additional expenditure maintaining dead weight.

3. Agility. Are we agile enough to respond to change? Not really. Many organizations have a sense of built in fear when it comes to change. This absolutely hampers growth. Remember that as an organization, your  competitive edge lies in your ideas and the people that can execute them. Any company can hire software people to hack out lines of mundane code, but in order to flourish and gain competitive advantage, you actually need a team of people that can do actual R&D. They will be able to keep up with trends and fashion new trends and pass them into the business, providing a large amount of value. The manner in which this value chain is maintained is another big point, but if those processes are not in place, you will also have a bad time!

4. Working together to ramp up scarce skills. Africa is a big continent. As a continent, we have about as many available developers as any other country, BUT this assumes that we can transgress boundaries and actually work together. If, as a whole, we would collaborate, we could certainly make a global impact (See the AVOIR project as an example), but this requires buy in and actual collaboration.

As it stands, we are simply unable to take advantage of any sort of “tipping point”. How many companies right now are actively doing R&D in areas such as: Semantics and internet of things, bandwidth and compression management, robotics and hardware hacking, big data analytics, and many others? These are the things that will make you stand out!

You need to think to yourself every day as a developer “How can I do something that has never been done before today?” Until that is a reality, we haven’t got a chance.

Low Earth Orbit ads

This may seem a little nuts, but it is an idea that I have been throwing around for a few years now.

Imagine a large company being able to launch a large billboard into Low Earth Orbit (LEO) and have it fly over entire countries displaying an advert? Companies like Coca-Cola could easily afford the costs, and the returns on a nice Equatorial orbit may be great!

I would approach it something like this (leave comments if you have better ideas!):

  • Mylar (space blankets) can be printed with the company logo etc.
  • Mylar also has the advantage of being thermally resistant as well as being very light to keep launch costs low.
  • Current launch costs are around USD 4000 – 20 000 depending on weight. This is completely affordable for most large advertisers
  • The billboard would burn up on re-entry, so the chance of persistent debris is lowered.
  • Careful monitoring of these objects would be simple, due to the reflective nature of the mylar.
  • Somebody could make a whole lot of dough if they ever get past the regulatory issues about putting very large pieces of junk into LEO.

Just an idea, but I think it may work. These should be low enough orbits so as to not interfere with things, and be very short lived.

What do you think?

ht_chromecast_nt_130724_16x9_992

Google Chromecast in a South African context

I had my Google Chromecast delivered from a local supplier last night, and thought that I would write a quick post on my experiences so far.

Seeing as though I have already had a large number of requests as to where I got it, I will answer that question first. I bought it from Takealot.com on the following URL http://www.takealot.com/tv-audio-video/google-chromecast-hdmi-streaming-media-player,29924636

Right, so the first thing that you need to do is plug the chromecast into a free HDMI port on your TV. Great. Easy enough. The box comes with an external power adapter as well as a USB adapter to power the device, but the external power plug is a US plug. Oops. Useless. USB power it is then! I would have liked to use the external power, simply for the fact that the TV does not have to be on for me to queue up online videos to the device, but alas, unless you are willing to screw around with clumsy power adapters and transformers, forget about it. The USB cable plugged into one of the TV USB slots and powered up the device without issue.

You are presented with a beautiful wallpaper and a device name, with the instruction to go and finish setup by connecting to your new Chromecast with an Android device or a laptop.

I tried to complete setup immediately with my Samsung Galaxy S4, having to download the Chromecast app from the Play store beforehand, which failed. I then tried to set up using my laptop computer, and was told by Google that I was using an unsupported OS (Linux), but I could try anyway. That failed too. Hum…

I then had a bit of an idea, and checked that uPnP was enabled on my (admittedly very old) wifi router, and enabled that. It would have been nice if that little caveat was covered in the intro screen, but it wasn’t. I use MAC address filtering to limit wifi access at home to specific devices, and one thing that I really did appreciate is that the Chromecast device displayed its MAC address on the setup page by default.

The setup, once started, becomes somewhat fiddly. My S4 has decided that a wifi connection is unworthy if it cannot reach the internet, and this was a big problem in completing the setup. I resorted to my laptop again, and managed to get through the steps after having to (confusingly) change wifi networks mid way to properly configure the device.

The device will not connect properly to anything but a 2.4GHz wifi network, so keep that in mind too.

I did have to do each of the steps a couple of times in order for the device to recognise my network and install itself properly, but once that was done, it was pretty plain sailing thereafter.

I immediately was able to stream a YouTube video to the TV in full HD without a glitch. The coolest part was that in the Chrome browser, I installed the Chromecast extension and was able to share not only a specific browser tab to the TV, but also my entire screen. There was some noticeable lag (about 500ms) when playing Kerbal Space Program via the network, but for a very graphics intensive app, and on a not-so-great wifi router, it was rather impressive (and still completely playable).

The apps that Google use to sell you the Chromecast (Netflix, Hulu etc.) are great, but not available in South Africa. Sure, I know that you can get a Netflix account (illegally) by spoofing a DNS service to make it look like you are in the US or UK, but the Chromecast has a trick up its sleeve. Google DNS services are hard coded into the device, so, even with a service like that, you would still need some trickery to get it right.

On the other hand, however, DStv BoxOffice works beautifully via a Chrome browser window, and you are able to enjoy the entire Online catalogue at R30 a movie, even if you are not a subscriber! To me, that is well worth the purchase price, as you are not entitled to pay a subscription, and you can rent when you want to. It is way cheaper for a family to grab a BoxOffice movie in this manner than it is to go to the cinema!

Overall, I think that the device is well worth getting (if you don’t already have an XBMC device or similar), although the price could come down a little in my opinion. There is a LOT of potential here, and I do think that we are only seeing the beginnings of something here for TV viewing.

The ultimate best awesome crazy cool killer feature of this device, though completely undocumented, is for people that do a lot of presentations. If you are a regular speaker, you will know that fiddling with projectors and screens on your laptop can quickly become a nightmare. I would suggest getting one of these things to pop into your laptop bag, and carry around with you. When you need to give a talk, simply plug it in and cast your presentation, saving a lot of time and stress!

I don’t normally do reviews like this, so I don’t really know how to end it off, but, yeah, get one of these things, they are OK tending towards good. In the future, depending on the climate, they may be awesome.

 

How to truncate multiple MongoDB collections in a Database

MongoDB has a drop() command that you can use to delete everything in a certain collection, but this also, unfortunately, will drop your indexes and other things too. What I wanted was a way that I could “truncate” the collection (borrowing from MySQL) and retain the indexes etc too.

The following snippet will do that, plus it has a built in “Oops, I changed my mind” safety check in case you need to cancel the collection truncate command.

var dbName = 'myDB';
db.getSiblingDB(dbName).getCollectionNames().forEach(function(collName) {
    // Drop all collections except system ones (indexes/profile)
    if (!collName.startsWith("system.")) {
        // Safety net
        print("WARNING: going to drop ["+dbName+"."+collName+"] in 5s .. hit Ctrl-C if you've changed your mind!");
        sleep(5000);
        db[collName].drop();
    }
})

This would be best saved as a UDF in your mongo shell, and probably made to take a parameter for the db too…

Spring data Neo4j using Java based config

There are very few examples in the wild on using Spring’s Java config methods to configure and start a Neo4j Graph Database service to use in your application. This post will serve as a primer to get you started on your Neo4j application and hopefully save you some bootstrap time as well!

The first thing that we need to do is make sure that you have a running Neo4j server up and ready for action, as well as a new Spring project that you can start with.

In your project POM XML file, you need to add in a few dependencies to work with Neo4j. In this example, I have used Neo4j-1.9.5-community (Spring Data Neo4j for Neo4j-2.x was not available at the time of writing). I have used Spring Framework 3.2.3-RELEASE as the Spring version, and Sping-data-Neo4j-2.3.2-RELEASE.

<dependencies>
		<!-- Spring and Transactions -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>

		<!-- Logging with SLF4J & LogBack  // clipped... -->
                <!-- JavaConfig needs this library -->
		<dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib</artifactId>
			<version>2.2.2</version>
		</dependency>

		<!-- Test Artifacts // clipped -->
                <dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
                <dependency>
			<groupId>cglib</groupId>
			<artifactId>cglib-nodep</artifactId>
			<version>2.2</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate.javax.persistence</groupId>
			<artifactId>hibernate-jpa-2.0-api</artifactId>
			<version>1.0.1.Final</version>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>1.0.0.GA</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-expression</artifactId>
			<version>${spring-framework.version}</version>
		</dependency>
		<dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-neo4j-aspects</artifactId>
            <version>${spring-data-neo4j.version}</version>
            <exclusions>
                <exclusion>
                    <groupId>org.hibernate.javax.persistence</groupId>
                    <artifactId>hibernate-jpa-2.0-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
		<dependency>
			<groupId>org.springframework.data</groupId>
			<artifactId>spring-data-neo4j-rest</artifactId>
			<version>${spring-data-neo4j.version}</version>
		</dependency>
		<dependency>
			<groupId>org.codehaus.mojo</groupId>
			<artifactId>aspectj-maven-plugin</artifactId>
			<version>1.2</version>
			<type>maven-plugin</type>
		</dependency>
	</dependencies>

NOTE: I have clipped some of the less relevant bits for testing and standard Spring dependencies, but if you would like a full POM example, please just let me know!

The next big thing is that you now need to define your graphDatabaseService as a bean that you can then use via the @Autowired annotation in the rest of your code.

import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.aspectj.EnableSpringConfigured;
import org.springframework.data.neo4j.aspects.config.Neo4jAspectConfiguration;
import org.springframework.data.neo4j.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.config.Neo4jConfiguration;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.jta.JtaTransactionManager;

@Configuration
@Import(Neo4jAspectConfiguration.class)
@EnableTransactionManagement
@EnableNeo4jRepositories("com.company.your.repos")
@EnableSpringConfigured
public class AppConfig extends Neo4jConfiguration {

	@Bean
	public GraphDatabaseService graphDatabaseService() {
                // if you want to use Neo4j as a REST service
		//return new SpringRestGraphDatabase("http://localhost:7474/db/data/");
                // Use Neo4j as Odin intended (as an embedded service)
		GraphDatabaseService service = new GraphDatabaseFactory().newEmbeddedDatabase("/tmp/graphdb");
		return service;
	}

Great! You are just about done! Now create a simple entity with the @NodeEntity annotation and save some data to it! You now have a working graph application!

This is really easy once you know how, sometimes, though, getting to know how is hard!

If you enjoyed this post, or found it useful, please leave a comment and I will start a new series on Neo4j in Java/Spring!

CORS in Python Bottle Framework

I was hacking up a quick mobile web app and needed to do an AJAX (jQuery based) POST and PUT to a simple Python Bottle REST server. Turn out that the AJAX POST was sending HTTP OPTIONS before the POST and the server was rejecting it with a 405. This, I find out, was due to a Cross Origin scripting issue and needed a solution.

Easiest way that I could come up with to fix the CORS (Cross Origin Resource Sharing) problem, was to write a simple bottle.py decorator that would enable me to do cross origin posts easily.

Firstly, the JQuery AJAX looked something like this on the client side:

$.ajax({
                            url: "http://host:port/save",
                            type: "POST",
                            data: JSON.stringify( { "mydata" : "Some stuff" } ),
                            contentType: "application/json",
                            success: function(data){
                                $("#result").html('got datal: ' + data);
                            },
                            error:function(error){
                                $("#result").html('There was an error while submitting: ' + error.message);
                            }
                    });

and the Python code looks like this:

# the decorator
def enable_cors(fn):
    def _enable_cors(*args, **kwargs):
        # set CORS headers
        response.headers['Access-Control-Allow-Origin'] = '*'
        response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, OPTIONS'
        response.headers['Access-Control-Allow-Headers'] = 'Origin, Accept, Content-Type, X-Requested-With, X-CSRF-Token'

        if bottle.request.method != 'OPTIONS':
            # actual request; reply with the actual response
            return fn(*args, **kwargs)

    return _enable_cors

You can then add the decorator to whatever of your @route methods that you need to enable CORS for with the simple @enable_cors annotation

@route('/save/', method=['OPTIONS', 'POST'])
@enable_cors
def save():
    # Rest of your code here...

Note that in the method I have set a list of the allowed methods, which include HTTP OPTIONS…

That is it! Javascript folks will tell you to rather do a $.post query, but I do prefer this method (I am more of a server side type of dude…)

There are, other ways to achieve this, but in my opinion, this is simplest and most elegant.