: Beginning Android

Different Strokes for Different Folks

Different Strokes for Different Folks

One set of resources may not fit all situations where your application may be used. One obvious area comes with string resources and dealing with internationalization (I18N) and localization (L10N). Putting strings all in one language works fine probably at least for the developer but only covers one language.

That is not the only scenario where resources might need to differ, though. Here are others:

Screen orientation: is the screen in a portrait orientation? Landscape? Is the screen square and, therefore, does not really have an orientation?

Screen size: how many pixels does the screen have, so you can size your resources accordingly (e.g., large versus small icons)?

Touchscreen: does the device have a touchscreen? If so, is the touchscreen set up to be used with a stylus or a finger?

Keyboard: what keyboard does the user have (QWERTY, numeric, neither), either now or as an option?

Other input: does the device have some other form of input, like a directional pad or click-wheel?

The way Android currently handles this is by having multiple resource directories, with the criteria for each embedded in their names.

Suppose, for example, you want to support strings in both English and Spanish. Normally, for a single-language setup, you would put your strings in a file named res/values/strings.xml. To support both English and Spanish, you would create two folders, res/values-en and res/values-es, where the value after the hyphen is the ISO 639-1[18] two-letter code for the language you want. Your English-language strings would go in res/values-en/strings.xml and the Spanish ones in res/values-es/strings.xml. Android will choose the proper file based on the users device settings.

Seems easy, right?

Where things start to get complicated is when you need to use multiple disparate criteria for your resources. For example, let us suppose you want to develop both for the T-Mobile G1 and two currently-fictitious devices. One device (the Fictional One) has a VGA screen normally in a landscape orientation (640?480), an always-open QWERTY keyboard, a directional pad, but no touch-screen. The other device (the Fictional Two) has a G1-sized screen (320?480), a numeric keyboard but no QWERTY, a directional pad, and no touch-screen.

You may want to have somewhat different layouts for these devices, to take advantage of different screen real estate and different input options:

You want different layouts for each combination of resolution and orientation

You want different layouts for touch-screen devices versus ones without touch-screens

You want different layouts for QWERTY versus non-QWERTY devices

Once you get into these sorts of situations, though, all sorts of rules come into play, such as:

The configuration options (e.g., -en) have a particular order of precedence, and they must appear in the directory name in that order. The Android documentation[19] outlines the specific order in which these options can appear. For the purposes of this example, screen orientation must precede touchscreen type, which must precede screen size.

There can only be one value of each configuration option category per directory.

Options are case sensitive.

So, for the scenario described previously, in theory, we would need the following directories:

res/layout-port-notouch-qwerty-640x480

res/layout-port-notouch-qwerty-480x320

res/layout-port-notouch-12key-640x480

res/layout-port-notouch-12key-480x320

res/layout-port-notouch-nokeys-640x480

res/layout-port-notouch-nokeys-480x320

res/layout-port-stylus-qwerty-640x480

res/layout-port-stylus-qwerty-480x320

res/layout-port-stylus-12key-640x480

res/layout-port-stylus-12key-480x320

res/layout-port-stylus-nokeys-640x480

res/layout-port-stylus-nokeys-480x320

res/layout-port-finger-qwerty-640x480

res/layout-port-finger-qwerty-480x320

res/layout-port-finger-12key-640x480

res/layout-port-finger-12key-480x320

res/layout-port-finger-nokeys-640x480

res/layout-port-finger-nokeys-480x320

res/layout-land-notouch-qwerty-640x480

res/layout-land-notouch-qwerty-480x320

res/layout-land-notouch-12key-640x480

res/layout-land-notouch-12key-480x320

res/layout-land-notouch-nokeys-640x480

res/layout-land-notouch-nokeys-480x320

res/layout-land-stylus-qwerty-640x480

res/layout-land-stylus-qwerty-480x320

res/layout-land-stylus-12key-640x480

res/layout-land-stylus-12key-480x320

res/layout-land-stylus-nokeys-640x480

res/layout-land-stylus-nokeys-480x320

res/layout-land-finger-qwerty-640x480

res/layout-land-finger-qwerty-480x320

res/layout-land-finger-12key-640x480

res/layout-land-finger-12key-480x320

res/layout-land-finger-nokeys-640x480

res/layout-land-finger-nokeys-480x320

Dont panic! We will shorten this list in just a moment!

Note that for many of these, the actual layout files will be identical. For example, we only care about touch-screen layouts being different than the other two layouts, but since we cannot combine those two, we would theoretically have to have separate directories with identical contents for finger and stylus.

Also note that there is nothing preventing you from also having a directory with the unadorned base name (res/layout). In fact, this is probably a good idea, in case future editions of the Android runtime introduce other configuration options you did not consider having a default layout might make the difference between your application working or failing on that new device.

Now, we can cheat a bit, by decoding the rules Android uses for determining which, among a set of candidates, is the right resource directory to use:

1.First up, Android tosses out ones that are specifically invalid. So, for example, if the screen size of the device is 320?240, the 640x480 directories would be dropped as candidates, since they specifically call for some other size.

2.Next, Android counts the number of matches for each folder, and only pays attention to those with the most matches.

3.Finally, Android goes in the order of precedence of the options in other words, it goes from left to right in the directory name.

So we could skate by with only the following configurations:

res/layout-port-notouch-qwerty-640x480

res/layout-port-notouch-qwerty

res/layout-port-notouch-640x480

res/layout-port-notouch

res/layout-port-qwerty-640x480

res/layout-port-qwerty

res/layout-port-640x480

res/layout-port

res/layout-land-notouch-qwerty-640x480

res/layout-land-notouch-qwerty

res/layout-land-notouch-640x480

res/layout-land-notouch

res/layout-land-qwerty-640x480

res/layout-land-qwerty

res/layout-land-640x480

res/layout-land

Here, we take advantage of the fact that specific matches take precedence over unspecified values. So, a device with a QWERTY keyboard will choose a resource with qwerty in the directory over a resource that does not specify its keyboard type. Combine that with the most matches wins rule, we see that res/layout-port will only match devices with 480?320 screens, no QWERTY keyboard, and a touch-screen in portrait orientation.

We could refine this even further, to only cover the specific devices we are targeting (the T-Mobile G1, the Fictional One, and the Fictional Two), plus take advantage of res/layout being the overall default:

res/layout-port-notouch-640x480

res/layout-port-notouch

res/layout-land-notouch-640x480

res/layout-land-notouch

res/layout-land

res/layout

Here, 640x480 differentiates the Fictional One from the other two devices, while notouch differentiates the Fictional Two from the T-Mobile G1.


: 0.364. /Cache: 3 / 1