get unstuck, in time

29 June 2009

Locatable and iPhone 3.0 issues

Several people have reported that Locatable -- I think Relocatable, actually -- is not working on iPhone OS 3.0. I haven't had a chance to debug yet but consider this an open thread to complain and/or troubleshoot.
Note that Apple has now built the Geolocation API into the Mobile Safari browser in 3.0 using the standard navigator.geolocation object. Looks like Locatable was just ahead of its time!

Labels: , , ,

16 February 2009

JSF and default form actions

For a major project I'm working on we're using JavaServer Faces.  It has its attractions but it's missing something of the polish I'd expect (they're feverishly working on getting 2.0 out the door, which aims to provide a lot more functionality, particularly for Ajax processing).
One of the stranger side effects of the processing structure of JSF is that all forms post back to the same page.  This makes sense when you consider that the server must perform validation and handle state transitions, and only then can decide to send a new (next) page as a response to a given action.  However, this means that if your form gets submitted without an action button or link being specifically clicked, you won't go anywhere -- even if, as is often the case, there's only one logical action from a form (such as a login form, where the action is, well, to log in).
There are a number of canned solutions for this including custom tags such as the one provided by j4j, but it turns out it's very easy to roll one's own solution.
All you need to know is the ID of the enclosing form, and you simply duplicate the default action by using a non-renderable button and a hidden input field that references it.  This tricks the JSF mechanism into thinking the button has been clicked.
Here's a simplification of our login form using this approach:
<h:form id="loginForm">
<%-- Invisible button --%>
<h:commandButton id="hiddenSubmit" style="display:none" action="#{loginBean.doLogin}" />
<%-- Hidden input to make JSF think the button was clicked --%>
<input type="hidden" name="loginForm:hiddenSubmit" value="" />

<p>Username: <h:inputText id="email" value="#{}" maxlength="255" /></p>
<p>Password: <h:inputSecret id="password" value="#{loginBean.password}" redisplay="false" maxlength="255" /></p>

<%-- Visible button --%>
<h:commandButton value="Log in" action="#{loginBean.doLogin}" />

Labels: , ,

23 December 2008

Turf Bombing on your iPhone

The creator of Turf Bombing emailed to let me know this creative web application now supports iPhones with Locatable installed.  This is a great concept that blends real locations with a virtual game that can be played on both laptops and mobiles.  (And you'll probably have an advantage playing on an iPhone with GPS, as WiFi-based locations are often far less accurate.)
Here's a brief description of the concept:
Turf Bombing is a location-based turf battle game which rewards and encourages traveling and learning about different neighborhoods.  Gangs are assigned by the zip code of your home address. The goal of each gang is to gain as much territory as possible.  Territories are acquired as players plant time bombs at different locations in physical space. If the bomb is not diffused by a local gang member in time, the bomb will explode and the territory will be turned over to the gang that planted the bomb. 

Labels: ,

FireEagle + Relocatable

Last month I was fortunate enough to see a presentation at Google headquarters UK from Yahoo!'s FireEagle team, part of the inaugural location-based developer meetup session.  (That's right, not only did Google let Yahoo!s in the building, they even gave them food and drink -- of course, we all had to sign an NDA to get into the meeting room, presumably so we wouldn't wander about jotting down random scrawlings on people's whiteboards).  As you might know, FireEagle is a permission-based location storage service.  It's sort of like a depot where you can save your most recent location, and allow other (FireEagle-enabled) web sites and services to access it.  They are apparently close to launching a Facebook application, for example, that lets you locate anyone in your friends list who has a FireEagle account.
There are several FireEagle-related apps in the AppStore but they also suffer from the Apple restriction of not being able to run in the background, a condition that can only be avoided on a jailbroken phone.  This is exactly the scenario that got me to write the Relocatable application in the first place, and sadly, it's not one that is likely to be resolved soon.
For those of you who are interested in always-on updates to FireEagle via your iPhone, Robbie over at has a recipe for you.  He goes through the full process, including jailbreaking, installing Locatable/Relocatable, and setting up some python scripts to send your location data to FireEagle automatically.  Good stuff!
Speaking of FireEagle, I'd love to see a web-only solution also, using the W3C API and Locatable.  This would be more of an on-demand app, e.g. a bookmark for iPhone Safari that when loaded would save your current location.  Any takers?  Let me know and I'll put a link up here.

Labels: , , ,

22 September 2008

Schema migration with Safari's Javascript Database

Locatable relies on Safari's SQLite-based Javascript database implementation for its client-side data storage. As anyone who has worked with Gears or similar technologies can attest, this is pretty slick stuff. The only thing that's been hard for me to get used to is the callback/closure paradigm for dealing with asynchronous query results (really? they couldn't make a synchronous method for selects?) Coming from a more linear JDBC (and before that, though it pains me to say it, ODBC... and before that, Oracle Pro*C... the list goes on...) aesthetic, I have to say the code ends up looking a bit pasta-ish. But it works. What Safari has not yet provided, though, is any semantics around schema migration. It's easy to create and drop tables from code, and to add (but not delete) columns from existing tables (subject to the usual constraint checking). The openDatabase command lets you specify a version number, but it's not particularly useful; its only impact is to throw an exception if you try to open a database while specifying a different version than then one it was created with. Which means it's down to application code to handle upgrades that require schema modifications. One way to do this would be to have a table with a row that specifically tracks the version number or code. I'm guessing this is how Gearshift works for Google Gears. When starting up, you could query this; if it doesn't exist, you're running for the first time, otherwise you could apply the right schema mods. But that's too much work (for someone as lazy as me). Fortunately, JSDB does include transactions, and of course a transaction will bomb out if it gets an error. So if all you want to do is make sure you get the user upgraded to the latest schema, an easier way looks something like this: in your initialization function:
var db = openDatabase('mydb', '1.0', 'mydb', 65536);

db.transaction(function (transaction) {
      "CREATE TABLE version001 (id integer primary key)",
    // Do table creation required for version 001
   transaction.executeSql("CREATE TABLE mytable ...", []);

db.transaction(function (transaction) {
      "CREATE TABLE version002 (id integer primary key)",
    // Do schema migration to version 002
    transaction.executeSql("ALTER TABLE mytable ..."), []);
And so on. When this runs, the create table statements for dummy tables version001 and version002 act like assertions: the transaction fails (and the rest of the SQL statements within it are skipped) if the table already exists. (It's not strictly necessary to have the version001 table in this example, as the create table line for "mytable" has the same effect; it's just there for clarity). If a user has a version001 table, the code skips to the version002 piece. You can put inserts, updates, and so on in there, none of which will have any effect unless it's the first run through (be careful of other side effects, though; Javascript variables have no transaction boundaries). Doubtless there are other (and perhaps better) ways of doing this; this one certainly has the time drawback of testing against each version dummy table, which could get slow if you have a lot of versions to check through. If you only have a few, it's probably just as fast as (and a lot less complicated than) asynchronously handling a callback that tells you what version number you're at, and going from there (in which case you'd need all the same code, just broken into a bunch of different functions). (And yes, this does mean that altitude, horizontal accuracy and vertical accuracy will be part of the schema in the next release of Locatable!)

Labels: , ,

01 September 2008

Locatable roadmap and feature planning

I thought I'd give an update on where I'm going with Locatable and I'd love to hear feedback or suggestions for new functionality. I've just tested a better technique for saving data to the client-side database from the Locatable application which means that the app itself should not need any network connectivity. This is good news as there's a risk of settings becoming unsynchronized between the app and the database the way it's working right now (e.g. if the connection fails). This means rewriting all the preferences-saving and preferences-loading code and won't have any visible effect on the UI. Preferences anyway are about to get more complex. Now that Locatable is tracking per-site preferences (so you can choose to only be prompted once or twice per site to share location), there needs to be a UI to see what sites are currently in the list and manage their individual settings. I'm thinking of it a lot like the cookie manager in Firefox — you should be able to blacklist and whitelist individual sites that you visit, as well as alter their settings individually. So that's the task for Locatable 0.4. The other item on the TODO list requires a schema upgrade, which is why I've been procrastinating on it. It would be good to store the horizontal accuracy of the reading so this can be shared (via the W3C API and redirector). It would be nice to have altitude and vertical accuracy as well, though I'm not sure if these even work (certainly not on an iPod Touch!). Once those are in there, the plan is to submit to the AppStore. If accepted, the only difference between the jailbroken version and the AppStore one will be the inclusion of Relocatable, which of course won't work. (I won't be discontinuing development on it, but it may become its own package in Cydia.) In the meantime I'm open to suggestions on other functionality that should be included. Primarily what I've been hearing about is people using Relocatable to do their own lojack-type apps. I'd really like to get some feedback on using Locatable on your web sites to integrate positioning data, do maps mash-ups, and so on. Private feedback is fine, public is even better (and I'll be happy to put links on the Featured Sites page).

Labels: , , , ,

29 August 2008

The plunge

... I've taken it. Over the next 18 months, I will pay O2 UK £664 (plus the £159 I laid down at the Apple Store today) for the privilege of owning an iPhone 3G. When I look at it that way it seems, um, a lot, but as I can remember the time when I was paying £15/mo. for a bundle of 5 megabytes of data access (that was 2002, on Orange, if memory serves), I guess I can see the bright side of an unlimited data plan. As you might expect, the first step before syncing music and photos was Pwnage. Can't wait to try some of the iPhone-specific apps out there, particularly Saurik's new video recorder. Oh, and to see how Locatable works in the field using actual GPS. One annoyance: I couldn't get PwnageTool (the latest, to add in a custom boot image. I wanted to get the classic multicolor Apple image on there, but every time I went to add it, the tool crashed. Oh well — next upgrade.

Labels: ,

Copyright (C) 2001-2008