Design Blog

Notes on design in Android and how I create beautiful software

Upsell is not a town in Sweden

It’s the time of year when sons, daughters, and fathers of infants panic, and mothers too wait in uneasy anticipation of getting a breakfast tray tipped all over them in the morning. Florists and chocolatiers rub their hands together in glee, but even on Mother’s Day, stock doesn’t sell itself. So today we’ll be taking a critical look at an online shopping workflow, with a seasonal example.

Launch animations

One of the driving principles behind the design of Shadowburst apps is that every computer should look as attractive as computers do in films. One of the biggest things Android does to get the ‘Movie OS’ look is to animate transitions between screens, whether that’s swiping between tabs, animated scrolling, or sliding menus. Transitions aren’t just there to be pretty. Just like in the movies themselves, a smooth transition is less visually jarring than a simple cut, and it can help the user to see the relationship between the old and new screens. This article is about the transition between activities.

In early Android™ versions, the activity transition was simple. A new activity would slide in from the right, with the previous activity sliding out to the left. Pressing back would finish the activity by sliding it out to the right, with the previous activity reclaiming the foreground by sliding in from the left. Android had no support for right-to-left locales then, but today you can put the inverted forms of the animations in an anim-rtl directory to use them in right-to-left locales.

It was simple, but it helped to set up the forward/back relationship in the user’s mind. Mobile GPUs were a lot smaller then, and users tended to turn the animation off because it was often jerky (or “janky”, in Android developers’ parlance). Nowadays, with much faster GPUs and a better animation framework, activity transitions are invariably smooth, but this has caused another change.

In more recent Android versions, there is a new animation. New activities grow from the centre of the screen while becoming more opaque. Using back to finish an activity makes it go away by the inverse route: it fades out and shrinks towards the centre. This new animation reinforces the idea that the old activity is still present, unchanged, ‘behind’ the new activity, but sacrifices the forwards-backwards association. Perhaps the designers assume that users are used to that idea by now.

This new animation, available from API version 16 (Jelly Bean), has an extra benefit: it gives you the freedom to start the new activity growing from somewhere other than the centre. Android uses this extensively to give better feedback when launching a new activity. For example, when you start an activity from an icon on the home screen or the “All Apps” menu, the icon grows into the activity. When you return to an activity by clicking it in the “Recent Apps” menu, the thumbnail grows and turns into the activity.

The Hat Game uses this feature to give extra menu feedback on devices that support it. One example is the Bluetooth item in the action bar. When you click this, the Bluetooth activity starts, by growing out of the button. Again, the idea of this is not just to add “bling”, but also to better show that the new activity is a response to the user’s button-click. The code to add this is incredibly simple, even including the workaround for older devices. It takes advantage of Java’s late binding of function calls to avoid having to use reflection. The code below is from the main activity.

@SuppressLint("NewApi")
private void startActivity(Intent i, View source) {
    if (source != null) {
        try {
            Bundle opts = ActivityOptions.makeScaleUpAnimation(
                source,
                0, 0,
                source.getWidth(), source.getHeight()).toBundle();
            startActivity(i, opts);
        } catch (LinkageError e) {
            Rect r = new Rect();
            source.getGlobalVisibleRect(r);
            i.setSourceBounds(r);
            startActivity(i);
        }
    } else {
        startActivity(i);
    }
}

This function uses the ActivityOptions helper to create the animation options. This class only exists in API version 16 and up. The *minimum* version for this project is 8, but the *target* version is 17, so the package compiles correctly using this later version. The @SuppressLint("NewApi") annotation tells the Android tools not to warn about calling a function newer than the minimum version.

The call isn’t actually linked until it is called at runtime. When it’s called, if the JIT finds the class, the call proceeds and returns just like any other function call, so makeAnimationOptions will return the Bundle necessary for the animation, which is then passed on to startActivity(Intent, Bundle) (which also is only available from API 16). On an older version, the JIT will attempt to link the function call, fail to find the class, and throw an error. The function catches the error and calls the older fallback.

This code plays a little fast-and-loose with the JIT, compared to the alternative of checking Build.VERSION, but it is a little simpler, and has the advantage that you can’t get the check wrong (for instance, by checking for the wrong version number, or omitting a more specific check for a particular feature). Structuring the code this way incurs practically no overhead when the feature is enabled and only the overhead of taking an exception when the feature is unavailable. Either cost is immeasurably small compared to starting an activity.

If you haven’t yet seen this animation, you can download a free trial of The Hat Game from Google Play™. Get it on Google Play

The Back Button

The back button in the Android interface is one of its most distinctive features. People have very clear ideas of what they want it to do: it goes back to the thing they were looking at before. They don’t want to keep the GUI state around, but they also don’t want to lose data. In most ‘productivity’ apps, pressing back from an editor window saves a draft.

On the Samsung Galaxy S 3 I use for my everyday development and testing, the back button is a soft key just below the screen, in the corner of the handset. It’s very easy to press by accident, especially when passing the phone around. Saving the state of the game and offering to restore it when the user comes back to the app was an important feature right from the start.

But sometimes for a game, it’s not enough to be able to restore the state. In my first play test I found people would wave the phone around when miming (in the third round), and this often caused accidental back presses. There’d be a pause while they worked out how to get back into the game (most players weren’t Android users), and it was very disruptive to the game.

It was clear I had to break the user’s expectation, and make the back button not always go back. This is quite common in games, where load times can be long, and state costly to save. It’s especially common for people porting PC games to get a bit lazy, and just make the back button bring up an “Are you sure?” dialog, even from the main menu. But I know that as a user I hate it when apps do that, so I knew I had to do something better.

In The Hat Game, there’s only one situation where accidentally exiting the game is disruptive: in the middle of a turn. The rest of the time, you’re not doing anything time-sensitive, and there’s usually a pause between players anyway. So that’s the only time that back is disabled. And it’s really disabled. A dialog would be almost as disruptive as exiting. Some apps set things up so that pressing back twice in quick succession exits, but I found that to be still too easy to press by accident. In The Hat Game, pressing back doesn’t change anything: it just shows a short, unobtrusive message on the screen (a toast, in Android-speak), telling you to pause the turn first and then press back. Pausing the game is a single screen press, so it’s just as easy as a dialog, or double-tapping back, but much less disruptive and harder to do by accident.

For games, it’s not always easy to fit in with other apps on the platform. Users interact with a game differently to any other kind of software. But in a situation like this, it only takes a little extra effort to fulfil users’ expectations. The reward, if you get it right, is that they don’t notice. Sometimes that seems unfair, but I think it’s worth it.

If you want to see the application of this technique, you can download The Hat Game from Google Play. Get it on Google Play

Hanc marginis exiguitas non caperet

For some years I have had a marvellous idea for a computer game. Each player takes control of a civilisation, and has to guide its scientific and cultural development. Starting from the earliest days with iron tools and the invention of writing, through the development of experimental science, and of philosophy, through to post-modernism and the internet age, and beyond, the player carefully shepherds his race, facing competition from the other races over resources and cultural superiority. As the game proceeds into what to us would be the future, the play area expands to the stars, with each player’s civilisation becoming a vast galactic empire.

The winner is the player whose race is first to prove that they are living inside a computer program.

 

Consumer grade

Goods are often distinguished as “consumer” or “professional”. The two biggest examples I can think of are cameras and sound recording and reproduction equipment. The distinction has traditionally been that consumer-grade goods are cheap, but produce inferior output, and don’t interface well with other components. Professional goods are more expensive, connect to other professional devices, produce brilliant output, and often have more controls the user can adjust.

In software, we have another category: “enterprise-class”. Particularly server products and web apps are given this ill-defined quality. The intent is to define a sort of quality hierarchy: enterprise-class products are the most robust and scalable, then professional-level, then consumer-grade. But consider the following.

Products targeted at consumers aim to be used by many people. They need to be easy enough for the layperson to use. Customers generally hear about them through recommendations from friends, which means the product has to be very good for word of it to spread. Usually the person who uses the product is the same person who chooses which to buy. Consumers and hobbyists are very intolerant of software that runs slow, is unreliable, or doesn’t interoperate. They have little enough information that it’s easy for them to switch products. Security, while not at the forefront of users’ minds, is more vital when your product has a large install base. Consumers generally want free support.

Professional users tend to choose products based on reviews written in inclusivist trade magazines that don’t want to annoy manufacturers. They have expensive computers fast enough to tolerate slow software. They know about what they want to achieve, and can use the software in a sophisticated way, so ease of use is not as important. Because they use the software as part of their full-time work, they are more willing to put in time doing manual tasks that consumers would require automating. They are easier to lock in to one product because they have so much data. They tend to expect a hefty manual, but are willing to buy a book on how to use the product effectively.

The people who choose enterprise products are usually not the same people who have to use or administer them, and the choice is based almost entirely on marketing material and sales patter. The buyers are willing to throw at the product whatever hardware is needed to make it fast enough. In use, the product will be behind a large firewall with a strict access-control policy, and there will probably be a mechanism for ensuring timely security updates. If the system is mission-critical, there will be a failover system, so reliability is less important. Customers expect to have to pay through the nose for service contracts to configure the software, and are willing to hire consultants to make it interoperate. They have lots of data and expect lock-in as a matter of course.

Our conclusion must be that the traditional distinctions are misleading. Far from being a badge of quality, “enterprise-class” is a measure of a product’s shortcomings. Rather, the discriminant of quality must be scalability, not just in the strict sense of how much data you can handle, but the wider sense of what sort of customers you can appeal to. If you can be nice enough for a single user that he’ll recommend you to others, and you can handle the picky administrators employed by enterprises, you must be a well-engineered system.

But ease of use means fewer support contracts. Efficiency means your software is licensed for fewer CPUs. Interoperability makes it harder to sell ancillary software to existing customers. Lack of lock-in makes it easier for competitors to lure away your customers. Free updates make it harder to generate repeat sales. It is, I think, a great shame that the very properties that enhance your product, hurt your business.

Games of skill

The most enduring board games are the ones where adults and children can play together on a level playing field, usually ensured by adding large doses of randomness to make skill affect the outcome less. I’d like to see this taken to its logical extreme with games where the players’ actions can’t at all affect who wins (if there even is a single winner), only how stylish the victory is. The aim is not just to give ‘weaker’ players a chance of winning, but to make people take the outcome less seriously, to make them play for the taking part, not the winning.

But I think the perception of the skill/chance balance is more important than the balance itself. Strategy games (both turn-based and real-time) are widely seen as being pure skill, but players still complain that they lost because of the smallest chance factors, like starting location or prevailing wind.

Without some external factor like gambling, there is no reason to want to win. Nobody would play Russian roulette with a cap gun, because there is no tension at all. But with games of skill, winning is a proof of skill, a way of showing off. For very competitive people, this can be more important than a monetary bet. Even with a large chance element, such as in Risk, Monopoly, or poker, the bragging rights of winning are worth enough to make the game worth trying at.

Nintendo’s Mario Kart games are a great example of how hard it is to get this balance right. Driving makes it a game of skill, but they add the chance elements of blue shells, lightning bolts, &c., to give weaker players a chance to win. Some players think they went too far with Mario Kart Wii, making it too chance-based, but on the whole those are the hardcore, skilful players: not the grandparents playing the game with people two generations younger.