Thursday, January 23, 2014

UI design

I have an interesting UI design issue. In a project in which we develop an Android app, we were discussing the behavior of the back button.

The app has tabs in the actionbar. The behavior of the back button currently is to leave the app, independent of the tab you have pressed. My idea on the back button is that it should take you back to the home tab, then when you press it again, you leave the app. If in one of the tabs you have pressed a button or a list item which brings you deeper into the app, the back behavior should be as follows: first press brings you to the default page of the tab you have selected, next press brings you to the default page in the home tab (or whichever tab is selected when you enter the app), third press makes you leave the app.

In another project, we had to different landing pages, depending on the preferences of the user. I made it so that the back button brings you back to the landing page that is in your preferences, or the landing page that you have selected when you entered the app. I feel that this is the most intuitive behavior of the back button, even if, as a developer said, the button is not stricly bringing you "back".

Wednesday, January 22, 2014

Rooting an encrypted Android device

I wanted to root my Nexus 7, so I installed the right image and zip. But then the device didn't work any more. I think it's because the device was encrypted, and somehow after rebooting, the thing got stuck. I managed to get the right factory images from Google (I didn't backup the system, which you should always do), my defice is "flo" which is "razor". After I got the device back to a factory installation, rooting the device with clockworkmod was easy. Now I'll encrypt it again.

Wednesday, December 18, 2013

How to make ormlite and robolectric work together.
I use Roboguice also, this is my RoboInjectedTestRunner:

public class RoboInjectedTestRunner extends RobolectricTestRunner {

 public RoboInjectedTestRunner(Class testClass)
   throws InitializationError {

 protected Class getTestLifecycleClass() {
  return TestLifeCycleWithInjection.class;

 public static class TestLifeCycleWithInjection extends DefaultTestLifecycle {

  public void prepareTest(Object test) {
   Application application = Robolectric.application;

   AbstractModule eftelingModule = new EftelingModule();
   AbstractModule testModule = new TestModule();

     RoboGuice.newDefaultRoboModule(application), eftelingModule, testModule);



If you don't use Roboguice, you can use the default RobolectricTestRunner instead.
This is the annotations I have for my test classes:
@Config( shadows = {ShadowCaseSensitiveSQLiteCursor.class})
public class APITest {

This is the ShadowCaseSensitiveSQLiteCursor: (it's from here: so please give that post a credit)
 * Simulates an Android Cursor object, by wrapping a JDBC ResultSet.
@Implements(value = SQLiteCursor.class, inheritImplementationMethods = true)
public class ShadowCaseSensitiveSQLiteCursor extends ShadowSQLiteCursor {
  private ResultSet resultSet;

  public void __constructor__(SQLiteCursorDriver driver, String editTable, SQLiteQuery query) {

   * Stores the column names so they are retrievable after the resultSet has closed
  private void cacheColumnNames(ResultSet rs) {
    try {
      ResultSetMetaData metaData = rs.getMetaData();
      int columnCount = metaData.getColumnCount();
      columnNameArray = new String[columnCount];
      for (int columnIndex = 1; columnIndex <= columnCount; columnIndex++) {
        String cName = metaData.getColumnName(columnIndex);
        this.columnNames.put(cName, columnIndex - 1);
        this.columnNameArray[columnIndex - 1] = cName;
    } catch (SQLException e) {
      throw new RuntimeException("SQL exception in cacheColumnNames", e);

  private Integer getColIndex(String columnName) {
    if (columnName == null) {
      return -1;

    Integer i = this.columnNames.get(columnName.toLowerCase());
    if (i == null) return -1;
    return i;

  public int getColumnIndex(String columnName) {
    return getColIndex(columnName);

  public int getColumnIndexOrThrow(String columnName) {
    Integer columnIndex = getColIndex(columnName);
    if (columnIndex == -1) {
      throw new IllegalArgumentException("Column index does not exist");
    return columnIndex;

  public void checkPosition() {
    if (-1 == currentRowNumber || getCount() == currentRowNumber) {
      throw new IndexOutOfBoundsException(currentRowNumber + " " + getCount());

  public void close() {
    if (resultSet == null) {

    try {
      resultSet = null;
      rows = null;
      currentRow = null;
    } catch (SQLException e) {
      throw new RuntimeException("SQL exception in close", e);

  public boolean isClosed() {
    return (resultSet == null);

  private Map fillRowValues(ResultSet rs) throws SQLException {
    Map row = new HashMap();
    for (String s : getColumnNames()) {
      row.put(s, rs.getObject(s));
    return row;

  private void fillRows(String sql, Connection connection) throws SQLException {
    //ResultSets in SQLite\Android are only TYPE_FORWARD_ONLY. Android caches results in the WindowedCursor to allow moveToPrevious() to function.
    //Robolectric will have to cache the results too. In the rows map.
    Statement statement = connection.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY);
    ResultSet rs = statement.executeQuery(sql);
    int count = 0;
    if ( {
      do {
        Map row = fillRowValues(rs);
        rows.put(count, row);
      } while (;
    } else {

    rowCount = count;


  public void setResultSet(ResultSet result, String sql) {
    this.resultSet = result;
    rowCount = 0;

    //Cache all rows.  Caching rows should be thought of as a simple replacement for ShadowCursorWindow
    if (resultSet != null) {
      try {
        fillRows(sql, result.getStatement().getConnection());
      } catch (SQLException e) {
        throw new RuntimeException("SQL exception in setResultSet", e);

Sunday, December 08, 2013

My dad moved from Windows XP to Windows 8. Disaster. One thing Windows 8 doesn't seem to support is getting your old email (Outlook Express, from POP3) into your new mail program. Apparently, Windows users don't keep their email?

What I did to transfer his mail is the following.
I made a copy of the OutlookExpress mail file and put it on my computer. Evolution allows me to import it into a new mail box. Then I created an account on my dad's IMAP mail, and copied the mail from the import mailbox to his Inbox. Simple as that. Why can't Microsoft think of a way to keep your old email?

Saturday, November 02, 2013

The art of bad design

In the course of my life, I have used some ten different vacuum cleaners, if not more. We all use vacuum cleaners, and we all know what the common issues with vacuum cleaners are.
  1. The power cord.
    The cord of a vacuum cleaner tends to get tangled when you use it, and because it's longish, it gets tangled when you store the machine in a closet. That's why modern vacuum cleaners have a system that retracts the cord when you push a button or when you jerk the cord. This works fine on all vacuum cleaners. That is, it works fine when it's new. But lets consider your average three year old vacuum cleaner. My Dyson currently is two years old, and when I store it, the cord sticks out by about a foot. And this is ok, because in all other cleaners, it was worse. The cord retraction was tested with new cleaners. Apparently they don't test older machines.
  2. The wheels.
    A vacuum cleaner has two big wheels, and a small caster. This causes the device to follow your movements and not topple. The caster hops over the cord most of the time, it doesn't get stuck. As long as it's new. After a few years, or even after six months, the caster wears out, and it does get stuck when it hits the power cord. I've had a vacuum cleaner with a fine looking caster, made out of plastic, it looked like a half sphere with a little wheel sticking out. It stopped moving after half a year, and when I took it apart, every idiot could see that it couldn't have lasted long. It was badly designed and badly made. I replaced it with the cheapest and simplest caster from the hardware store, which outlasted the rest of the vacuum cleaner. Why didn't the manufacturer put in that caster? Is it because it would have added one euro to the price?
  3. The hose.
    When you walk around pulling the vacuum cleaner, you know that the device has a tendency of falling backwards when you pull it in the wrong direction. Which you do because you don't pay attention. Manufacturers come up with all kinds of solutions for this, and when you test your new vacuum cleaner, you're happy because it works perfectly well. But the connections between the hose and the device wear out quickly, or they get stuck because dust is collecting inside, so my two year old Dyson does topple when I make a wrong move. Which is stupid because if Mr Dyson would have spent an hour a week using an old vacuum cleaner, he'd know what the issues are and he could have started looking for proper solutions.
  4. The brush.
    I have cats. Cats drop mountains of hair in your home. Which you have to vacuum out. My vacuum cleaner, like all of them, has a brush with hairs on the edge and a whole that sucks in the middle. The cat hair gets sucked towards the brush, and it gets stuck between the floor and the brush, outside the brush, so it can't be sucked up into the machine. Every two minutes, I have to pause and remove the cat's hair from the brush. Mr Dyson apparently doesn't have cats. Or he would have made the brush inside out: it would have brushes that it rests on in the middle, and it would be sucking at the edges.
If I can think of that, why can't the average designer of vacuum cleaners? One thing I know. Vacuum cleaner designers don't do the vacuum cleaning at their place.

The art of bad design

I have a wastebin in my kitchen. It's a simple bin, mostly thin sheet metal, plastic inner bucket. The lid opens by a pedal at the bottom, so you don't have to touch it with your hands. It was rather cheap, though one of the most expensive ones the store had on display.
Now, someone has spent a couple of days designing the thing. They created a few prototypes, tested them, created some production models, tested them, then set off to mass produce them. Also, the designer probably designed wastebins of similar type before, and they obviously use one on a daily basis. You'd expect the bin to be perfect. But it's not.

First, the hinge that holds the lid protrudes a millimeter. When you lift the inner bucket from the bin, that millimeter is enough to make the bucket get stuck, you can't lift it out without wiggling and jerking it. Which, if the bin is full, causes content to fall out. There's no reason for the hinge to protrude. At the same cost, it could have been made so that it doesn't stick out. But they didn't.
The second issue is when you want to get the plastic bag out of the bucket. Most people use plastic bags in the wastebin, so they don't have to thoroughly clean the bin every time they empty it. The handle that you use to lift the bucket, is one millimeter smaller than the bucket itself. It sticks out to the inside. Which means that when you lift the bag out, the handle gets pulled up and you can't lift the bag. Again you have to use both hands and wiggle and jerk, causing garbage to spread over your kitchen floor. There's no reason why this handle should stick out to the inside. It's just a designer being thoughtless.

I'm surprised how a person who has experience designing wastebins and who uses one, and has used many in their life, can make such stupid and unnecessary mistakes. My theory is that they are not the person who does the kitchen work too often in their household, or they wouldn't have made these mistakes.

Thursday, September 19, 2013

The art of terrible design

I am not a chef. Not by profession, not by hobby. I don't like to cook, but I do like good food, so every day I make a proper dinner from fresh ingredients. I guess I am a "gourmet cook".

I have always used a natural gas stove, with four burners. That's the best, the gas has the right high temperature and it's easy and fast to adjust. Like, when you make hot chocolate, you heat the milk quickly, then you have half a second to switch if of when it boils.

After my last move, I got a Bosch electric plate. It's induction based, so it's hot, and it's quick to adjust. It has four stations, which most of the days is just enough for me. However, it has one major flaw.
The designer decided that the plate should be easy to clean, hence it has no protruding knobs, it has touch keys. Or rather, you don't just touch them, you have to press them, "+" for higher, "-" for lower. The buttons go from 0 to 9 in half steps, you push it 17 times for full heat. The designer also thought that a chef wants as little knobs or pushbuttons on the plate as possible. So, instead of having a plus and a minus button for each station, it has one plus and one minus, and a selection button with a light that indicates which station is currently "active". Now, imagine the little pan with milk for my hot chocolate. I put it on 9, I wait for it to boil. When it does, I push the station selector twice to select the milk pan, then I push the minus button 17 times to switch it off. Then I pour new milk in the pan and I clean the plate, because the boiling milk went all over the plate. Of course, after a while you find out there are shortcuts, instead of pressing 17 times, there's a way to switch it of in just a few steps. But including the selector, it's always five or six. And you shouldn't accidentally push the wrong button, or one button once too many, because that increases the total nummber of actions, and you do press the wrong button because you want to stop the milk from boiling over and the buttons are barely visible on the plate. The fastest way to switch off the milk pan is to switch off the plate alltogether. Then you have to switch it back on and switch back on the other stations.

My question is: why does a very expensive stove have such a lousy user interface? Why can't it just have four turning knobs? The answer is simple. The engineers and designers of the stove are not chefs. Or if they are, they have never used this stove, because if they had, they would have changed the user interface.
I propose the following add-on to my stove: a remote control with four turning knobs that let you adjust the stations fast, while maintaining the option of easy cleaning of the plate.

Tuesday, July 23, 2013

I was at a Demo conference in 2001, in Phoenix, AZ. Demo2001. I was selected to maybe do a pitch, which they called "the hot seat". Some fifty startup entrepreneurs were located in the front of the room, and every half hour they'd call two names, and when your name came up, spotlights were pointed at you, people with huge cameras would rush towards you and film you from two feet distance, just to make it scary, and while your face was on a big screen in the front, you got two minutes for a pitch. Now, you weren't sure your name would come up. The people who weren't called, were nervous throughout the conference, because they didn't announce when they'd call someone, it just came up suddenly. Nerve wracking, because the room was full with investors and other important people, I guess there were 1000 people in the room.
My name came up second, right after the key note. I got to relax and listen to the presentations, while most of my fellow hot seat entrepreneurs were still waiting for their name. It's always good to have your pitch or presentation right at the start. I was second, which is even better than first.
On the last day of the conference, I was ill. High fever, maybe because of the heat, I stayed in bed. At the end of the day I talked to one of the programmers who'd manned our booth, and he said "there was a lady asking for you today". I asked if he caught the name, and he said "yeah, her name was Ann Winblad". I never shout at people, but this time I did. "then why didn't you call for me? Why didn't you run to my room, bang on the door, and get me down there in the booth?" and some words I won't repeat here. The poor guy didn't know who Ann Winblad is. I sent her an email, called her office, to no avail.

The company didn't make it, in the end. Me talking to Ms Winblad might have made the difference.

Monday, July 08, 2013

off line?

My web site has been off line for a few days, due to a misconfiguration of the firewall that went unnoticed.

Saturday, June 15, 2013

Wednesday, November 07, 2012


On November 22nd, I will speak at DroidCon NL. The subject will be RoboGuice and Android development.

Wednesday, October 31, 2012

Friday, September 28, 2012

Friday, September 14, 2012

Galaxy Nexus

I replaced the Galaxy Nexus that I lost, and I updated it to Yakju so It will have the latest Android version, like so.