Monday, 19 December 2011

Watch out for XmlPullParser.nextText()

Jesse Wilson

[This post is by Jesse Wilson from the Dalvik team. —Tim Bray]

Using XmlPullParser is an efficient and maintainable way to parse XML on Android. Historically Android has had two implementations of this interface:

The implementation from Xml.newPullParser() had a bug where calls to nextText() didn’t always advance to the END_TAG as the documentation promised it would. As a consequence, some apps may be working around the bug with extra calls to next() or nextTag():

    public void parseXml(Reader reader)
throws XmlPullParserException, IOException {
XmlPullParser parser = Xml.newPullParser();
parser.setInput(reader);

parser.nextTag();
parser.require(XmlPullParser.START_TAG, null, "menu");
while (parser.nextTag() == XmlPullParser.START_TAG) {
parser.require(XmlPullParser.START_TAG, null, "item");
String itemText = parser.nextText();
parser.nextTag(); // this call shouldn’t be necessary!
parser.require(XmlPullParser.END_TAG, null, "item");
System.out.println("menu option: " + itemText);
}
parser.require(XmlPullParser.END_TAG, null, "menu");
}

public static void main(String[] args) throws Exception {
new Menu().parseXml(new StringReader("<?xml version='1.0'?>"
+ "<menu>"
+ " <item>Waffles</item>"
+ " <item>Coffee</item>"
+ "</menu>"));
}

In Ice Cream Sandwich we changed Xml.newPullParser() to return a KxmlParser and deleted our ExpatPullParser class. This fixes the nextTag() bug. Unfortunately, apps that currently work around the bug may crash under Ice Cream Sandwich:

org.xmlpull.v1.XmlPullParserException: expected: END_TAG {null}item (position:START_TAG <item>@1:37 in java.io.StringReader@40442fa8) 
at org.kxml2.io.KXmlParser.require(KXmlParser.java:2046)
at com.publicobject.waffles.Menu.parseXml(Menu.java:25)
at com.publicobject.waffles.Menu.main(Menu.java:32)

The fix is to call nextTag() after a call to nextText() only if the current position is not an END_TAG:

  while (parser.nextTag() == XmlPullParser.START_TAG) {
parser.require(XmlPullParser.START_TAG, null, "item");
String itemText = parser.nextText();
if (parser.getEventType() != XmlPullParser.END_TAG) {
parser.nextTag();
}
parser.require(XmlPullParser.END_TAG, null, "item");
System.out.println("menu option: " + itemText);
}

The code above will parse XML correctly on all releases. If your application uses nextText() extensively, use this helper method in place of calls to nextText():

  private String safeNextText(XmlPullParser parser)
throws XmlPullParserException, IOException {
String result = parser.nextText();
if (parser.getEventType() != XmlPullParser.END_TAG) {
parser.nextTag();
}
return result;
}

Moving to a single XmlPullParser simplifies maintenance and allows us to spend more energy on improving system performance.

Friday, 16 December 2011

Android 4.0.3 Platform and Updated SDK tools

Today we are announcing Android 4.0.3, an incremental release of the Android 4.0 (Ice Cream Sandwich) platform. The new release includes a variety of optimizations and bug fixes for phones and tablets, as well as a small number of new APIs for developers. The new API level is 15.

Some of the new APIs in Android 4.0.3 include:

Social stream API in Contacts provider: Applications that use social stream data such as status updates and check-ins can now sync that data with each of the user’s contacts, providing items in a stream along with photos for each. This new API lets apps show users what the people they know are doing or saying, in addition to their photos and contact information.

Calendar provider enhancements. Apps can now add color to events, for easier tracking, and new attendee types and states are now available.

New camera capabilities. Apps can now check and manage video stabilization and use QVGA resolution profiles where needed.

Accessibility refinements. Improved content access for screen readers and new status and error reporting for text-to-speech engines.

Incremental improvements in graphics, database, spell-checking, Bluetooth, and more.

For a complete overview of what’s new in the platform, see the Android 4.0.3 API Overview.

Going forward, we’ll be focusing our partners on Android 4.0.3 as the base version of Ice Cream Sandwich. The new platform will be rolling out to production phones and tablets in the weeks ahead, so we strongly encourage you to test your applications on Android 4.0.3 as soon as possible.

We would also like to remind developers that we recently released new version of the SDK Tools (r16) and of the Eclipse plug-in (ADT 16.0.1). We have also updated the NDK to r7.

Visit the Android Developers site for more information about Android 4.0.3 and other platform versions. To get started developing or testing on the new platform, you can download it into your SDK using the Android SDK Manager.

Thursday, 15 December 2011

Introducing Android Training

[This post is by Reto Meier, Android Developer Relations Tech Lead. — Tim Bray]

Today I’m thrilled to announce the beta launch of Android Training — a collection of classes that we hope will help you to build better Android apps.

From designing effective navigation, to managing audio playback, to optimizing battery life, these classes are designed to demonstrate best practices for solving common Android development problems.

Each class explains the steps required to solve a problem, or implement a feature, with plenty of code snippets and sample code for you to use within your own apps.

We’re starting small and this is just the beginning for Android Training. Over the coming months we will be increasing the number of classes available, as well as introducing over-arching courses and sample apps to further help your development experience.

Helping developers build great apps is what the Android Developer Relations team is all about, so we’re excited to see how you use these classes to make your apps even better.

We’d love to know what you think of these classes, and what classes you’d like to see next.

Wednesday, 14 December 2011

More Android Games that Play Nice

[This post is by Dan Galpin, who lives the Android Games lifestyle every day. — Tim Bray]

Making a game on Android is easy. Making a great game for a mobile, multitasking, often multi-core, multi-purpose system like Android is trickier. Even the best developers frequently make mistakes in the way they interact with the Android system and with other applications — mistakes that don’t affect the quality of gameplay, but which affect the quality of the user’s experience in other ways.

A truly great Android game knows how to play nice: how to fit seamlessly into the system of apps, services, and UI features that run on Android devices. In this multi-part series of posts, Android Developer Relations engineers who specialize in games explain what it takes to make your game play nice.

II: Navigation and Lifecycle

Android users get used to using the back key. We expect the volume keys to work in some intuitive fashion. We expect that the home key behaves in a manner consistent with the Android navigation paradigm. Sometimes we even expect the menu key to do something.

1. Problem: There’s no place like [Home]

I’m playing [insert favorite game here] and I accidentally hit the [Home] key or the [Back] key. This is probably happening because I’m furiously using the touchscreen to actually play the game. Whether I’ve been cutting ropes, controlling aircraft, cleaving fruit, or flinging birds, I’m almost certainly angry if I’ve suddenly lost all of my game progress.

What went wrong?

Lots of developers assume that pressing the Home key exits a game. Perhaps this is because on some mobile devices the Home key is a somewhat-difficult-to-press physical button. Depending on the device and Android release, it might be a physical, capacitive, or soft button. This means that it is relatively easy to hit accidentally. Having progress lost by such an event as an incoming call is even worse.

How to avoid Angry Users

  1. Save as much about the status of the game into the Bundle in onSaveInstanceState() as you can. This helper function will get called whenever your application receives an onPause() callback. Note that you can save byte arrays into that bundle, so it can easily be used for raw data.


  2. If your game takes lots of native system resources, consider dumping large textures (or all textures and geometry) during onPause() or onStop(). (GLSurfaceView will do this automatically unless you tell it not to — at least you can tell it not to do so starting in API level 11). This will help your title continue to reside in memory, which will typically speed task-switching back to your game for very large titles that might otherwise be swapped out of memory, but may slow things down for smaller titles that can more efficiently multitask if they don’t bother to do this.


  3. When your game resumes, restore the state from the bundle in onRestoreInstanceState(). If there is any sort of time-consuming loading that has to be done, make sure that you notify the user of what is happening to give them the best possible experience.



  4. Test thoroughly!

2. Problem: [Back] I say!

I’m in the middle of playing a game and I hit the back key. One of several bad things can happen here:

  1. The game exits immediately, losing all state and leading to Angry User Syndrome. (see Problem 1).


  2. The game does nothing.


What went wrong?

We already know what is wrong with scenario 1. It’s essentially a data loss scenario, and it’s worse than pigs stealing your eggs. What is wrong with scenario 2?

The [Back] key is an essential part of the Android navigation paradigm. If the back key doesn’t return to the previous screen in the activity stack (or in the game hierarchy) there better be a very good reason, such as an active document with no capability to save a draft.

What to do about it

If the user is in the middle of gameplay It is customary to display some sort of dialog asking the user if they intended the action:

“Are you sure you wish to exit now? That monster looks hungry.”

In an extreme action game, you might also wish to do something similar to what Replica Island (RI) did. RI assumed that any [Back] keypress that happened within 200ms of another touch event was invalid in order to make it a bit more challenging to accidentally press the key.

At the Main Menu of the game, you can decide whether it makes sense to prompt the user or not. If your game has very long load times, you might want to prompt the user.

3. Problem: Quiet [Down]!

There’s nothing worse than wanting to settle down for a good session of [insert favorite game here] in some sort of public place with your volume turned up. Suddenly everyone has learned that you prefer pummelling produce to predicting present progressions and that’s practically profane in your profession.

What went wrong?

By default, volume keys in most Android devices will control the ringer volume, and your application must pass the volume keys through to the super class so this continues to work.

What to do about it

In order to make these keys control the music volume (which is the channel that your game will be using), you need to call setVolumeControlStream(AudioManager.STREAM_MUSIC). As stated previously, all you need to do is pass these keys through to the framework and you’ll get control of the audio in the standard and proper way. Do it as early as possible so a user can start changing the volume far before you begin playing anything.

Monday, 12 December 2011

Add Voice Typing To Your IME

[This post is by Luca Zanolin, an Android engineer who works on voice typing. — Tim Bray]



A new feature available in Android 4.0 is voice typing: the difference for users is that the recognition results appear in the text box while they are still speaking. If you are an IME developer, you can easily integrate with voice typing.

To simplify the integration, if you download this library and modify your IME as described below, everything will work smoothly on any device with Android 2.2 or later. On 4.0+, users will get voice typing, and earlier versions will use standard voice recognition; the difference is illustrated below.

To see how to integrate voice typing you can take a look at this sample IME. The IME is really simple and contains only one button: a microphone. By pressing the microphone, the user triggers voice recognition.

Here are the steps that you need to follow to integrate voice recognition into your IME.

Download the library

Download this library and add it to your IME APK.

Create the voice recognition trigger

The library contains the VoiceRecognitionTrigger helper class. Create an instance of it inside the InputMethodService#onCreate method in your IME.

public void onCreate() {
super.onCreate();
...
mVoiceRecognitionTrigger = new VoiceRecognitionTrigger(this);
}

Add the microphone icon to your IME

You need to modify the UI of your IME, add a microphone icon, and register an OnClickListener to trigger voice recognition. You can find the assets inside the sample IME. The microphone icon should be displayed only if voice recognition is installed; use VoiceRecognitionTrigger#isInstalled().

public View onCreateInputView() {
LayoutInflater inflater = (LayoutInflater) getSystemService(
Service.LAYOUT_INFLATER_SERVICE);
mView = inflater.inflate(R.layout.ime, null);
...
mButton = (ImageButton) mView.findViewById(R.id.mic_button);
if (mVoiceRecognitionTrigger.isInstalled()) {
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mVoiceRecognitionTrigger.startVoiceRecognition();
}
});
mButton.setVisibility(View.VISIBLE);
} else {
mButton.setVisibility(View.GONE);
}
return mView;
}

If your IME supports multiple languages, you can specify in which language recognition should be done as a parameter of startVoiceRecognition().

Notify the trigger when your IME starts

When your IME starts, you need to notify the trigger, so it can insert into the text view any pending recognition results.

@Override
public void onStartInputView(EditorInfo info, boolean restarting) {
super.onStartInputView(info, restarting);
if (mVoiceRecognitionTrigger != null) {
mVoiceRecognitionTrigger.onStartInputView();
}
}

Modify your AndroidManifest

In order to start a voice recognition through the Intent API, the library uses a service and an activity, and you need to add them into your manifest.

<manifest ... >
<application ...>
...
<service android:name="com.google.android.voiceime.ServiceHelper" />
<activity
android:name="com.google.android.voiceime.ActivityHelper"
android:theme="@android:style/Theme.Translucent.NoTitleBar"
android:excludeFromRecents="true"
android:windowSoftInputMode="stateAlwaysHidden"
android:finishOnTaskLaunch="true"
android:configChanges="keyboard|keyboardHidden|navigation
|orientation"/>
</application>
</manifest>

Update the microphone icon dynamically (optional)

This step is optional, but you should implement it if possible as it will improve the user experience. Voice recognition requires network access, and if there is no network, your IME should notify the user that voice recognition is currently disabled. To achieve this, you need to register the VoiceRecognitionTrigger.Listener and enable/disable the microphone accordingly.

The listener is registered in InputMethodService#onCreate, and you have to unregister it in InputMethodService#onDestroy, otherwise you will leak the listener.

@Override
public void onCreate() {
super.onCreate();
...
mVoiceRecognitionTrigger = new VoiceRecognitionTrigger(this);
mVoiceRecognitionTrigger.register(new VoiceRecognitionTrigger.Listener() {
@Override
public void onVoiceImeEnabledStatusChange() {
updateVoiceImeStatus();
}
});
}

...
@Override
public void onDestroy() {
...
if (mVoiceRecognitionTrigger != null) {
mVoiceRecognitionTrigger.unregister(this);
}
super.onDestroy();
}

private void updateVoiceImeStatus() {
if (mVoiceRecognitionTrigger.isInstalled()) {
mButton.setVisibility(View.VISIBLE);
if (mVoiceRecognitionTrigger.isEnabled()) {
mButton.setEnabled(true);
} else {
mButton.setEnabled(false);
}
} else {
mButton.setVisibility(View.GONE);
}
mView.invalidate();
}

And add this permission into your manifest:

<manifest ... >
...
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
...
</manifest>

That’s all there is to it

Voice recognition makes it easy for users to do more with their Android devices, so we appreciate your support in adding it to your IMEs.

Thursday, 8 December 2011

A Closer Look at 10 Billion Downloads



[This post is by Eric Chu, Android Developer Ecosystem. —Dirk Dougherty]



On Tuesday, we announced that Android Market passed 10 Billion app downloads. We wanted to look a little deeper at that huge number. First question: which app was lucky number 10 billion? Photobucket Mobile. They’ll be getting a great prize package, including tickets to next year’s Google I/O developer conference.



Remember we still have 8 days left to celebrate 10 billion downloads with 10-cent apps on Android Market. You can follow which apps are promoted each day on +Android, our Google+ page.



Here’s a graphical deep dive into 10 billion downloads...








Tuesday, 6 December 2011

10 Billion Android Market Downloads and Counting



[This post is by Eric Chu, Android Developer Ecosystem. —Dirk Dougherty]





One billion is a pretty big number by any measurement. However, when it’s describing the speed at which something is growing, it’s simply amazing. This past weekend, thanks to Android users around the world, Android Market exceeded 10 billion app downloads—with a growth rate of one billion app downloads per month. We can’t wait to see where this accelerating growth takes us in 2012.





To celebrate this milestone, we partnered with some of the Android developers who contributed to this milestone to make a bunch of great Android apps available at an amazing price. Starting today for the next 10 days, we’ll have a new set of awesome apps available each day for only 10 cents each. Today, we are starting with Asphalt 6 HD, Color & Draw for Kids, Endomondo Sports Tracker Pro, Fieldrunners HD, Great Little War Game, Minecraft, Paper Camera, Sketchbook Mobile, Soundhound Infinity and Swiftkey X.



Of course, none of these apps would have existed if it weren’t for the developers who created them. Every day, these developers continue to push the limits on what’s possible and delight us in the process. For that, we thank them.



Please join us in this 10-day celebration and check in every day to see what new apps our developer partners are making available on Android Market—for only a dime.

Monday, 28 November 2011

Games Coming to Android Market in Korea



[This post is by Eric Chu, Android Developer Ecosystem. —Dirk Dougherty]



In the 24 months since the first Android device became available locally, Korea has quickly become one of the top countries in Android device activations. In parallel, we’ve also seen tremendous growth in app downloads from Android Market. Korea is now the second-largest consumer of apps worldwide. Today we are adding to this momentum by bringing games to Android Market in Korea.



Starting right away, Android users in Korea can explore the many thousands of popular game titles available in Android Market and download them onto their devices. For paid games, purchasing is fast and convenient through direct carrier billing, which lets users in Korea easily charge their purchases to their monthly mobile operator bills.



If you are a game developer, now is the time to localize your game resources, app descriptions, and marketing assets to take advantage of this new opportunity. When you are ready, please visit the Android Market developer console to target your app for distribution in South Korea and set prices in Korean Won (KRW). If you don’t want to distribute to Korea right away, you can also exclude it.



With the huge popularity of games on Android and the convenience of direct carrier billing in Korea, we expect to see a jump in game purchases and downloads in the weeks ahead. For game developers worldwide, it’s “game on” in Korea!

Tuesday, 22 November 2011

Making Android Games that Play Nice

[This post is by Ian Ni-Lewis, a Developer Advocate who devotes most of his time to making Android games more awesome. — Tim Bray]



Making a game on Android is easy. Making a great game for a mobile, multitasking, often multi-core, multi-purpose system like Android is trickier. Even the best developers frequently make mistakes in the way they interact with the Android system and with other applications
 — mistakes that don’t affect the quality of gameplay, but which affect the quality of the user’s experience in other ways.

A truly great Android game knows how to play nice: how to fit seamlessly into the system of apps, services, and UI features that run on Android devices. In this multi-part series of posts, Android Developer Relations engineers who specialize in games explain what it takes to make your game play nice.

I: The Audio Lifecycle (or, why is there music coming from my pants?)

One of the most awesome things about Android is that it can do so much stuff in the background. But when apps aren’t careful about their background behaviors, it can get annoying. Take my own personal pet peeve: game audio that doesn’t know when to quit.

The problem

I’m on the bus to work, passing the time with a great Android game. I’m completely entranced by whatever combination of birds, ropes, and ninjas is popular this week. Suddenly I panic: I’ve almost missed my stop! I leap up, quickly locking my phone as I shove it into a pocket.

I arrive breathless at my first meeting of the day. The boss, perhaps sensing my vulnerability, asks me a tough question. Not tough enough to stump me, though — I’ve got the answer to that right here on my Android phone! I whip out my phone and press the unlock button... and the room dissolves in laughter as a certain well-known game ditty blares out from the device.

The initial embarrassment is bad enough, but what’s this? I can’t even mute the thing! The phone is showing the lock screen and the volume buttons are inactive. My stress level is climbing and it takes me three tries to successfully type in my unlock code. Finally I get the thing unlocked, jam my finger on the home button and breathe a sigh of relief as the music stops. But the damage is done — my boss is glowering and for the rest of the week my co-workers make video game noises whenever they pass my desk.

What went wrong?

It’s a common mistake: the developer of the game assumed that if the game received an onResume() message, it was safe to resume audio. The problem is that onResume() doesn’t necessarily mean your app is visible — only that it’s active. In the case of a locked phone, onResume() is sent as soon as the screen turns on, even though the phone’s display is on the lock screen and the volume buttons aren’t enabled.

Fixing this is trickier than it sounds. Some games wait for onWindowFocusChanged() instead of onResume(), which works pretty well on Gingerbread. But on Honeycomb and higher, onWindowFocusChanged() is sent when certain foreground windows — like, ironically, the volume control display window — take focus. The result is that when the user changes the volume, all of the sound is muted. Not the developer’s original intent!

Waiting for onResume() and onFocusChanged() seems like a possible fix, and it works pretty well in a large number of cases. But even this approach has its Achilles’ heel. If the device falls asleep on its own, or if the user locks the phone and then immediately unlocks it, your app may not receive any focus changed messages at all.

What to do about it

Here’s the easy two-step way to avoid user embarrassment:

  1. Pause the game (and all sound effects) whenever you receive an onPause() message. When gameplay is interrupted — whether because the phone is locked, or the user received a call, or for some other reason — the game should be paused.


  2. After the game is paused, require user input to continue. The biggest mistake most game developers make is to automatically restart gameplay and audio as soon as the user returns to the game. This isn’t just a question of solving the “music over lock screen” issue. Users like to come back to a paused game. It’s no fun to switch back to a game, only to realize you’re about to die because gameplay has resumed before you expected it.


Some game designers don’t like the idea of pausing the background music when the game is paused. If you absolutely must resume music as soon as your game regains focus, then you should do the following:

  1. Pause playback when you receive onPause().


  2. When you receive onResume():

    1. If you have previously received an onFocusChanged(false) message, wait for an onFocusChanged(true) message to arrive before resuming playback.


    2. If you have not previously received an onFocusChanged(false) message, then resume audio immediately.



  3. Test thoroughly!


Fixing audio embarrassments is almost always a quick and easy process. Take the time to do it right, and your users will thank you.

Friday, 11 November 2011

Updated NDK for Android 4.0

Today we are releasing an updated version of the Android NDK, now in revision 7. The updated NDK lets developers who are using native code get started with the new native APIs available in Android 4.0.

Android NDK r7 includes a number of build system improvements and bug fixes, but most importantly it gives you access to two new sets of APIs:

Low-level streaming multimedia: A new API based on Khronos OpenMAX AL 1.0.1 provides a direct, efficient path for low-level streaming multimedia. The new path is ideal for applications that need to maintain complete control over media data before passing it to the platform for presentation. For example, media applications can now retrieve data from any source, apply proprietary encryption/decryption, and then send the data to the platform for display.

Audio decoding into PCM: Extensions to the existing native audio API based on Khronos OpenSL ES let native apps decode compressed audio assets to PCM format.

For detailed information about how to use these new APIs, please see the documentation included with the Android NDK r7 package. To read about the build system improvements and bug fixes included in this release, check out the release notes.

Thursday, 10 November 2011

New Layout Widgets: Space and GridLayout

[This post is by Philip Milne, who is part of the Android framework team. — Tim Bray]

Ice Cream Sandwich (ICS) sports two new widgets that have been designed to support the richer user interfaces made possible by larger displays: Space and GridLayout.

The most commonly used class for layout in Android is LinearLayout, which allows its children to be aligned in the usual ways: along either the horizontal or vertical axes. It’s often possible to take a complicated layout and break it down into a set of nested linear layouts and, provided this nesting doesn’t get too deep, this is still a good choice for many simple layouts.

A number of posts and articles (e.g. Android Layout Tricks #1, Flattening The Stack) have highlighted drawbacks of nested layouts; which fall into three basic categories:

  • Inability to control alignment along both axes simultaneously


  • Performance problems in hierarchies that are too deep


  • Unsuitability for design tools that support free-form editing


A simple example of the first problem is the following form:

As the font and the text of the “Email address” label change, we want the label to remain aligned with the baseline of the component to its right, and aligned with the right edge of the label below it. It’s not possible to do this with nested LinearLayouts because the label needs to be aligned with other components both horizontally and vertically.

These problems aren’t new to Android, or UI toolkits in general, but we’ve used them to drive our work in enriching platform support for flatter hierarchies.

GridLayout

To provide better support for layouts like these we have added a new layout to the Android framework: GridLayout, which can be used to solve the above problems by dividing the container’s real estate into rows and columns:

Now the “Email address” label can belong both to a row that is baseline-aligned, and a column that is right-aligned.

GridLayout uses a grid of infinitely-thin lines to separate its drawing area into: rows, columns, and cells. It supports both row and column spanning, which together allow a widget to occupy a rectangular range of cells that are next to each other. We’ll use the words row, column, and cell in the text below as shorthand for row group, column group and cell group respectively, where groups have one or more contiguous elements.

Similarities with LinearLayout

Wherever possible, GridLayout uses the same conventions as LinearLayout for all its XML API — so it should be easy to start using GridLayout if you’ve already used LinearLayout. In fact, the APIs are so similar that changing a tag name from LinearLayout to GridLayout in an XML file that uses LinearLayout will often produce a similar UI without requiring any other changes. When it doesn’t, you’ll still generally end up with a good starting point for a two-dimensional layout.

Getting Started

Two examples in the samples area of the Android 4.0 SDK show typical use of the programmatic and XML APIs respectively:

[Both examples produce the same UI.]

Here’s a slightly simpler version of the above XML layout.

<?xml version="1.0" encoding="utf-8"?>
<GridLayout
xmlns:android="http://schemas.android.com/apk/res/android"

android:layout_width="match_parent"
android:layout_height="match_parent"

android:useDefaultMargins="true"
android:alignmentMode="alignBounds"
android:columnOrderPreserved="false"

android:columnCount="4"
>

<TextView
android:text="Email setup"
android:textSize="32dip"

android:layout_columnSpan="4"
android:layout_gravity="center_horizontal"
/>

<TextView
android:text="You can configure email in just a few steps:"
android:textSize="16dip"

android:layout_columnSpan="4"
android:layout_gravity="left"
/>

<TextView
android:text="Email address:"

android:layout_gravity="right"
/>

<EditText
android:ems="10"
/>

<TextView
android:text="Password:"

android:layout_column="0"
android:layout_gravity="right"
/>

<EditText
android:ems="8"
/>

<Space
android:layout_row="4"
android:layout_column="0"
android:layout_columnSpan="3"
android:layout_gravity="fill"
/>

<Button
android:text="Next"

android:layout_row="5"
android:layout_column="3"
/>
</GridLayout>

The first difference you’ll notice in these examples is the absence of the WRAP_CONTENT and MATCH_PARENT constants that normally adorn Android layout resources. You don’t normally need to use these with GridLayout, for reasons that are described in the API doc for GridLayout.LayoutParams.

Row and Column Indices

The second thing you may notice in the XML resources is that widgets don’t always explicitly define which cells they are to be placed in. Each widget’s layout parameters have row and column indices that together define where the widget should be placed but when either or both of these values are not specified, GridLayout supplies default values rather than throwing an exception.

Automatic Index Allocation

As children are added to a GridLayout, it maintains a cursor position and a “high-water mark” that it uses to place widgets in cells that don’t yet have anything in them.

When GridLayout’s orientation property is horizontal and a columnCount has been set (to 8 in this example) the high-water mark (shown above in red) is maintained as a separate height value for each column. When indices need to be created, GridLayout first determines the size of the cell group (by looking at the rowSpan and columnSpan parameters of the new widget) and then, starting at the cursor, goes through the available locations from: left to right, top to bottom, so as to find the row and column indices of the first location that’s free.

When GridLayout’s orientation is vertical, all of the same principles apply, except that the roles of the horizontal and vertical axes are exchanged.

If you want multiple views to be placed in the same cell, you have to define the indices explicitly, as the default allocation procedure above is designed to place widgets in separate cells.

Sizes, Margins and Alignment/Gravity

In GridLayout, specifying sizes and margins is done just as with a LinearLayout. Alignment/gravity also works just like gravity in LinearLayout and uses the same constants: left, top, right, bottom, center_horizontal, center_vertical, center, fill_horizontal, fill_vertical and fill.

Flexibility

Unlike most grids in other toolkits, GridLayout does not associate data with rows or columns. Instead, everything to do with alignment and flexibility is associated with the components themselves. GridLayout departs from the norm here to provide a more general system that allows subtle relationships between ancestors in deeply nested layouts to be accommodated in a single layout configuration.

The flexibility of columns is inferred from the gravity of the components inside the column. If every component defines a gravity, the column is taken as flexible, otherwise the column is considered inflexible. Full details are in GridLayout’s API docs.

Emulating Features from other Layouts

GridLayout does not incorporate all of the features of every layout in the Android platform but it has a rich enough feature set that idiomatic use of other layouts can normally be emulated from inside a single GridLayout.

Although LinearLayout can be considered a special case of a GridLayout, for the degenerate case when a set of views are aligned in a single row or column, LinearLayout is the better choice when this is all that is required as it clarifies the purpose of the container and may have some (relatively small) performance advantages.

TableLayout configurations are normally straightforward to accommodate, as GridLayout supports both row and column spanning. TableRows can be removed, as they are not required by GridLayout. For the same UI, a GridLayout will generally be faster and take less memory than than a TableLayout.

Simple RelativeLayout configurations can be written as grids simply by grouping the views that are related to each other into rows and columns. Unlike conventional grids, GridLayout uses a constraints solver to do the heavy lifting of the layout operation. By using GridLayout’s rowOrderPreserved and columnOrderPreserved properties it’s possible to free GridLayout from the confines of traditional grid systems and support the majority of RelativeLayout configurations — even ones that require grid lines to pass over each other as children change size.

Simple FrameLayout configurations can be accommodated within the cells of a GridLayout because a single cell can contain multiple views. To switch between two views, place them both in the same cell and use the visibility constant GONE to switch from one to the other from code. As with the LinearLayout case above, if all you need is the functionality described above, FrameLayout is the better choice and may have some small performance advantages.

One key feature that GridLayout lacks is the ability to distribute excess space between rows or columns in specified proportions — a feature that LinearLayout provides by supporting the principle of weight. This omission and possible ways around it are discussed in GridLayout’s API docs.

The Phases of the Layout Operation

It’s useful to distinguish the allocation phase for cell indices discussed above from the layout operation itself. Normally the phase that allocates indices happens once, if at all, when a UI is initialized. The index-allocation phase only applies when indices have been left unspecified, and is responsible for ensuring that all views have a defined set of cells in which they are to be placed at layout time.

The layout operation happens after this and is recalculated each time a view changes size. GridLayout measures the size of each child during the layout operation so it can calcuate the heights and widths of the rows and columns in the grid. The layout phase completes by using gravity to place each of the components in its cell.

Although index allocation normally only happens once, GridLayout is technically a dynamic layout, meaning that if you change its orientation property or add or remove children after components have been laid out, GridLayout will repeat the above procedure to reallocate indices in a way that is right for the new configuration.

From a performance standpoint, it is worth knowing that the GridLayout implementation has been optimized for the common case, when initialization happens once and layout happens frequently. As a result, the initialization step sets up internal data structures so that the layout operation can complete quickly and without allocating memory. Put another way, changes either to GridLayout’s orientation or the number of children it has are much more expensive than an ordinary layout operation.

Conclusion

GridLayout’s feature set incorporates much of the functionality of the Android framework’s existing general-purpose layouts: LinearLayout, FrameLayout, TableLayout and RelativeLayout. As such, it provides a way to replace many deeply nested view hierarchies with a single highly optimized layout implementation.

If you are starting a UI from scratch and are not familiar with Android layouts, use a GridLayout — it supports most of the features of the other layouts and has a simpler and more general API than either TableLayout or RelativeLayout.

We anticipate that the combination of FrameLayout, LinearLayout and GridLayout together will provide a feature set that’s rich enough to allow most layout problems to be solved without writing layout code by hand. It’s worth spending some time deciding which of these layouts is right for the top of your tree; a good choice will minimize the need for intermediate containers and result in a user interface that is faster and uses less memory.

Tuesday, 8 November 2011

More Android Developer Labs in Asia

A couple of months ago, we kicked off a series of Android Developer Labs in Asia, North America and Europe. To wrap up the 2011 series, we now have opened registration for 2 more locations in Asia.

  • Taipei — December 2, 2011

  • Hong Kong — December 6, 2011

Remember, this ADL series isn’t another set of introduction-to-Android sessions, nor any other kind of general overview. It's specifically aimed at optimizing Android apps for tablets, in particular creating high-quality tablet apps with an emphasis on polish and user experience.

Registration is a two-step process. Anyone can register, but we can only accommodate a relatively small number of attendees from among the registrants, based on whether they already have an Android app with the potential to be a top-tier tablet app in terms of quality, fit, and finish. The goal is to bring your app to the ADL, and leave equipped to make it into one that makes Android tablet users smile.

Thursday, 3 November 2011

JNI Local Reference Changes in ICS

[This post is by Elliott Hughes, a Software Engineer on the Dalvik team. — Tim Bray]

If you don’t write native code that uses JNI, you can stop reading now. If you do write native code that uses JNI, you really need to read this.

What’s changing, and why?

Every developer wants a good garbage collector. The best garbage collectors move objects around. This lets them offer very cheap allocation and bulk deallocation, avoids heap fragmentation, and may improve locality. Moving objects around is a problem if you’ve handed out pointers to them to native code. JNI uses types such as jobject to solve this problem: rather than handing out direct pointers, you’re given an opaque handle that can be traded in for a pointer when necessary. By using handles, when the garbage collector moves an object, it just has to update the handle table to point to the object’s new location. This means that native code won’t be left holding dangling pointers every time the garbage collector runs.

In previous releases of Android, we didn’t use indirect handles; we used direct pointers. This didn’t seem like a problem as long as we didn’t have a garbage collector that moves objects, but it let you write buggy code that still seemed to work. In Ice Cream Sandwich, even though we haven't yet implemented such a garbage collector, we've moved to indirect references so you can start detecting bugs in your native code.

Ice Cream Sandwich features a JNI bug compatibility mode so that as long as your AndroidManifest.xml’s targetSdkVersion is less than Ice Cream Sandwich, your code is exempt. But as soon as you update your targetSdkVersion, your code needs to be correct.

CheckJNI has been updated to detect and report these errors, and in Ice Cream Sandwich, CheckJNI is on by default if debuggable="true" in your manifest.

A quick primer on JNI references

In JNI, there are several kinds of reference. The two most important kinds are local references and global references. Any given jobject can be either local or global. (There are weak globals too, but they have a separate type, jweak, and aren’t interesting here.)

The global/local distinction affects both lifetime and scope. A global is usable from any thread, using that thread’s JNIEnv*, and is valid until an explicit call to DeleteGlobalRef(). A local is only usable from the thread it was originally handed to, and is valid until either an explicit call to DeleteLocalRef() or, more commonly, until you return from your native method. When a native method returns, all local references are automatically deleted.

In the old system, where local references were direct pointers, local references were never really invalidated. That meant you could use a local reference indefinitely, even if you’d explicitly called DeleteLocalRef() on it, or implicitly deleted it with PopLocalFrame()!

Although any given JNIEnv* is only valid for use on one thread, because Android never had any per-thread state in a JNIEnv*, it used to be possible to get away with using a JNIEnv* on the wrong thread. Now there’s a per-thread local reference table, it’s vital that you only use a JNIEnv* on the right thread.

Those are the bugs that ICS will detect. I’ll go through a few common cases to illustrate these problems, how to spot them, and how to fix them. It’s important that you do fix them, because it’s likely that future Android releases will utilize moving collectors. It will not be possible to offer a bug-compatibility mode indefinitely.

Common JNI reference bugs

Bug: Forgetting to call NewGlobalRef() when stashing a jobject in a native peer

If you have a native peer (a long-lived native object corresponding to a Java object, usually created when the Java object is created and destroyed when the Java object’s finalizer runs), you must not stash a jobject in that native object, because it won’t be valid next time you try to use it. (Similar is true of JNIEnv*s. They might be valid if the next native call happens on the same thread, but they won’t be valid otherwise.)

 class MyPeer {
public:
MyPeer(jstring s) {
str_ = s; // Error: stashing a reference without ensuring it’s global.
}
jstring str_;
};

static jlong MyClass_newPeer(JNIEnv* env, jclass) {
jstring local_ref = env->NewStringUTF("hello, world!");
MyPeer* peer = new MyPeer(local_ref);
return static_cast<jlong>(reinterpret_cast<uintptr_t>(peer));
// Error: local_ref is no longer valid when we return, but we've stored it in 'peer'.
}

static void MyClass_printString(JNIEnv* env, jclass, jlong peerAddress) {
MyPeer* peer = reinterpret_cast<MyPeer*>(static_cast<uintptr_t>(peerAddress));
// Error: peer->str_ is invalid!
ScopedUtfChars s(env, peer->str_);
std::cout << s.c_str() << std::endl;
}

The fix for this is to only store JNI global references. Because there’s never any automatic cleanup of JNI global references, it’s critically important that you clean them up yourself. This is made slightly awkward by the fact that your destructor won’t have a JNIEnv*. The easiest fix is usually to have an explicit ‘destroy‘ function for your native peer, called from the Java peer’s finalizer:

 class MyPeer {
public:
MyPeer(JNIEnv* env, jstring s) {
this->s = env->NewGlobalRef(s);
}
~MyPeer() {
assert(s == NULL);
}
void destroy(JNIEnv* env) {
env->DeleteGlobalRef(s);
s = NULL;
}
jstring s;
};

You should always have matching calls to NewGlobalRef()/DeleteGlobalRef(). CheckJNI will catch global reference leaks, but the limit is quite high (2000 by default), so watch out.

If you do have this class of error in your code, the crash will look something like this:

    JNI ERROR (app bug): accessed stale local reference 0x5900021 (index 8 in a table of size 8)
JNI WARNING: jstring is an invalid local reference (0x5900021)
in LMyClass;.printString:(J)V (GetStringUTFChars)
"main" prio=5 tid=1 RUNNABLE
| group="main" sCount=0 dsCount=0 obj=0xf5e96410 self=0x8215888
| sysTid=11044 nice=0 sched=0/0 cgrp=[n/a] handle=-152574256
| schedstat=( 156038824 600810 47 ) utm=14 stm=2 core=0
at MyClass.printString(Native Method)
at MyClass.main(MyClass.java:13)

If you’re using another thread’s JNIEnv*, the crash will look something like this:

 JNI WARNING: threadid=8 using env from threadid=1
in LMyClass;.printString:(J)V (GetStringUTFChars)
"Thread-10" prio=5 tid=8 NATIVE
| group="main" sCount=0 dsCount=0 obj=0xf5f77d60 self=0x9f8f248
| sysTid=22299 nice=0 sched=0/0 cgrp=[n/a] handle=-256476304
| schedstat=( 153358572 709218 48 ) utm=12 stm=4 core=8
at MyClass.printString(Native Method)
at MyClass$1.run(MyClass.java:15)

Bug: Mistakenly assuming FindClass() returns global references

FindClass() returns local references. Many people assume otherwise. In a system without class unloading (like Android), you can treat jfieldID and jmethodID as if they were global. (They’re not actually references, but in a system with class unloading there are similar lifetime issues.) But jclass is a reference, and FindClass() returns local references. A common bug pattern is “static jclass”. Unless you’re manually turning your local references into global references, your code is broken. Here’s what correct code should look like:

 static jclass gMyClass;
static jclass gSomeClass;

static void MyClass_nativeInit(JNIEnv* env, jclass myClass) {
// ‘myClass’ (and any other non-primitive arguments) are only local references.
gMyClass = env->NewGlobalRef(myClass);

// FindClass only returns local references.
jclass someClass = env->FindClass("SomeClass");
if (someClass == NULL) {
return; // FindClass already threw an exception such as NoClassDefFoundError.
}
gSomeClass = env->NewGlobalRef(someClass);
}

If you do have this class of error in your code, the crash will look something like this:

    JNI ERROR (app bug): attempt to use stale local reference 0x4200001d (should be 0x4210001d)
JNI WARNING: 0x4200001d is not a valid JNI reference
in LMyClass;.useStashedClass:()V (IsSameObject)

Bug: Calling DeleteLocalRef() and continuing to use the deleted reference

It shouldn’t need to be said that it’s illegal to continue to use a reference after calling DeleteLocalRef() on it, but because it used to work, so you may have made this mistake and not realized. The usual pattern seems to be where native code has a long-running loop, and developers try to clean up every single local reference as they go to avoid hitting the local reference limit, but they accidentally also delete the reference they want to use as a return value!

The fix is trivial: don’t call DeleteLocalRef() on a reference you’re going to use (where “use” includes “return”).

Bug: Calling PopLocalFrame() and continuing to use a popped reference

This is a more subtle variant of the previous bug. The PushLocalFrame() and PopLocalFrame() calls let you bulk-delete local references. When you call PopLocalFrame(), you pass in the one reference from the frame that you’d like to keep (typically for use as a return value), or NULL. In the past, you’d get away with incorrect code like the following:

 static jobjectArray MyClass_returnArray(JNIEnv* env, jclass) {
env->PushLocalFrame(256);
jobjectArray array = env->NewObjectArray(128, gMyClass, NULL);
for (int i = 0; i < 128; ++i) {
env->SetObjectArrayElement(array, i, newMyClass(i));
}
env->PopLocalFrame(NULL); // Error: should pass 'array'.
return array; // Error: array is no longer valid.
}

The fix is generally to pass the reference to PopLocalFrame(). Note in the above example that you don’t need to keep references to the individual array elements; as long as the GC knows about the array itself, it’ll take care of the elements (and any objects they point to in turn) itself.

If you do have this class of error in your code, the crash will look something like this:

  JNI ERROR (app bug): accessed stale local reference 0x2d00025 (index 9 in a table of size 8)
JNI WARNING: invalid reference returned from native code
in LMyClass;.returnArray:()[Ljava/lang/Object;

Wrapping up

Yes, we asking for a bit more attention to detail in your JNI coding, which is extra work. But we think that you’ll come out ahead on the deal as we roll in better and more sophisticated memory management code.

Tuesday, 1 November 2011

Android 4.0 Graphics and Animations

[This post is by Romain Guy and Chet Haase, Android engineers who have been known to collaborate on the subject of graphics, UIs, and animation. You can read more from them on their blogs at curious-creature.org and graphics-geek.blogspot.com. — Tim Bray]

Earlier this year, Android 3.0 launched with a new 2D rendering pipeline designed to support hardware acceleration on tablets. With this new pipeline, all drawing operations performed by the UI toolkit are carried out using the GPU.

You’ll be happy to hear that Android 4.0, Ice Cream Sandwich, brings an improved version of the hardware-accelerated 2D rendering pipeline to phones, starting with Galaxy Nexus.

Enabling hardware acceleration

In Android 4.0 (API level 14), hardware acceleration, for the first time, is on by default for all applications. For applications at lower API levels, you can turn it on by adding android:hardwareAccelerated="true" to the <application> tag in your AndroidManifest.xml.

To learn more about the hardware accelerated 2D rendering pipeline visit the official Android developer guide. This guide explains how to control hardware acceleration at various levels, offers several performance tips and tricks and describes in details the new drawing model.

I also encourage you to watch the Android Hardware Accelerated Rendering talk that we gave at Google I/O 2011.

Introducing TextureView

Applications that need to display OpenGL or video content rely today on a special type of UI element called SurfaceView. This widget works by creating a new window placed behind your application’s window. It then punches a hole through your application’s window to reveal the new window. While this approach is very efficient, since the content of the new window can be refreshed without redrawing the application’s window, it suffers from several important limitations.

Because a SurfaceView’s content does not live in the application’s window, it cannot be transformed (moved, scaled, rotated) efficiently. This makes it difficult to use a SurfaceView inside a ListView or a ScrollView. SurfaceView also cannot interact properly with some features of the UI toolkit such as fading edges or View.setAlpha().

To solve these problems, Android 4.0 introduces a new widget called TextureView that relies on the hardware accelerated 2D rendering pipeline and SurfaceTexture. TextureView offers the same capabilities as SurfaceView but, unlike SurfaceView, behaves as a regular view. You can for instance use a TextureView to display an OpenGL scene or a video stream. The TextureView itself can be animated, scrolled, etc.

The following piece of code creates a TextureView to display the video preview from the default camera. The TextureView itself is rotated 45 degrees and semi-transparent.

public class TextureViewActivity extends Activity implements TextureView.SurfaceTextureListener {
private Camera mCamera;
private TextureView mTextureView;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

mTextureView = new TextureView(this);
mTextureView.setSurfaceTextureListener(this);

setContentView(mTextureView);
}

@Override
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
mCamera = Camera.open();

Camera.Size previewSize = mCamera.getParameters().getPreviewSize();
mTextureView.setLayoutParams(new FrameLayout.LayoutParams(
previewSize.width, previewSize.height, Gravity.CENTER));

try {
mCamera.setPreviewTexture(surface);
} catch (IOException t) {
}

mCamera.startPreview();

mTextureView.setAlpha(0.5f);
mTextureView.setRotation(45.0f);
}

@Override
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
// Ignored, the Camera does all the work for us
}

@Override
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
mCamera.stopPreview();
mCamera.release();
return true;
}

@Override
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
// Called whenever a new frame is available and displayed in the TextureView
}
}

A TextureView can just as easily be used to embed an OpenGL scene in your application. As of Android 4.0, eglCreateWindowSurface() can be used to render into a SurfaceTexture object.

Animation

There were minor improvements in Android 4.0 to some of the new animation facilities that were added in the 3.x releases.

First, if you're new to the new android.animation package and classes added in 3.0 and 3.1, you might want to read Animation in Honeycomb and Introducing ViewPropertyAnimator. These articles discuss the new APIs added in 3.0 that make animation in Android easier, more powerful, and more flexible. The Android 4.0 improvements discussed below are small additions to these core facilities.

Properties

One of the constraints of the Java programming language is the lack of “properties”. There is no way to refer generically to a field or a setter/getter of an object. As long as you know what kind of object you have, this is not a problem, because you then know the set of fields and methods that you can call. But if someone passes you some subclass of Object and you'd like to get or set some value “foo” on it, you're out of luck. You can use reflection or JNI to get access to the foo field/methods, but there is no way to refer directly to a field or a method unless you know the instance type of the object that has that field/method on it.

This is a constraint that the new animation system works within. Its whole job, you might say, is to get and set values on generic objects that it's been told about. If someone wants to animate the alpha property on a View, they tell the system the target object and the name of that field (“alpha”), and the animation system uses JNI to figure out which method(s) act on a field of that name. Basically, it looks for setAlpha() and, sometimes, getAlpha() methods. Then when an animation frame occurs, it calculates the new value and passes it into the setter method that it found.

This seems like a lot of work for what it does, but there's really no way around it. Unless the animation system were specific to View objects, there's no way that it could know that the target object has appropriate setter/getter methods. And even if it did, there's still no way for callers that construct the animations to tell the animator about the property named “alpha”; there are no function handles like there are in other languages, and there's no way to reference a public field either. (I'm ignoring Reflection here, which has Method and Field objects, because this approach requires much more overhead and processing than the simple function/field references of other languages).

If only there were a way to refer to these properties and to get/set them on generic objects...

Now there is. There is a new Property object in the android.util package that does exactly this. This class offers a set() and a get() method. So if someone hands you a Property object, you can safely call the set() and get() methods without knowing anything about the target object and it will do the job. Moreover, it will do it much more efficiently than the current JNI or reflection approaches because it can, depending on the implementation of it, set a field or call a method on the target object directly. For example, the new ALPHA property on View calls setAlpha() on the View object.

The Property class is a generic utility that can be used anywhere, not just in animations. But it's animations that benefit enormously from it, in their ability to handle properties in a type-safe and efficient manner.

For example prior to Android 4.0, you might construct a fade-out animation on some object myView like this:

ObjectAnimator anim = ObjectAnimator.ofFloat(myView, "alpha", 0);

In Android 4.0, you can use the new ALPHA object on View to construct a Property-based animator instead:

ObjectAnimator anim = ObjectAnimator.ofFloat(myView, View.ALPHA, 0);

ViewPropertyAnimator Additions

There were minor API additions to the ViewPropertyAnimator class (introduced in Android 3.1) which make this class more flexible and powerful:

  • cancel(): You can now cancel() a running ViewPropertyAnimator.


  • setStartDelay(): You can now set a startDelay on the ViewPropertyAnimator, just like the startDelay of the other Animator classes.


  • start(): ViewPropertyAnimators start automatically, but they do so on the next animation frame handled. This allows them to collect several requests and bundle them together, which is much more efficient and makes it easier to synchronize multiple animations together. However, if you just want to run a single animation, or want to make sure it starts immediately, at the time of construction, you can call start() to avoid that intervening delay.


LayoutTransition

LayoutTransition (introduced in Android 3.0) continues to provide functionality that makes some kinds of animations easier, specifically when adding, removing, hiding, and showing views. For example, either this snippet in a layout file:

<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:id="@+id/container">

Or this code added at runtime:

 container.setLayoutTransition(new LayoutTransition());

will result in a container that animates the visibility of its children views. So when a view is added to the container, the other children will animate out of the way and then the new one will fade in. Similarly, removing a child from the container will fade it out and then animate the other children around to their final places and sizes.

You can customize the animations and timing behavior of a LayoutTransition object, but the code above allows a very easy way to get reasonable default animation behavior.

One of the constraints in the pre-4.0 version of the class was that it did not account for changes in the bounds of the parent hierarchy. So, for example, if a LinearLayout with horizontal orientation has a layout_width of wrap_content and you want to run a transition that removes an item from that layout, then you might notice the parent snapping to the end size and clipping its children instead of animating all of them into their new positions. The new approach (enabled by default, but disabled by a call to setAnimateParentHierarchy(false)) also animates the layout bounds and scrolling values of the parent layout and its parents, all the way up the view hierarchy. This allows LayoutTransition to account for all layout-related changes due to that view being added or removed from its transitioning container.

Conclusion

The Android 3.0 release saw huge improvements in the visual capabilities of the platform, as we started enabling hardware acceleration and providing new, more flexible animation capabilities. Android 4.0 continues this trend as we continue to work hard on improving the performance, features, and usability of the Android APIs. We’re not done yet, but the enhancements in this release should help you create more exciting Android experiences and applications.

Wednesday, 26 October 2011

Introducing Android WebDriver

[This post is by Dounia Berrada, an engineer on the EngTools team. — Tim Bray]

Selenium WebDriver is a browser automation tool which provides a lightweight and elegant way for testing web apps. Selenium WebDriver is now available as an SDK extra in the Android SDK, and supports 2.3 (Gingerbread) and onwards!

Whether or not your site is optimized for mobile browsers, you can be sure that users will be accessing it from their phones and tablets. WebDriver makes it easy to write automated tests that ensure your site works correctly when viewed from the Android browser. We’ll walk you through some basics about WebDriver and look at it in action.

WebDriver Basics

WebDriver tests are end-to-end tests that exercise the web application just like a real user would. WebDriver models user interactions with a web page such as finger flicks, finger scrolls and long presses. It can rotate the display and interact with HTML5 features such as local storage, session storage and the application cache. Those tests run as part of an Android tests project and are based on Junit. They can be launched from Eclipse or the command line. WebDriver tests can be wired with a continuous integration system and can run on phone and tablet emulators or real devices. Once the test starts, WebDriver opens a WebView configured like the Android browser and runs the tests against it.

WebDriver is an Android SDK extra and can be installed following these instructions. Once you’ve done that you’ll be ready to write tests! There is a comprehensive WebDriver user guide on the Selenium site, but let’s start with a basic example using www.google.com to give you a taste of what’s possible.

Getting Started

First, create an Android project containing an empty activity with no layout.

public class SimpleAppActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
}

Then create the Android test project that will contain the tests. WebDriver will create the WebView and set the layout automatically in the main Activity.

Let’s write a test that opens the Google home page on Android and issues a query for “weather in San Francisco”. The test will verify that Google returns search results, and that the first result returned is giving the weather in San Francisco.

public class SimpleGoogleTest extends ActivityInstrumentationTestCase2<SimpleAppActivity> {

public void testGoogleShouldWork() {
// Create a WebDriver instance with the activity in which we want the test to run
WebDriver driver = new AndroidDriver(getActivity());
// Let’s open a web page
driver.get("http://www.google.com");

// Lookup for the search box by its name
WebElement searchBox = driver.findElement(By.name("q"));

// Enter a search query and submit
searchBox.sendKeys("weather in san francisco");
searchBox.submit();

// Making sure that Google shows 11 results
WebElement resultSection = driver.findElement(By.id("ires"));
List<WebElement> searchResults = resultSection.findElements(By.tagName("li"));
assertEquals(11, searchResults.size());

// Let’s ensure that the first result shown is the weather widget
WebElement weatherWidget = searchResults.get(0);
assertTrue(weatherWidget.getText().contains("Weather for San Francisco, CA"));
}
}

Now let’s see our test in action! WebDriver will create a WebView with the same configuration as the Android browser in the main UI thread, i.e. the activity thread. The activity will display the WebView on the screen, allowing you to see your web application as the test code is executing.

Interaction Testing

We’ve mentioned that WebDriver supports creating advanced gestures to interact with the device. Let’s use WebDriver to throw an image across the screen by flicking horizontally, and ensure that the next image in the gallery is displayed.

WebElement toFlick = driver.findElement(By.id("image"));
// 400 pixels left at normal speed
Action flick = getBuilder(driver).flick(toFlick, 0, -400, FlickAction.SPEED_NORMAL)
.build();
flick.perform();
WebElement secondImage = driver.findElement(“secondImage”);
assertTrue(secondImage.isDisplayed());

Now, let’s rotate the screen and ensure that the image displayed on screen is resized.

assertEquals(landscapeSize, secondImage.getSize())
((Rotatable) driver).rotate(ScreenOrientation.PORTRAIT);
assertEquals(portraitSize, secondImage.getSize());

What if your test reveals a bug? You can easily take a screenshot for help in future debugging:

File tempFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);

Find Out More

If this has whetted your appetite and you’d like to know more, go ahead and install the Android WebDriver, take a look at the documentation on the Selenium project’s wiki, or just browse the javadocs. For questions and feedback not only of the Android WebDriver but also its desktop brethren, please join webdriver@googlegroups.com. For announcements keep an eye on http://seleniumhq.wordpress.com/.

Tuesday, 25 October 2011

Changes to Library Projects in Android SDK Tools, r14

Last week, we released the SDK for Android 4.0 and a new set of developer tools, now in revision 14. The updated tools include a lot of build changes, many that improve build performance. Also included is an under-the-hood change in how libraries are used by main projects — a first step in improving library support and code reusability. While the change should have little impact on existing projects, some developers have had issues when migrating to the updated tools. Please read below for more information about the change to library projects and how to solve migration issues.

Previously, library projects were handled as extra resource and source code folders to be used when compiling the resources and the application’s source respectively. While this worked fine for most cases, there were two issues.

1. Developers asked us for the ability to distribute a library as a single jar file that included both compiled code and resources. The nature of Android resources, with their compiled IDs prevented this.

2. The implementation of the library projects was extremely fragile in Eclipse. Adding extra source folders outside of the project folders is non-trivial when it needs to be handled automatically, in a way that doesn’t expose a user’s local installation path (which is required for people working in teams through a source control system such as SVN or git).

For r14, we decided to fix both issues at once, by moving to a compiled-code based library mechanism. This solves the implementation fragility in Eclipse and will allow us to, later, enable distribution of libraries as a single jar file.

As you might have seen in the release notes, moving to this new mechanism can affect existing projects in some cases, but there are simple fixes.

The first impact of this change is that the new library project requires the resource IDs generated by libraries to be non final. This prevents the Java compiler from inlining the values in the library code, and therefore prevents usage of the switch statement in the library code. To address such occurrences in your code, Eclipse provides a refactoring action to convert from switch statements to if/else (see here).

Second, some projects may not have been properly migrated to the new mechanism, resulting in projects that fail to compile, with errors such as duplicated classes being added in the dex build step. ADT 14 should have migrated older projects to the new mechanism but the fragility of the old mechanism may have prevented it from happening. This makes projects reference the libraries twice, using both the old and new mechanisms, which then triggers the libraries classes being packaged twice. If you see this in your projects, look in the Package Explorer for extraneous source folders named with the pattern <libraryname>_src. The screenshot to the right shows an example of this.

To fix the project, you must remove the extraneous source folders with the following steps:

  • Right click source folder and choose Build Path > Remove from Build path
  • A dialog will pop up. In it, make sure to check “Also unlink the folder from the project” to completely remove the folder.

With this change to library projects, we pave the way to better support for reusable components. We will continue working to make components easier to create, work with, and manage. Our goal is to make it easy for developers to create apps with great user experiences that easily adapt to all form factors.

Some developers have also told us that they only use library projects internally, that they don’t need to distribute binary versions and would prefer to continue with a source-based mechanism. We are investigating how we could support this alongside the new mechanism.

Finally, I wanted to point out that we are tracking a few known issues (and workaround for them) in the current r14 tools at this page: http://tools.android.com/knownissues.

We are working on a tools update that will include fixes for most of these. We are hoping to have it out shortly.

Thursday, 20 October 2011

New Public APIs in ICS

Since Android is open-source, anyone can look at the code and see how it works inside. If you do this, you’ll notice that most but not all of the APIs are publicly documented.

If they’re publicly documented, they’re part of what we consider the Android Application Framework. This means their tests appear in the Compatibility Test Suite (CTS) so that our hardware partners have to prove that the APIs work, and that we promise to try very hard not to change them and thus break your code.

In almost every case, there’s only one reason for leaving APIs undocumented: We’re not sure that what we have now is the best solution, and we think we might have to improve it, and we’re not prepared to make those commitments to testing and preservation.

We’re not claiming that they’re “Private” or “Secret” — How could they be, when anyone in the world can discover them? We’re also not claiming they’re forbidden: If you use them, your code will compile and probably run. And in fact we know of quite a few apps out there whose developers have used undocumented APIs, often to good effect. It’s hard to get too upset about this in cases where there’s a useful API that we haven’t gotten around to stabilizing.

But the developers who use those APIs have to be prepared to deal with the situation that arises when we move them from the undocumented outside into the Android Application Framework. Fortunately, this is reasonably straightforward. Also we take a close look at Android Market, using our in-house analytics tools, to get a feel for the impact when we know one of these changes is coming.

There are a few such changes coming up in the Android 4.0 “Ice Cream Sandwich” (ICS) release of Android. We wanted to take the opportunity to combine these words on undocumented APIs with some specifics about the changes.

Calendars

Let’s start with the good news: As of ICS, the Android Framework will include a fully-worked-out set of APIs for accessing Calendar data. You can guess the bad news: Quite a few developers have built apps (including many good ones) using the undocumented Calendar APIs, some using fairly low-level access to the calendar database. Unfortunately, these integrations were unsupported, and prone to breakage by platform updates or OEM customization of calendar features.

We want to see lots of good calendar apps and extensions that work reliably across Android devices, and aren't broken by platform updates. So we decided to create a clean API, including a comprehensive set of Intents, to manage calendar data in ICS. Now anyone can code against these new APIs and know that Android is committed to supporting them, and that partners have to support these APIs as part of CTS.

Once the new APIs arrive, you’re going to have to update your apps before they’ll run correctly on ICS while still working on older releases. There are a variety of techniques for doing that, many of which have been featured on this blog, including reflection and lazy loading. Recently, we introduced Multiple-APK support, which could also be used to help with this sort of transition.

Text To Speech

Android has never really had a text-to-speech API at the Framework level, but there was unofficial access at the C++ level. With ICS, we will have a fully-thought-through application-level API running on Dalvik, so you can access it with ordinary Java-language application code.

The old C++ API will no longer be supported, but we’ll have a compatibility layer that you can use to bridge from it to the new API. We think it should be easy to update for ICS with very little work.

Doing the Right Thing

We recognize that this means some work for developers affected by these changes, but we’re confident that Android programs in general, and both Calendar and TTS apps in particular, will come out ahead. And we also think that most developers know that when they use undocumented APIs, they’re making a commitment to doing the right thing when those APIs change.

Followers