Tom Insam

Egyptian calendar, dating system established several thousand years before the common era
[It] consisted of 365 days organized into 12 months of 30 days each [..] There was apparently no attempt to introduce a leap-year day to compensate for the slippage of one day every four years; as a result, the civil calendar slowly rotated through the seasons, making a complete cycle through the solar calendar after 1,460 years.
The Egyptian civil calendar was altered by Julius Caesar about 46 BCE with the addition of a leap-year day occurring once every four years.

Egyptian calendar, Encyclopædia Britannica

I’m building things with a combination of the new Room ORM and Data Binding, and I find that when Room has compile errors they express as hundreds of lines of Error:(6, 31) error: cannot find symbol class BR and related things, and no actual real error.

Turns out, javac will print a maximum of 100 compilation errors, and when dealing with preprocessors you often want the last error message, not the first. Put this in your top-level build.gradle file and become happy:

allprojects {
    gradle.projectsEvaluated {
        tasks.withType(JavaCompile) {
            options.compilerArgs << "-Xmaxerrs" << "4000"
            options.compilerArgs << "-Xmaxwarns" << "4000"

25 Mar 2017

Code Points

A commonly touted disadvantage of UTF-8 is that string indexing is O(n). Because code points take up a variable number of bytes, you won’t know where the 5th codepoint is until you scan the string and look for it. UTF-32 doesn’t have this problem; it’s always 4 * index bytes away.

The problem here is that indexing by code point shouldn’t be an operation you ever need!


Unicode itself gives the term “character” multiple incompatible meanings, and as far as I know doesn’t use the term in any normative text.

– Let’s Stop Ascribing Meaning to Code Points

26 Jan 2017

Electric Objects EO2

I just bought an Electric objects EO2. First impressions:

  • It's exactly as pretty as I was hoping for. Which is to say, very pretty.
  • It's heavier than I was expecting. I'm renting, and I'm not quite ready right now to put the holes in the wall that mounting it would require (though the instructions and mounting kit are themselves lovely). Someone thought about this, and the frame has lovely little grippy feet on the bottom so it props up nicely against the wall and doesn't feel unsteady at all.
  • Auto-brightness is off by default. The lowest brightness setting still feels a little high, but that might just be my perception of it because it's so new. Update 4 days later: Nope, brightness is perfect. It never feels like it's glowing too much, and the lowest setting when the room lights are out is very low indeed.
  • Anything animated that's not really subtle drives me crazy. I've never been able to handle having a moving screen in my peripheral vision, and this absolutely counts. But tiny subtle animations are just lovely. Before it arrived I'd assumed that I would almost resent using what is essentially a computer to display still jpegs, so I'd stockpiled nice animations, but in practice it displays those jpegs so well that I'm just as happy with still images.
  • The iOS app for photo and playlist management is... functional. I imagine that I won't be using it a lot as I settle into the things I like, but initial setup is a drag of stuttering scrolling and loading screens.

And here are the nerdy developer things I wanted to know before I bought it:

  • It's an Android device, running some AOSP-like fork of 4.4.2. No Google Play Services, obviously.
  • There's a micro-USB socket on the back of it, and ADB, etc, work just fine. "adb shell" gets you a root shell.
  • You can side-load anything you feel like.

"That’s four different ways to talk to Google on this phone, not counting apps like Maps and Gmail. And each one has a slightly different interface and provides slightly different results"


I quoted the above passage, though, because it suggests some rough edges regarding what is supposed to be the Pixel’s standout feature

— John Gruber

I don't disagree . But consistency isn't everything. To free-associate for 5 minutes on the subject of Force Touch (surely a stand-out feature, and moreover one that's had 12 months to shake out the edge cases):

  • The weather app springboard icon force touch action has both a widget and the actions are nouns - quick links to recent cities. The clock app force touch action has no widget, and the actions are verbs (create new alarm, for instance).
  • The core "telephone" apps have different combinations of actions and widgets - Messages (no widget, "new message" and a list of recent contacts as actions), FaceTime (no Force Touch actions at all, but a widget listing recent contacts),  Phone (a widget listing recent contacts and actions, including contact search), and Contacts (a widget with recent contacts, and a create contact action, but no search this time).
  • Some built-in Apple apps have no force-touch menu at all (eg Videos, Find iPhone,
  • The "leaves" in the iPhone safari tab switcher have fake parallax as you tilt the phone, and respond to force-touch by flexing apart. You can long-press to drag them around. The "leaves" in the system task switcher do neither of these things.
  • Springboard icon force-touch menus grew a "share app" action in iOS 10. Unless you get at that menu from a spotlight search, in which case they don't have it any more.

While I was looking at the weather and clock apps anyway,

  • The cities in the iOS weather app sync with their Mac equivalent (but the Celsius / Fahrenheit setting doesn't). The cities in the world clock app do not.
  • To rearrange world clock rows you tap "Edit" and use the drag handles that appear. To rearrange weather rows you long press (not force touch, that does something different) and drag up and down. But both apps have swipe to delete.

Having said all that, Force Touch is amazing and you will have to pry it from my cold dead fingers. I just don't think universal consistency on a platform is achievable in a world where you sill also have to actually ship things.


31 May 2016


So while it's nice that I'm able to host my own email, that's also the reason why my email isn't end to end encrypted, and probably never will be. By contrast, WhatsApp was able to introduce end to end encryption to over a billion users with a single software update.

The ecosystem is moving

In Intent Resolving in Android M, Said Tahsin Dane points out a change in Android Marshmallow to the intent querying mechanism. Specifically, when using queryIntentActivities,

If there is a domain verified application, [queryIntentActivities] does not return anything else. MATCH_ALL flag removes some system filters but only if there is no verified application.

This makes a lot of sense if I’m an application wanting to open a link to some other app and I want the system to just Do The Right Thing. But it led to problems with one aspect of the Eventbrite app.

Sometimes I want to be able to open the event the user is currently looking at in a web browser. I was doing this by constructing the URL to the web version, asking the system for everything that could handle it, then removing the Eventbrite app from the list and presenting the remaining intents (presumably the user’s web browser(s)) in a chooser. But when I added validated App Links, the list of “remaining intents” was empty - I had only been offered myself in list of possible handlers for the URL.

I’m working around this by building the intents list in 2 stages. First, I ask for a list of apps that can handle a “normal” URL. Then when I build the Intent list I’ll substitute the “real” URL:

// This URI is handled by the Android M "App Links" system, and if I
// try to open it the only intent the system will offer me is the
// Eventbrite app.
Uri realUri = Uri.parse("");

// We'll ask the system to open a generic URL, rather than the deep-link
// capable one we actually want.
Uri fakeUri = Uri.parse("");

Intent browserIntent = new Intent(Intent.ACTION_VIEW, fakeUri);
PackageManager pm = getActivity().getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(browserIntent, 0);

// Loop through everything the system gives us, and remove the current
// app (the whole point here is to open the link in something else).
final List<Intent> targetIntents = new ArrayList<>(activities.size());
for (ResolveInfo currentInfo : activities) {
    String packageName = currentInfo.activityInfo.packageName;
    if (!packageName.contains("com.eventbrite")) {
        // Build an intent pointing to the found package, but
        // this intent will contain the _real_ url.
        Intent intent = new Intent(Intent.ACTION_VIEW, realUri);

// Now present the user with the list of apps we have found (this chooser
// is smart enough to just open a single option directly, so we don't need
// to handle that case).
Intent chooserIntent = Intent.createChooser(targetIntents.remove(0), "");
targetIntents.toArray(new Parcelable[targetIntents.size()]));

Now I can offer to open the current view in the user’s web browser, but still retain the Eventbrite app as the default handler for Eventbrite events when followed from elsewhere.

09 Apr 2015

[]WATCH predictions

I read some reviews of the watch. I haven't used one, but I can tell you most of the same things the reviews do:

For the first week or so you'll be playing with it constantly and there will be lots of people saying "the battery life isn't good enough", because it's not designed to be used constantly.

You'll get lots of notifications and you'll realize that they're really annoying and intrusive. Then you'll put the effort in to manage those notifications and the problem will go away, you'll only be told about important things.

Then the novelty will wear off and it'll just be a thing you glance at but you'll forget about it a lot but it's useful and you'll be happy you have it.

Then you'll get to the actual useful phase where it really does fulfill that "I don't look at my phone" thing and you'll find that not only does the battery last long enough* but your phone battery lasts a lot longer now as well, because you're not looking at it as much - calendar notifications no longer mean that you're holding an inherently distracting device that you're inclined to keep fiddling with.

Then you'll stop using it, and think "this is actually annoying to wear", and take it off.

Then you'll realize that actually you use it all the time and had stopped noticing and now it's incredibly irritating to have to pick the phone up all the time, and you'll miss messages because your phone is face-down on the desk or something, so you put it back on.


Forgive me while I'm That Android Guy for a moment here. But I know all this because we did this last year. I'm genuinely interested to see if the extra capabilities of []WATCH are really meaningful, but it'll be hard - ecosystem lock-in means that almost no-one will be able to have worn both. Maybe the touch-drawing or the Haptic Wossname or whatever will be a meaningful improvement over Android Wear. Maybe not. I don't know anyone who'll be able to tell me, and I'm bored of reading reviews that tell me all the same things I learned last year about smart watches.

Oh. And it's really annoying in restaurants and cinemas because YOU HAVE A LIGHTBULB STRAPPED TO YOUR WRIST. Google solved that one pretty fast - there's a 'theatre mode' now that locks the backlight off unless you explicitly tap to wake, but wow that was annoying while it lasted.

* battery life of >20 hours and <1 week is not interesting because everything in that range means "charge nightly". I have a Pebble Time coming. I'm wondering if the slightly >1 week battery it promises will make a meaningful difference.