<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>ajack.org</title>
 <link href="http://ajack.org/atom.xml" rel="self"/>
 <link href="http://ajack.org/"/>
 <updated>2013-01-22T14:06:23+00:00</updated>
 <id>http://ajack.org/</id>
 <author>
   <name>Jack Weeden</name>
   <email>jack@ajack.org</email>
 </author>

 
 <entry>
   <title>Quickly making files publicly accessible with Dropbox and Automator</title>
   <link href="http://ajack.org/blog/quickly-making-files-publicly-accessible-with-dropbox-and-automator"/>
   <updated>2012-05-16T00:00:00+01:00</updated>
   <id>http://ajack.org/blog/quickly-making-files-publicly-accessible-with-dropbox-and-automator</id>
   <content type="html">&lt;p&gt;Quite often I want to take a screenshot, put it in my Dropbox's public directory and share the link with somebody. Typically this entails taking the screenshot, opening Finder, moving the file to Dropbox/Public, right clicking the file, choosing &quot;Copy Public URL&quot; and shraing the link. I knocked together a little Automator service to take some of the monotony out of it.&lt;/p&gt;

&lt;p&gt;Open Automator and choose to create a new Service.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2012/automator-dropbox-1.png&quot; alt=&quot;Create a new service&quot; /&gt;&lt;/p&gt;

&lt;p&gt;First, change the &quot;Service receives selected&quot; drop down to &quot;files or folders&quot; in &quot;Finder&quot;. This ensures the service is only available in the context menu when clicking on items in Finder.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2012/automator-dropbox-2.png&quot; alt=&quot;Service receives selected&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Choose &quot;Files and Folders&quot; from the library and drag &quot;Copy Finder Items&quot; into the main window. In the &quot;To:&quot; dropdown, select &quot;Other...&quot; and browse to your Dropbox Public directory. Check the &quot;replace existing files&quot; if that's what you feel like doing.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2012/automator-dropbox-3.png&quot; alt=&quot;Move Finder items&quot; /&gt;&lt;/p&gt;

&lt;p&gt;We'll need to get your public URL first though, so browse to your Dropbox directory in Finder, right click a file and hit Dropbox &gt; Copy Public Link. Paste this somewhere and remove the filename from the end, you'll end up with something like &quot;http://dl.dropbox.com/u/123456/&quot; where &quot;123456&quot; is unique to your account.&lt;/p&gt;

&lt;p&gt;Now choose &quot;Utilities&quot; from the library, and drag &quot;Run Shell Script&quot; into the main window, underneath the existing action. We're going to write a little script that will get the filename, append it to your Dropbox public URL and copy it to the clipboard.&lt;/p&gt;

&lt;p&gt;First, make sure you change the &quot;Pass input:&quot; dropdown to &quot;as arguments&quot;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2012/automator-dropbox-4.png&quot; alt=&quot;Pass input as arguments&quot; /&gt;&lt;/p&gt;

&lt;p&gt;In the input field, paste in the following code replacing the URL in the first line with your public URL we got earlier.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;dropbox_url&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;http://dl.dropbox.com/u/XXXXXX/&amp;quot;&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -ne &lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;dropbox_url&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}$(&lt;/span&gt;basename &lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt; | pbcopy
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;That's it. Hit File &gt; Save and give the service a name (I called mine &quot;Copy to Dropbox&quot;).&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2012/automator-dropbox-5.png&quot; alt=&quot;Finished service&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now, when you right click a file in Finder there'll be an option to use the service. Select it and the file will be copied to the public directory and the Dropbox URL for it will be copied to your clipboard. I should note here that while the URL will be immediately copied to your clipboard, the file will take a certain time to upload to Dropbox, so it'll probably not be ready immediately. I just check the Dropbox icon in the menu bar - if it's still flashing then the file's not ready yet.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2012/automator-dropbox-6.png&quot; alt=&quot;Context menu&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I chose to make two versions of this, one which copies the file to the public directory and one which moves it. To move instead of copy, simply drag the &quot;Move Finder Items&quot; action from the library in the first step, instead of &quot;Copy Finder Items&quot;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Using Growl for long-running scripts</title>
   <link href="http://ajack.org/blog/using-growl-for-long-running-commands"/>
   <updated>2012-01-10T00:00:00+00:00</updated>
   <id>http://ajack.org/blog/using-growl-for-long-running-commands</id>
   <content type="html">&lt;p&gt;Often it's nice to know when a long-running process has finished without having to continually check the terminal it's running in. I use this small function to call &lt;a href=&quot;http://growl.info/&quot; title=&quot;Growl&quot;&gt;Growl&lt;/a&gt; to notify me when a command has finished.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;gn &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    /usr/local/bin/growlnotify -m &lt;span class=&quot;s2&quot;&gt;&amp;quot;Starting \&amp;quot;$*\&amp;quot;&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;$*&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$?&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; 0 &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
        /usr/local/bin/growlnotify -m &lt;span class=&quot;s2&quot;&gt;&amp;quot;\&amp;quot;$*\&amp;quot; succeeded&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt;
        /usr/local/bin/growlnotify -m &lt;span class=&quot;s2&quot;&gt;&amp;quot;\&amp;quot;$*\&amp;quot; failed&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This simply wraps the command in a couple of calls to growlnotify. Add this to your ~/.bash_profile and simply prepend &lt;em&gt;gn&lt;/em&gt; to your long-running command&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nb&quot;&gt;source&lt;/span&gt; ~/.bash_profile
gn nvm install v0.6.7
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;



</content>
 </entry>
 
 <entry>
   <title>Grabbing SMSs from a USB connected Android phone</title>
   <link href="http://ajack.org/blog/grabbing-sms-from-android"/>
   <updated>2011-12-02T00:00:00+00:00</updated>
   <id>http://ajack.org/blog/grabbing-sms-from-android</id>
   <content type="html">&lt;p&gt;Since moving abroad I've found myself in the position of being one of those guys that own more than one phone. It's a privileged and elite club for sure but I'll save the praise for another day. Now having two phones is useful as I can keep in contact with people in both countries for the smallest payout (although using my UK phone in the Netherlands is obviously expensive). I tend to carry my Dutch phone around with me during the day and leave my UK phone at home. That usually works fine but it's annoying if I get a text on the phone I don't have with me. Since the phone I leave at home is always connected via USB to a small server that sits on my desk, I figured it'd be easy to grab the new messages off it and shoot 'em over the internet to wherever I might be. Turns out it is.&lt;/p&gt;

&lt;p&gt;A note here: this technique almost certainly only works on rooted phones - I don't imagine you'd have access to the SMS database with a non-rooted device. For reference, I'm using a rooted T-Mobile G1 running CM5 (because I'm too lazy to update it).&lt;/p&gt;

&lt;p&gt;The method here is pretty straightforward: use &lt;a href=&quot;http://developer.android.com/guide/developing/tools/adb.html&quot; title=&quot;Android Debug Bridge&quot;&gt;adb&lt;/a&gt; to grab the SMS database off the phone, use python and sqlite3 to parse its contents, and send an email. In reality though there was no need to grab the database - everything could be done over adb. The first step was figuring out where the database was and what data it kept.&lt;/p&gt;

&lt;p&gt;The database is located at&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;/data/data/com.android.providers.telephony/databases/mmssms.db
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;and can be browsed using sqlite3 directly on the phone. The schema for the &lt;em&gt;sms&lt;/em&gt; table is:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;_id INTEGER PRIMARY KEY,
thread_id INTEGER,
address TEXT,
person INTEGER,
date INTEGER,
protocol INTEGER,
&lt;span class=&quot;nb&quot;&gt;read &lt;/span&gt;INTEGER DEFAULT 0,
status INTEGER DEFAULT -1,
&lt;span class=&quot;nb&quot;&gt;type &lt;/span&gt;INTEGER,
reply_path_present INTEGER,
subject TEXT,
body TEXT,
service_center TEXT,
locked INTEGER DEFAULT 0
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Some interesting data, but all I'm interested in is &lt;em&gt;address&lt;/em&gt;, &lt;em&gt;date&lt;/em&gt; and &lt;em&gt;body&lt;/em&gt;. Now that we've got this far, we can get all messages with one call of adb from the server, like so:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;adb shell &lt;span class=&quot;s1&quot;&gt;&amp;#39;sqlite3 /data/data/com.android.providers.telephony/databases/mmssms.db &amp;quot;SELECT address, date, body FROM sms&amp;quot;&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This gets us all of the messages on the phone. Since I wanted to just get &lt;em&gt;new&lt;/em&gt; messages, we can limit the SELECT to just return anything newer than &lt;em&gt;some date&lt;/em&gt;. I've already read all the messages on there so I only want to see new ones. So I created a text file, wrote the current date in milliseconds (since that's the format Android uses to timestamp its SMSs) to it and used that to limit the database query.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;adb shell &lt;span class=&quot;s1&quot;&gt;&amp;#39;sqlite3 /data/data/com.android.providers.telephony/databases/mmssms.db &amp;quot;SELECT address, date, body FROM sms WHERE date &amp;gt; \&amp;#39;SOME_DATE\&amp;#39;&amp;quot;&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;I wrapped this up in a Python script and scheduled it as a cron job, each time it runs it writes the current date to the file, which is read back in each execution. The server that the phone's connected to has a small landing page on it which I use to monitor backups and the like, so I figured that'd be a nice central point to display any new messages.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2011/android-sms.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The SMS is also delivered to my Gmail inbox which I typically have open, so I get a notification usually within a couple of minutes of receiving an SMS.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2011/android-sms-email.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Polling the phone every couple of minutes isn't the most optimal solution but I don't need to know about SMSs in realtime, so approximate is good enough.&lt;/p&gt;

&lt;p&gt;As usual the code is on &lt;a href=&quot;https://github.com/jackbot/android-sms-grabber&quot; title=&quot;Android SMS grabber&quot;&gt;GitHub&lt;/a&gt; so check it out.&lt;/p&gt;

&lt;h2&gt;Further work&lt;/h2&gt;

&lt;p&gt;The nice thing about this setup is that it's not just useful for notifying about new messages but can be used to control the server by sending the phone a certain string. For example, I could send a message of &quot;restart apache&quot; to the phone, check for that string in the Python script then perform the necessary action. Options!&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Quick Gmailer</title>
   <link href="http://ajack.org/blog/quick-gmailer"/>
   <updated>2011-10-06T00:00:00+01:00</updated>
   <id>http://ajack.org/blog/quick-gmailer</id>
   <content type="html">&lt;p&gt;At work I very rarely use my company-supplied computer, opting to use my personal machine with all my stuff on it. The only drawback to this is that I can't access the internal wiki or print. Drawbacks indeed. Since I typically have a terminal open, I wrote this script to send myself internal links that I might get via e-mail or files I want to visualise on some dead trees. It's very simple but means I don't have to go to Gmail and do it all manually.&lt;/p&gt;

&lt;p&gt;It accepts a range of parameters depending on whether you want a subject, body, attachment or mixture. The following examples assumed the script is aliased to 'g' (which the chicks dig)&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;g &lt;span class=&quot;s1&quot;&gt;&amp;#39;http://www.some-obscure-internal-link.com&amp;#39;&lt;/span&gt;
g ~/Desktop/secret_documents.txt
g &lt;span class=&quot;s1&quot;&gt;&amp;#39;Some subject&amp;#39;&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&amp;#39;Some body text....&amp;#39;&lt;/span&gt; /path/to/attachment
g &lt;span class=&quot;c&quot;&gt;# Read from stdin &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Not much to say about it! Check it out at &lt;a href=&quot;https://github.com/jackbot/quick-gmailer&quot; title=&quot;On GitHub&quot;&gt;Github&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Extracting single databases from MySQL dump</title>
   <link href="http://ajack.org/blog/extracting-single-databases-from-mysql-dump"/>
   <updated>2011-03-27T00:00:00+00:00</updated>
   <id>http://ajack.org/blog/extracting-single-databases-from-mysql-dump</id>
   <content type="html">&lt;p&gt;If you've ever used mysqldump (or PHPMyAdmin) to make a dump of every database on a host to a single file, you'll know how much of a pain it is to then go through that file to see which databases it contains. A while ago I dumped all the databases on my old desktop so I could import them on my MacBook. I did a straight dump of all the databases in one go, then when it came to importing them I decided I'd probably like to go through and sort them out, deleting any I didn't want. The file came in at around 300MB and so choked any GUI text editor I tried to open it in. Vim coped with it fine, but it was a chore to go through the thousands of lines just to see what was going on. So I wrote a small python script that parses the file, displays a list of the databases it contains and allows extraction of single databases into separate files.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2011/sql-extractor.png&quot; alt=&quot;SQL extractor&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Simply pass it the path of the SQL dump, choose a number from the list and it'll be written out to a new file in the current working directory under the name &lt;strong&gt;(database).sql&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get the script &lt;a href=&quot;http://www.ajack.org/code/sql-dump-extractor.py&quot; title=&quot;Get the script&quot;&gt;here&lt;/a&gt; or at &lt;a href=&quot;https://github.com/jackbot/sql-dump-extractor&quot; title=&quot;On GitHub&quot;&gt;Github&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>A motion interface with HTML5</title>
   <link href="http://ajack.org/blog/a-motion-interface-with-html5"/>
   <updated>2011-03-26T00:00:00+00:00</updated>
   <id>http://ajack.org/blog/a-motion-interface-with-html5</id>
   <content type="html">&lt;p&gt;I was looking at the &lt;a href=&quot;http://slides.html5rocks.com/&quot; title=&quot;HTML5 Rocks&quot;&gt;HTML5 Rocks slides&lt;/a&gt; yesterday and came across the &lt;a href=&quot;http://slides.html5rocks.com/#slide-orientation&quot; title=&quot;Device orientation&quot;&gt;Device Orientation&lt;/a&gt; slide which allows a compliant browser to access the orientation data from an accelerometer on a supported device. Then I noticed the Chrome logo moving and saw that Chrome is able to access the sensor data from my MacBook's &lt;a href=&quot;http://en.wikipedia.org/wiki/Sudden_Motion_Sensor&quot; title=&quot;Sudden Motion Sensor&quot;&gt;Sudden Motion Sensor&lt;/a&gt;. Awesome! I had no idea this data was available to the browser.&lt;/p&gt;

&lt;p&gt;I remembered seeing a few articles a while ago (when Apple started putting the accelerometers in MacBooks) where people had got access to the raw data and used it for such things as turning their machines into lightsabres and changing desktops by hitting the sides of the laptop. For some reason the latter always stuck in my head so when I saw the device orientation event in HTML5, I thought I could mimic this behaviour. Getting the sensor data is very simple, first you need to create the event handler.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;&lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;orientationListener&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;alpha&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;alpha&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;beta&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;beta&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;var&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;gamma&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;event&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;gamma&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Do stuff here&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You can then bind it to the &quot;deviceorientation&quot; event handler like so&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;javascript&quot;&gt;&lt;span class=&quot;nb&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;addEventListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&amp;#39;deviceorientation&amp;#39;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;orientationListener&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Easy! For some reason, the alpha value is always null. The beta value represents tilting the device left and right (roll) and the gamma value towards and away from you (pitch).&lt;/p&gt;

&lt;p&gt;I wrote a simple &lt;a href=&quot;http://ajack.org/code/html5-device-orientation.html&quot; title=&quot;Flickr browser&quot;&gt;Flickr browser&lt;/a&gt; which uses left and right tilting to browse a set of images. Here's a video of it in action.&lt;/p&gt;

&lt;iframe src=&quot;http://player.vimeo.com/video/21535483?title=0&amp;amp;byline=0&amp;amp;portrait=0&quot; width=&quot;400&quot; height=&quot;225&quot; frameborder=&quot;0&quot;&gt;&lt;/iframe&gt;



</content>
 </entry>
 
 <entry>
   <title>Fixing a Sansa Clip+ stuck in a boot loop</title>
   <link href="http://ajack.org/blog/fixing-a-sansa-clip-stuck-in-a-boot-loop"/>
   <updated>2011-03-21T00:00:00+00:00</updated>
   <id>http://ajack.org/blog/fixing-a-sansa-clip-stuck-in-a-boot-loop</id>
   <content type="html">&lt;p&gt;This is a quick post to outline the steps needed to sort out an 8GB Sansa Clip+ that's stuck on the firmware boot screen. I have had &lt;a href=&quot;http://rockbox.org&quot; title=&quot;Rockbox&quot;&gt;Rockbox&lt;/a&gt; installed on my Clip+ for some time and everything has worked flawlessly. A couple of weeks ago, however, I was having trouble booting into either Rockbox or the default Sansa firmware. Rockbox would get stuck on the loading screen while the default Sansa firmware would get stuck on the &quot;Refreshing your media&quot; screen.&lt;/p&gt;

&lt;p&gt;I wasn't able to reinstall Rockbox (which I figured to be the root of the problem) but I finally managed to get into the default firmware (if you've got Rockbox installed, hold left while powering the Clip on). The disk did not mount though so I couldn't update the Rockbox install. A quick look at dmesg showed there was a problem.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2011/sansa-clip-dmesg.png&quot; alt=&quot;dmesg&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There was no dice mounting /dev/disk1 manually either, so I popped open Disk Utility to see what it had to say. After hitting &quot;verify disk,&quot; I was confronted with a bunch of filesystem errors. Hitting &quot;repair disk&quot; sorted this out no sweat.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2011/sansa-clip-repair.png&quot; alt=&quot;Disk Utility&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If you're running Linux, just hit up some &lt;a href=&quot;http://en.wikipedia.org/wiki/Fdisk&quot; title=&quot;fdisk&quot;&gt;fdisk&lt;/a&gt;-fu, it'll achieve the same results. After this my Clip was working like a damn pro. I expect this will work if you're just running the standard firmware, but I haven't tried it.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Writing an autonomous Android app</title>
   <link href="http://ajack.org/blog/writing-an-autonomous-android-app"/>
   <updated>2011-03-20T00:00:00+00:00</updated>
   <id>http://ajack.org/blog/writing-an-autonomous-android-app</id>
   <content type="html">&lt;p&gt;I have recently been working on a project for my PhD that involved installing devices in people's homes in an attempt to change behaviours around recycling and food waste. In a nutshell, I needed to unobtrusively and reliably capture the contents of a kitchen bin. It was decided that the best way to do this was to augment the bin with a 3g or wifi enabled mobile phone which would be able to to the capturing, processing and transmitting of the data in a single, small device. Given that I have experience writing Android apps, and the fact that there is a multitude of different Android devices on the market, the Android platform was clearly the best option available to me. The overall aim of the project is to run a study with multiple student households in geographically different environments over a period of six weeks. The phones are securely encased within the bins, which makes them difficult to physically access, and the problem is further complicated due to the fact I have recently moved abroad as part of my PhD and so I am not even in the same country as the devices. This post serves to document my experiences in creating an autonomous Android app that requires little to no user intervention.&lt;/p&gt;

&lt;h2&gt;Crash reporting&lt;/h2&gt;

&lt;p&gt;The first thing I considered when starting to write the app was &quot;what's going to happen when the app crashes?&quot; Note the &quot;when&quot;, not &quot;if&quot; – if you think there is no chance that your app is going to crash at some point, you're almost entirely wrong. So before I think about how I'm going to recover from the crash, I'm going to want to see some details about it. This includes - at a minimum - a timestamp, a unique device identifier and the stack trace (so we know exactly where the error occurred and why). A friend of mine introduced me to &lt;a href=&quot;http://code.google.com/p/acra/&quot; title=&quot;ACRA&quot;&gt;ACRA&lt;/a&gt;, a fully comprehensive crash reporting tool. Of course it's possible to implement this yourself (see details in &lt;a href=&quot;http://stackoverflow.com/questions/601503/how-do-i-obtain-crash-data-from-my-android-application&quot; title=&quot;How do I obtain crash data from my Android application?&quot;&gt;this thread&lt;/a&gt;) but ACRA generates crash data and uploads it directly to a Google Docs spreadsheet, giving a nice overview of all crash information. Additionally, it's possible to set up e-mail notification when the spreadsheet has been changed, so you get informed of a crash reasonably quickly. The &lt;a href=&quot;http://code.google.com/p/acra/wiki/ACRA3HowTo&quot; title=&quot;ACRA how-to&quot;&gt;documentation&lt;/a&gt; for ACRA is very helpful and allows you to add crash reporting to your application within minutes.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2011/autonomous-android-acra.png&quot; alt=&quot;ACRA reports in Google Docs spreadsheet&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Since I have four Android devices in my project, I need a way of identifying which one has crashed. ACRA supports adding custom fields to the report, letting me include the IMEI number of the device. I use the IMEI number throughout my code as a way of uniquely identifying the devices, using the following code.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getIMEI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;TelephonyManager&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;telephonyManager&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TelephonyManager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getSystemService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;TELEPHONY_SERVICE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;telephonyManager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDeviceId&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;We'll need the &lt;em&gt;READ_PHONE_STATE&lt;/em&gt; permission to get the IMEI number, so add the following to your AndroidManifest.xml file.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;uses-permission&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;android:name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;android.permission.READ_PHONE_STATE&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Adding it to the ACRA report is as simple as the following:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;&lt;span class=&quot;n&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;imei&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Util&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getIMEI&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;ErrorReporter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getInstance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;putCustomData&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;IMEI&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;imei&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;ACRA reports back a &lt;em&gt;lot&lt;/em&gt; of information about a crash. Sometimes this can be a little overwhelming when looking at the spreadsheet, so I suggest hiding some of the columns that are irrelevant for you. Since I know a lot about my target devices (it's not an app that's released in the wild), I can hide several fields that don't tell me anything I don't already know.&lt;/p&gt;

&lt;h2&gt;Crash recovery&lt;/h2&gt;

&lt;p&gt;Now we have a nice way of visualising the crash report data, we should think about how to recover from a crash. Now Android has different ways of dealing with unexpected events. The system might generate an ANR (Application not responding) if it receives no response to an input event within 5 seconds (reference) or it might just straight up crash if an exception is thrown that is unhandled. This manifests itself in the all-too-commonly-seen force close dialog.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2011/autonomous-android-anr.png&quot; alt=&quot;Application not responding dialog and force close dialog&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Since my app doesn't deal with user input at all, this is largely irrelevant. But what happens when my software generates an exception? I'm dealing a lot with bitmaps and network transmissions so there's plenty of scope for things to go wrong. This is where &lt;a href=&quot;http://developer.android.com/reference/java/lang/Thread.html#setDefaultUncaughtExceptionHandler(java.lang.Thread.UncaughtExceptionHandler)&quot; title=&quot;Thread.setDefaultUncaughtExceptionHandler()&quot;&gt;Thread.setDefaultUncaughtExceptionHandler()&lt;/a&gt; comes into play. Calling this method, and passing it your own UncaughtExceptionHandler allows you to get control in the case any unhandled exception occurs. This is a nice thing to have in place because we don't want the Android system showing a dialog saying the app is not responding and prompting the user to close it because the environment in which we're running the app is not user-oriented. Intervening in this process allows us to control what happens when an unhandled exception is thrown. The following code snippet shows how we can do this. I only have one core activity in my app that does all of the capturing and transmitting of the images, so I put this line in there.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;&lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setDefaultUncaughtExceptionHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyDefaultExceptionHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;pintent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;That's all we need to handle those unhandled exceptions. (Note: I'm passing in a variable to the constructor, this will be explained later). Now we define our actual UncaughtExceptionHandler, like so:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;MyDefaultExceptionHandler&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;implements&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;UncaughtExceptionHandler&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PendingIntent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;restartIntent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;MyDefaultExceptionHandler&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;PendingIntent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;restartIntent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pi&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
        
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;uncaughtException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Thread&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Throwable&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// Send the ACRA report&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;ErrorReporter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getInstance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;handleSilentException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;// Restart the app using the PendingIntent&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;AlarmManager&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;mgr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AlarmManager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;restartContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getSystemService&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ALARM_SERVICE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;mgr&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;AlarmManager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;RTC&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;currentTimeMillis&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2000&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;restartIntent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;exit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;I'll outline what the rest of the code does below - of course, it's entirely up to you what you do when you encounter an unhandled exception but my actions are as follows.&lt;/p&gt;

&lt;h3&gt;Send an ACRA report&lt;/h3&gt;

&lt;p&gt;I want to report this exception as I would any other exception the app generates, which means sending an ACRA report to my Google Docs spreadsheet. Assuming you've set up ACRA as defined in the documentation, all you need to do is send a silent report.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;&lt;span class=&quot;n&quot;&gt;ErrorReporter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getInstance&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;handleSilentException&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;arg1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h3&gt;Restart the app&lt;/h3&gt;

&lt;p&gt;I want to restart my application right away, so the phone can continue to do its job. It's no good handling unexpected crashes then doing nothing. To restart the app, we can do the following. In my main activity which is running constantly, I create a &lt;a href=&quot;http://developer.android.com/reference/android/app/PendingIntent.html&quot; title=&quot;PendingIntent&quot;&gt;PendingIntent&lt;/a&gt; that will remain in existence even if the activity that created it no longer exists.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;&lt;span class=&quot;n&quot;&gt;PendingIntent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;pintent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;PendingIntent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getActivity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getBaseContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getIntent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getIntent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getFlags&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;This PendingIntent is passed to my UncaughtExceptionHandler above so it can be used with the AlarmManager to restart my app. In the overridden &lt;code&gt;uncaughtException()&lt;/code&gt; method, we get an instance of the &lt;a href=&quot;http://developer.android.com/reference/android/app/AlarmManager.html&quot; title=&quot;AlarmManager&quot;&gt;AlarmManager&lt;/a&gt; class, which allows us to schedule events for the future. As the above code shows, an event is scheduled 2000ms in the future (just to give a bit of a pause before we start the app again) and then the PendingIntent is passed to the alarm manager so it's given something to do (i.e. start the PendingIntent). Finally we exit so the process is killed.&lt;/p&gt;

&lt;p&gt;It is probably a good idea to only restart the app a certain number of times within a given timeframe. If there is a fundamental - and therefore consistent - problem with your code, your app is going to crash, restart, crash, restart, etc. continually. A simple rule saying &quot;if we've restarted n times in the past m minutes, don't restart the app, just close it and send a notification&quot;. Maybe the phone needs a reboot, which is covered below.&lt;/p&gt;

&lt;p&gt;We also want to make sure the app starts up when the phone boots. This way, if any manual intervention has to occur, we can just turn the phone off, turn it back on again and put it back in its housing. Once the phone boots up, the app will start automatically. To do this, we need to create a BroadcastReceiver which will receive a notification when the phone boots up. When it receives this notification, we can tell it to start the app. We'll need to create a new class for the BroadcastReceiver.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;BootReceiver&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;BroadcastReceiver&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;onReceive&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Intent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;arg1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;Intent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;MyActivity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;addFlags&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;FLAG_ACTIVITY_NEW_TASK&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt; 
        &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;startActivity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Each time the phone successfully boots, it'll create an intent to start MyActivity (you should replace this with the activity you want to start).&lt;/p&gt;

&lt;p&gt;We'll need to add the following to the AndroidManifest.xml file now to create the intent filter. Additionally, we'll require the &lt;em&gt;RECEIVE_BOOT_COMPLETED&lt;/em&gt; permission.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;receiver&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;android:name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;.BootReceiver&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;intent-filter&amp;gt;&lt;/span&gt;
        &lt;span class=&quot;nt&quot;&gt;&amp;lt;action&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;android:name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;android.intent.action.BOOT_COMPLETED&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class=&quot;nt&quot;&gt;&amp;lt;/intent-filter&amp;gt;&lt;/span&gt;
&lt;span class=&quot;nt&quot;&gt;&amp;lt;/receiver&amp;gt;&lt;/span&gt;

&lt;span class=&quot;nt&quot;&gt;&amp;lt;uses-permission&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;android:name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;android.permission.RECEIVE_BOOT_COMPLETED&amp;quot;&lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Conserving battery&lt;/h2&gt;

&lt;p&gt;Depending on your situation, your phone might not be constantly connected to a mains power source, in which case you'll need to minimise your battery usage. I used a couple of techniques to keep the power consumption down.&lt;/p&gt;

&lt;h3&gt;Turning off the radio&lt;/h3&gt;

&lt;p&gt;The majority of the time my app was just sitting there waiting for an event to happen in which the accelerometer triggered an action. Only then would a picture be uploaded to the server. It makes sense, then, that the radio only needs to be enabled when the transmission is happening, and it should be turned off the rest of the time. The simplest way to do this is to enable airplane mode when we don't need data connectivity, and disable it when we do. Airplane mode will cut all radio activity and therefore decrease battery consumption. We can write a function that enables airplane mode when we pass true, and disable it when we pass false.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;airplaneMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Settings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;putInt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getContentResolver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Settings&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;System&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;AIRPLANE_MODE_ON&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enable&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Intent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;intent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;Intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ACTION_AIRPLANE_MODE_CHANGED&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;putExtra&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;state&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;enable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sendBroadcast&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h3&gt;Dimming the screen&lt;/h3&gt;

&lt;p&gt;While this probably won't make much difference as the screen will turn off after a few seconds anyway, I kept the screen dimmed as much as possible while the app was running - no user intervention means nobody is going to be looking at the screen anyway.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;screenBrightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Window&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;float&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;WindowManager&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;LayoutParams&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;lp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getAttributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;lp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;screenBrightness&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;val&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;window&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setAttributes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;lp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;To set the screen brightness to its lowest value:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;&lt;span class=&quot;n&quot;&gt;screenBrightness&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;getWindow&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.05f&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h2&gt;Status information console&lt;/h2&gt;

&lt;p&gt;I wanted a way to remotely view the status of each of my devices and provide me with a way to manage them to some degree. This is of course invaluable if physical access to the devices is infeasible. A web interface is the most obvious solution here, especially as Android makes it easy to interface with HTTP services. I drafted a list of information I'd like a quick overview of for the devices.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time at which the app last started up&lt;/li&gt;
&lt;li&gt;Battery level&lt;/li&gt;
&lt;li&gt;Last activity&lt;/li&gt;
&lt;li&gt;Available memory&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2011/autonomous-android-console.png&quot; alt=&quot;A very minimally designed remote console&quot; /&gt;&lt;/p&gt;

&lt;p&gt;I wrote a PHP script that handles the transmitting of the information - which are supplied via GET parameters - and updates a database. Again, I used the phones' IMEI numbers to identify each one. Each time the app starts, it sends the current timestamp to the server and each time it captures a photo, it uploads the photo and current timestamp, battery level, and available memory. The following code creates an HttpClient and executes a call to the PHP script in question.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;&lt;span class=&quot;n&quot;&gt;HttpClient&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;httpClient&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;DefaultHttpClient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;HttpGet&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;request&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;HttpGet&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;http://www.my-server.com/update.php?action=an_action&amp;amp;imei=xxx&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;httpClient&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;execute&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;request&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Needless to say, we'll need the &lt;em&gt;INTERNET&lt;/em&gt; permission in order to do this, so this needs adding to the AndroidManifest.xml file.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;xml&quot;&gt;&lt;span class=&quot;nt&quot;&gt;&amp;lt;uses-permission&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;android:name=&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;android.permission.INTERNET&amp;quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;h3&gt;Time at which the app last started up&lt;/h3&gt;

&lt;p&gt;This information lets me know when the app was last started. This is useful to know as it lets me see when the last time the app crashed. Of course this information is available in the ACRA report but it's nice to have it on the console - which I visit more regularly.&lt;/p&gt;

&lt;h3&gt;Battery level&lt;/h3&gt;

&lt;p&gt;This is not necessarily a requirement but it's a nice thing to know. The devices are to be deployed into student houses (with a wall adapter so the phone has a continuous power source) but there's always the possibility that they'll get unplugged for whatever reason. So each time the phone uploads a photo, it'll also send the current battery level. If the battery level on any of the phones falls below a certain threshold, I get an e-mail notification and I can let the people in the household know that the phone has been unplugged. This the code you need to get the battery level.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;java&quot;&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getBatteryLevel&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Context&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;Intent&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batteryIntent&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;ctx&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getApplicationContext&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;registerReceiver&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;IntentFilter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Intent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ACTION_BATTERY_CHANGED&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rawlevel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batteryIntent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getIntExtra&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;level&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;batteryIntent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getIntExtra&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;quot;scale&amp;quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rawlevel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;amp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;amp&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;gt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rawlevel&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;level&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;You could do a nice visualisation to show battery level on your console, I just show the percentage. I should mention that this method will return a number between 0 and 1, so you'll need to multiply by 100 to get the percentage.&lt;/p&gt;

&lt;h3&gt;Last Activity&lt;/h3&gt;

&lt;p&gt;This is quite project specific, as my phones are taking pictures and uploading them - which provides the whole data source for the project - so I'd like to know if there's a lull in activity from any of the phones which might indicate something is wrong. To this end, each time an upload happens, I send the current timestamp to the server so I know how long ago the last activity was.&lt;/p&gt;

&lt;h3&gt;Available memory&lt;/h3&gt;

&lt;p&gt;As I'm dealing with bitmaps (and doing some resizing on the device), it's nice to know if the device is low on physical memory. Sending the amount of available memory on each image upload lets me see this. ACRA reports a the same data but only on a crash, this lets me see the memory availability on a more frequent basis.&lt;/p&gt;

&lt;h2&gt;Remote management console&lt;/h2&gt;

&lt;p&gt;Being able to see various bits of information about the status of each device is all well and good but it would be really nice if we could actually &lt;em&gt;control&lt;/em&gt; the device remotely. Really the only feature I wanted from this was the ability to reboot a device. It would be handy also to be able to do this from within the app, if, for example, the app is restarting itself over and over again the phone could be rebooted to see if this solves the problem. Helpfully, the PowerManager class provides us with the handy &lt;a href=&quot;http://developer.android.com/reference/android/os/PowerManager.html#reboot(java.lang.String)&quot; title=&quot;reboot()&quot;&gt;reboot()&lt;/a&gt; method. Easy, right? Well yes and no. When I was exploring how to remotely reboot the device, I found this method and went about writing the code to do it. My strategy was simple: use the web console to provide a link to reboot the device which, upon clicking, updates a flag in the database for the phone. When the app on the device starts, it executes an HTTP GET request to a script on the server which, if I've clicked the &quot;reboot&quot; link, returns a given string (e.g. &quot;reboot&quot;). The phone gets the response from the server and if it equals &quot;reboot&quot;, we reboot the device. Very simple but effective. It was only when I got to calling the PowerManager.reboot() method that I realised it's only available for API level 8 and higher (i.e. Android 2.2). The phones I chose for this project are Sony Ericsson XPeria X10 minis - chosen for their small physical size and having an on-board camera flash - which run Android 1.6. People have managed to put 2.1 onto the phones, but seemingly not 2.2, so I was really stumped. I am yet to come up with a method of rebooting the devices (short of rooting them, which is difficult since they're in a different country). This method, however, would work fine on 2.2 and above.&lt;/p&gt;

&lt;h2&gt;Further work&lt;/h2&gt;

&lt;p&gt;One feature I'm missing which would be extremely useful is the ability to do a remote update of the app. I've got all this infrastructure to inform me of problems and let me view device stats but no way of being able to really fix the problems. There's only one way I can think of to achieve this which involves a couple of issues for me: Android 2.2 and upwards support automatic updating of installed apps. However, this requires both devices running Android 2.2 (which mine do not) and also that the app is installed via the Android Market (which I wanted to avoid as it's not a publicly released app). The latter issue could be resolved by restricting the app to run on devices with specific IMEI numbers, and showing a message on other devices telling the user to uninstall the app as it will serve no purpose. This is a bit of a hack but it would solve the problem.&lt;/p&gt;

&lt;p&gt;I suspect with a rooted device it would be possible to put the APK on a server and use the methods outlined above to check if an update is needed, download the APK and install it locally. Since my devices aren't rooted, I haven't looked into this but I expect if you can get shell access, you could do this.&lt;/p&gt;

&lt;h2&gt;Do a pilot study&lt;/h2&gt;

&lt;p&gt;It is best when embarking on a project like this to schedule a pilot study first. This is especially invaluable if, like me, your testing strategies aren't all that extensive. Running the software for a short period of time before the real study will help you iron out any problems you might experience, or add any additional features you think are required.&lt;/p&gt;

&lt;h2&gt;Conclusions&lt;/h2&gt;

&lt;p&gt;Android is a great platform for using in projects like this &amp;ndash; the flexibility, ease of creating apps and feature-packed SDK really allow for software to be written that requires minimal, if any, user intervention. However, Android was not designed for such an environment and that sometimes gets in the way. The platform is intended to provide end users with a rich interactive experience &amp;ndash; quite the opposite of what I wanted here. It's also created in such a way that attempts to protect the user from any unscrupulous activity from less-than-honest apps (that's a good thing!) which makes it more difficult when you're creating something that you know will only be deployed on one device and you'd like to get real system level access and do things that maybe wouldn't be looked upon too kindly if distributed to the entire Android population. Still, as I've outlined here, it's certainly not an impossibility.&lt;/p&gt;

&lt;p&gt;If you're going to use Android devices for a similar project, I'd suggest using ones that can run 2.2 and upwards so you can remotely reboot it.&lt;/p&gt;

&lt;p&gt;The pilot study for this project will begin in the coming week so I'll be able to see how well these ideas worked.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Firefox Usage Visualisation</title>
   <link href="http://ajack.org/blog/firefox-usage-visualisation"/>
   <updated>2010-12-15T00:00:00+00:00</updated>
   <id>http://ajack.org/blog/firefox-usage-visualisation</id>
   <content type="html">&lt;p&gt;Recently I've been finding myself reading a lot about data visualisation and I've become quite interested in the many different ways it's possible to display data. I've fiddled a little with &lt;a href=&quot;http://www.processing.org/&quot; title=&quot;Processing&quot;&gt;Processing&lt;/a&gt; in the past – I like the way it's super easy to show something tangible with very little effort (especially as graphics isn't my strong point). In my recent readings about visualisation, I came across the &lt;a href=&quot;http://design-challenge.mozillalabs.com/open-data/OpenDataCompetition.php&quot; title=&quot;Mozilla Open Data Visualization Competition&quot;&gt;Mozilla Open Data Visualization Competition&lt;/a&gt;, a competition held by Mozilla to visualise data gathered from users participating in &lt;a href=&quot;https://testpilot.mozillalabs.com/&quot; title=&quot;Test Pilot&quot;&gt;Test Pilot&lt;/a&gt; program. Test Pilot anonymously gathers data relating to various aspects of typical Firefox usage from users who have chosen to participate.&lt;/p&gt;

&lt;p&gt;I spent a while thinking what parts of this data to visualise, then realised the deadline was a couple of days away so chose something reasonably quick and easy. I wanted to see how the open source nature of Firefox affected other devices and software its users choose. People use Firefox for many different reasons but I wanted to find out what the proportion of people using it due to the fact that it's open source. The surveys and data gathered in Test Pilot cover a wide range of aspects of Firefox usage but there was some data that was useful for this. First things first, the visualisation.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;http://static.ajack.org/images/2010/firefox-visualisation.png&quot; alt=&quot;Firefox vis&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There were two aspects I was interested in: what smartphones are Firefox users using and what other browsers they use. The circular graphs on the left indicate which specific phones/browsers are in use and the pie charts on the right show the total proportion of these in terms of open and closed source.&lt;/p&gt;

&lt;p&gt;It's clear from the smartphone graph that the majority of users don't use a smartphone (which I have to say surprised me). I should point out here that this question in the survey was optional, although mostly it was answered by everyone. The next largest proportion was the iPhone, followed closely by Android. With regard to software licensing, the open/closed source split was reasonably close. I categorised the operating systems as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open source: Android, Maemo, Symbian&lt;/li&gt;
&lt;li&gt;Closed source: iOS, Windows Mobile, Palm, RIM&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;As for alternative browsers, Internet Explorer still clearly has a slight lead (again I should point out that Test Pilot is a survey conducted on users who use Firefox most probably as their primary browser and are &quot;savvy&quot; enough to know about, opt into and install Test Pilot, so it really isn't indicative of internet users on a broad scale at all).&lt;/p&gt;

&lt;p&gt;It was slightly more challenging to categorise in browsers in terms of open/closed source. A lot of Chrome is open source (although potions aren't), so I decided that because the majority is, I would include it in that category. Internet Explorer and Safari clearly aren't and Opera is mostly proprietary (although has components that are open source) so all three go into the &quot;closed source&quot; category. I'm bring rather generic here by only having two categories (and not, for example, &quot;Mostly closed source but with some open compents&quot;, etc. because I wanted to get a broad idea of whether open source software licensing was important to Firefox users). The pie chart clearly shows most other browsers being used are closed source.&lt;/p&gt;

&lt;p&gt;So to summarise, it doesn't look like there is a strong relationship between using an open source browser and using other open source software in other areas, which indicates people typically use Firefox for other reasons.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Saving Flash Videos on Mac OS</title>
   <link href="http://ajack.org/blog/saving-flash-videos-on-mac-os"/>
   <updated>2010-12-04T00:00:00+00:00</updated>
   <id>http://ajack.org/blog/saving-flash-videos-on-mac-os</id>
   <content type="html">&lt;p&gt;I recently bought a Mac and realised that saving a Flash video that's buffered in the browser is a bit more difficult than it is on my Ubuntu machine. Sometimes I like to watch a Flash video when I'm somewhere without net access so I use this technique reasonably often. Under Ubuntu, the FLV is nicely kept in /tmp and copying it to a different location for watching later is as easy as firing up Nautilus, browsing to /tmp and copying the file. (The file is removed when you close the relevant browser window). In Mac OSX it's buried somewhere under /private and is a bit of a pain to find manually. So I wrote this script to look through /private for flash files (actually only files that start with &quot;Flash&quot;), show them in a list with their file sizes and provide an easy method of copying them so they don't get removed when the browser window is closed. Note, ALL flash files will be listed, including small flash adverts, etc., which you probably don't want. This is why the filesize is listed – if it's a video it'll probably be a few megabytes (or more), as opposed to an advert which will typically be a few Kb.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get the script &lt;a href=&quot;http://ajack.org/code/flash_getter.sh&quot; title=&quot;Get the script&quot;&gt;here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You'll need to change line 7 to an existing directory you want the files to be copied to. Use the script how you want; a suggested method is below:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; /dir/of/script
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;chmod +x flash_getter.sh
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;sudo mv flash_getter.sh /usr/bin/flash_getter
&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;flash_getter
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;



</content>
 </entry>
 
 <entry>
   <title>Hospital Records podcasting with Python</title>
   <link href="http://ajack.org/blog/hospital-records-podcasting-with-python"/>
   <updated>2010-10-23T00:00:00+01:00</updated>
   <id>http://ajack.org/blog/hospital-records-podcasting-with-python</id>
   <content type="html">&lt;p&gt;I've recently started listening to the &lt;a href=&quot;http://www.hospitalrecords.com/broadcast/&quot; title=&quot;Hospital Records podcast&quot;&gt;Hospital Records podcast&lt;/a&gt; while at work when I can't think of anything to listen to on Spotify. Since I have no music on my work computer, and therefore no proper media player, I lack the ability to use the podcasting service properly and so I wrote a small Python script to do it for me.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;./hospitalrecords.py --list
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Shows a list of the recent podcasts in reverse chronological order. The numbers printed on each line are identifiers for each podcast.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;./hospitalrecords.py --info 2
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Show the date and tracklisting for the second podcast in the list.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;./hospitalrecords.py --get 2
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;


&lt;p&gt;Downloads the second podcast in the list. The mp3 will be saved in the current working directory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get the script &lt;a href=&quot;http://ajack.org/code/hospitalrecords.py&quot; title=&quot;Get the script&quot;&gt;here&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
</content>
 </entry>
 
 
</feed>