Thursday, 23 June 2011

A Deep Dive Into Location

[This post is by Reto Meier, Tech Lead for Android Developer Relations, who wrote the book on Android App development. — Tim Bray]

I'm a big fan of location-based apps, but not their seemingly-inevitable startup latency.

Whether it's finding a place to eat or searching for the nearest Boris Bike, I find the delay while waiting for the GPS to get a fix, and then for the results list to populate, to be interminable. Once I’m in a venue and ready to get some tips, check-in, or review the food, I’m frequently thwarted by a lack of data connection.

Rather than shaking my fist at the sky, I’ve written an open-source reference app that incorporates all of the tips, tricks, and cheats I know to reduce the time between opening an app and seeing an up-to-date list of nearby venues - as well as providing a reasonable level of offline support — all while keeping the impact on battery life to a minimum.

Show Me the Code

You can check-out the Android Protips for Location open source project from Google Code. Don’t forget to read the Readme.txt for the steps required to make it compile and run successfully.

What Does it Actually Do?

It uses the Google Places API to implement the core functionality of apps that use location to provide a list of nearby points of interest, drill down into their details, and then check-in/rate/review them.

The code implements many of the best-practices I detailed in my Google I/O 2011 session, Android Protips: Advanced Topics for Expert Android Developers (video), including using Intents to receive location updates, using the Passive Location Provider, using and monitoring device state to vary refresh rates, toggling your manifest Receivers at runtime, and using the Cursor Loader.

The app targets Honeycomb but supports Android platforms from 1.6 and up.

Nothing would make me happier than for you to cut/copy/borrow / steal this code to build better location-based apps. If you do, I’d love it if you told me about it!

Now that you’ve got the code, let’s take a closer look at it

My top priority was freshness: Minimize the latency between opening the app and being able to check in to a desired location, while still minimizing the impact of the app on battery life.

Related requirements:

  • The current location has to be found as quickly as possible.


  • The list of venues should update when the location changes.


  • The list of nearby locations and their details must be available when we’re offline.


  • Check-ins must be possible while we’re offline.


  • Location data and other user data must be handled properly (see our prior blog post on best practices).


Freshness means never having to wait

You can significantly reduce the latency for getting your first location fix by retrieving the last known location from the Location Manager each time the app is resumed.

In this snippet taken from the GingerbreadLastLocationFinder, we iterate through each location provider on the device — including those that aren't currently available — to find the most timely and accurate last known location.

List<String> matchingProviders = locationManager.getAllProviders();
for (String provider: matchingProviders) {
Location location = locationManager.getLastKnownLocation(provider);
if (location != null) {
float accuracy = location.getAccuracy();
long time = location.getTime();

if ((time > minTime && accuracy < bestAccuracy)) {
bestResult = location;
bestAccuracy = accuracy;
bestTime = time;
}
else if (time < minTime &&
bestAccuracy == Float.MAX_VALUE && time > bestTime){
bestResult = location;
bestTime = time;
}
}
}

If there is one or more locations available from within the allowed latency, we return the most accurate one. If not, we simply return the most recent result.

In the latter case (where it’s determined that the last location update isn't recent enough) this newest result is still returned, but we also request a single location update using that fastest location provider available.

if (locationListener != null &&
(bestTime < maxTime || bestAccuracy > maxDistance)) {
IntentFilter locIntentFilter = new IntentFilter(SINGLE_LOCATION_UPDATE_ACTION);
context.registerReceiver(singleUpdateReceiver, locIntentFilter);
locationManager.requestSingleUpdate(criteria, singleUpatePI);
}

Unfortunately we can’t specify “fastest” when using Criteria to choose a location provider, but in practice we know that coarser providers — particularly the network location provider — tend to return results faster than the more accurate options. In this case I’ve requested coarse accuracy and low power in order to select the Network Provider when it’s available.

Note also that this code snippet shows the GingerbreadLastLocationFinder which uses the requestSingleUpdate method to receive a one-shot location update. This wasn’t available prior to Gingerbread - check out the LegacyLastLocationFinder to see how I have implemented the same functionality for devices running earlier platform versions.

The singleUpdateReceiver passes the received update back to the calling class through a registered Location Listener.

protected BroadcastReceiver singleUpdateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
context.unregisterReceiver(singleUpdateReceiver);

String key = LocationManager.KEY_LOCATION_CHANGED;
Location location = (Location)intent.getExtras().get(key);

if (locationListener != null && location != null)
locationListener.onLocationChanged(location);

locationManager.removeUpdates(singleUpatePI);
}
};

Use Intents to receive location updates

Having obtained the most accurate/timely estimate of our current location, we also want to receive location updates.

The PlacesConstants class includes a number of values that determine the frequency of location updates (and the associated server polling). Tweak them to ensure that updates occur exactly as often as required.

// The default search radius when searching for places nearby.
public static int DEFAULT_RADIUS = 150;
// The maximum distance the user should travel between location updates.
public static int MAX_DISTANCE = DEFAULT_RADIUS/2;
// The maximum time that should pass before the user gets a location update.
public static long MAX_TIME = AlarmManager.INTERVAL_FIFTEEN_MINUTES;

The next step is to request the location updates from the Location Manager. In this snippet taken from the GingerbreadLocationUpdateRequester we can pass the Criteria used to determine which Location Provider to request updates from directly into the requestLocationUpdates call.

public void requestLocationUpdates(long minTime, long minDistance, 
Criteria criteria, PendingIntent pendingIntent) {

locationManager.requestLocationUpdates(minTime, minDistance,
criteria, pendingIntent);
}

Note that we're passing in a Pending Intent rather than a Location Listener.

Intent activeIntent = new Intent(this, LocationChangedReceiver.class);
locationListenerPendingIntent =
PendingIntent.getBroadcast(this, 0, activeIntent, PendingIntent.FLAG_UPDATE_CURRENT);

I generally prefer this over using Location Listeners as it offers the flexibility of registering receivers in multiple Activities or Services, or directly in the manifest.

In this app, a new location means an updated list of nearby venues. This happens via a Service that makes a server query and updates the Content Provider that populates the place list.

Because the location change isn’t directly updating the UI, it makes sense to create and register the associated LocationChangedReceiver in the manifest rather than the main Activity.

<receiver android:name=".receivers.LocationChangedReceiver"/>

The Location Changed Receiver extracts the location from each update and starts the PlaceUpdateService to refresh the database of nearby locations.

if (intent.hasExtra(locationKey)) {
Location location = (Location)intent.getExtras().get(locationKey);
Log.d(TAG, "Actively Updating place list");
Intent updateServiceIntent =
new Intent(context, PlacesConstants.SUPPORTS_ECLAIR ? EclairPlacesUpdateService.class : PlacesUpdateService.class);
updateServiceIntent.putExtra(PlacesConstants.EXTRA_KEY_LOCATION, location);
updateServiceIntent.putExtra(PlacesConstants.EXTRA_KEY_RADIUS, PlacesConstants.DEFAULT_RADIUS);
updateServiceIntent.putExtra(PlacesConstants.EXTRA_KEY_FORCEREFRESH, true);

context.startService(updateServiceIntent);
}

Monitor inactive providers for a better option

The snippet from PlacesActivity below shows how to monitor two important conditions:

  • The Location Provider we are using being deactivated.


  • A better Location Provider becoming available.


In either case, we simply re-run the process used to determine the best available provider and request location updates.

// Register a receiver that listens for when the provider I'm using has been disabled. 
IntentFilter intentFilter = new IntentFilter(PlacesConstants.ACTIVE_LOCATION_UPDATE_PROVIDER_DISABLED);
registerReceiver(locProviderDisabledReceiver, intentFilter);

// Listen for a better provider becoming available.
String bestProvider = locationManager.getBestProvider(criteria, false);
String bestAvailableProvider = locationManager.getBestProvider(criteria, true);
if (bestProvider != null && !bestProvider.equals(bestAvailableProvider))
locationManager.requestLocationUpdates(bestProvider, 0, 0,
bestInactiveLocationProviderListener, getMainLooper());

Freshness means always being up to date. What if we could reduce startup latency to zero?

You can start the PlacesUpdateService in the background to refresh the list of nearby locations while your app is in the background. Done correctly, a relevant list of venues can be immediately available when you open the app.

Done poorly, your users will never find this out as you’ll have drained their battery too quickly.

Requesting location updates (particularly using the GPS) while your app isn’t in the foreground is poor practice, as it can significantly impact battery life. Instead, you can use the Passive Location Provider to receive location updates alongside other apps that have already requested them.

This extract from the FroyoLocationUpdateRequester enables passive updates on Froyo+ platforms.

public void requestPassiveLocationUpdates(long minTime, long minDistance, PendingIntent pendingIntent) {
locationManager.requestLocationUpdates(LocationManager.PASSIVE_PROVIDER,
PlacesConstants.MAX_TIME, PlacesConstants.MAX_DISTANCE, pendingIntent);
}

As a result receiving background location updates is effectively free! Unfortunately the battery cost of your server downloads aren’t, so you’ll still need to carefully balance how often you act on passive location updates with battery life.

You can achieve a similar effect in pre-Froyo devices using inexact repeating non-wake alarms as shown in the LegacyLocationUpdateRequester.

public void requestPassiveLocationUpdates(long minTime, long minDistance, 
PendingIntent pendingIntent) {

alarmManager.setInexactRepeating(AlarmManager.ELAPSED_REALTIME,
System.currentTimeMillis()+PlacesConstants.MAX_TIME,
PlacesConstants.MAX_TIME, pendingIntent);
}

Rather than receiving updates from the Location Manager, this technique manually checks the last known location at a frequency determined by the maximum location update latency.

This legacy technique is significantly less efficient, so you may choose to simply disable background updates on pre-Froyo devices.

We handle updates themselves within the PassiveLocationChangedReceiver which determines the current location and starts the PlaceUpdateService.

if (location != null) {
Intent updateServiceIntent =
new Intent(context, PlacesConstants.SUPPORTS_ECLAIR ? EclairPlacesUpdateService.class : PlacesUpdateService.class);

updateServiceIntent.putExtra(PlacesConstants.EXTRA_KEY_LOCATION, location);
updateServiceIntent.putExtra(PlacesConstants.EXTRA_KEY_RADIUS,
PlacesConstants.DEFAULT_RADIUS);
updateServiceIntent.putExtra(PlacesConstants.EXTRA_KEY_FORCEREFRESH, false);
context.startService(updateServiceIntent);
}

Using Intents to passively receive location updates when your app isn't active

You’ll note that we registered the Passive Location Changed Receiver in the application manifest.

<receiver android:name=".receivers.PassiveLocationChangedReceiver"/>

As a result we can continue to receive these background updates even when the application has been killed by the system to free resources.

This offers the significant advantage of allowing the system to reclaim the resources used by your app, while still retaining the advantages of a zero latency startup.

If your app recognizes the concept of “exiting” (typically when the user clicks the back button on your home screen), it’s good form to turn off passive location updates - including disabling your passive manifest Receiver.

Being fresh means working offline

To add offline support we start by caching all our lookup results to the PlacesContentProvider and PlaceDetailsContentProvider.

Under certain circumstances we will also pre-fetch location details. This snippet from the PlacesUpdateService shows how pre-fetching is enabled for a limited number of locations.

Note that pre-fetching is also potentially disabled while on mobile data networks or when the battery is low.

if ((prefetchCount < PlacesConstants.PREFETCH_LIMIT) &&
(!PlacesConstants.PREFETCH_ON_WIFI_ONLY || !mobileData) &&
(!PlacesConstants.DISABLE_PREFETCH_ON_LOW_BATTERY || !lowBattery)) {
prefetchCount++;

// Start the PlaceDetailsUpdateService to prefetch the details for this place.
}

We use a similar technique to provide support for offline checkins. The PlaceCheckinService queues failed checkins, and checkins attempted while offline, to be retried (in order) when the ConnectivityChangedReceiver determines that we’re back online.

Optimizing battery life: Smart Services and using device state to toggle your manifest Receivers

There's no point running update services when we aren’t online, so the PlaceUpdateService checks for connectivity before attempting an update.

NetworkInfo activeNetwork = cm.getActiveNetworkInfo();
boolean isConnected = activeNetwork != null &&
activeNetwork.isConnectedOrConnecting();

If we’re not connected, the Passive and Active Location Changed Receivers are disabled and the the ConnectivityChangedReceiver is turned on.

ComponentName connectivityReceiver = 
new ComponentName(this, ConnectivityChangedReceiver.class);
ComponentName locationReceiver =
new ComponentName(this, LocationChangedReceiver.class);
ComponentName passiveLocationReceiver =
new ComponentName(this, PassiveLocationChangedReceiver.class);

pm.setComponentEnabledSetting(connectivityReceiver,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP);

pm.setComponentEnabledSetting(locationReceiver,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);

pm.setComponentEnabledSetting(passiveLocationReceiver,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP);

The ConnectivityChangedReceiver listens for connectivity changes. When a new connection is made, it simply disables itself and re-enables the location listeners.

Monitoring battery state to reduce functionality and save power

When your phone is on its last 15%, most apps are firmly in the back seat to conserving what watts you have remaining. We can register manifest Receivers to be alerted when the device enters or leaves the low battery state.

<receiver android:name=".receivers.PowerStateChangedReceiver">
<intent-filter>
<action android:name="android.intent.action.ACTION_BATTERY_LOW"/>
<action android:name="android.intent.action.ACTION_BATTERY_OKAY"/>
</intent-filter>
</receiver>

This snippet from the PowerStateChangedReceiver disables the PassiveLocationChangedReceiver whenever the device enters a low battery state, and turns it back on once the battery level is okay.

boolean batteryLow = intent.getAction().equals(Intent.ACTION_BATTERY_LOW);

pm.setComponentEnabledSetting(passiveLocationReceiver,
batteryLow ? PackageManager.COMPONENT_ENABLED_STATE_DISABLED :
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
PackageManager.DONT_KILL_APP);

You can extend this logic to disable all prefetching or reduce the frequency of your updates during low battery conditions.

What’s Next?

This is already a monster post, so I’m going to leave it there. I’ll follow up in the next week with a post on my personal blog, The Radioactive Yak, that will go in to more detail on the psychic and smooth elements of this app like using the Backup Manager and the Cursor Loader.

I also plan to build a similar reference app for news apps, so that I can spend more time reading and less time waiting.

In the mean time, happy coding!

Monday, 20 June 2011

Things That Cannot Change

[This post is by Dianne Hackborn, whose fingerprints can be found all over the Android Application Framework — Tim Bray]

Sometimes a developer will make a change to an application that has surprising results when installed as an update to a previous version — shortcuts break, widgets disappear, or it can’t even be installed at all. There are certain parts of an application that are immutable once you publish it, and you can avoid surprises by understanding them.

Your package name and certificate

The most obvious and visible of these is the “manifest package name,” the unique name you give to your application in its AndroidManifest.xml. The name uses a Java-language-style naming convention, with Internet domain ownership helping to avoid name collisions. For example, since Google owns the domain “google.com”, the manifest package names of all of our applications should start with “com.google.” It’s important for developers to follow this convention in order to avoid conflicts with other developers.

Once you publish your application under its manifest package name, this is the unique identity of the application forever more. Switching to a different name results in an entirely new application, one that can’t be installed as an update to the existing application.

Just as important as the manifest package name is the certificate that application is signed with. The signing certificate represents the author of the application. If you change the certificate an application is signed with, it is now a different application because it comes from a different author. This different application can’t be uploaded to Market as an update to the original application, nor can it be installed onto a device as an update.

The exact behavior the user sees when installing an application that has changed in one of these two ways is different:

  • If the manifest package name has changed, the new application will be installed alongside the old application, so they both co-exist on the user’s device at the same time.

  • If the signing certificate changes, trying to install the new application on to the device will fail until the old version is uninstalled.

If you change the signing certificate of your application, you should always change its manifest package name as well to avoid failures when it’s installed. In other words, the application coming from a different author makes it a different application, and its package name should be changed appropriately to reflect that. (Of course it’s fine to use the same package name for the development builds of your app signed with your test keys, because these are not published.)

Your AndroidManifest.xml is a public API

More than just your package name that is immutable. A major function of the AndroidManifest.xml is essentially to declare a public API from your application for use by other applications and the Android system. Every component you declare in the manifest that is not private (that is whose android:exported state is true) should be treated as a public API and never changed in a way that breaks compatibility.

A subtle but important aspect of what constitutes a break in compatibility is the android:name attribute of your activity, service, and receiver components. This can be surprising because we think of android:name as pointing to the private code implementing our application, but it is also (in combination with the manifest package name) the official unique public name for that component, as represented by the ComponentName class.

Changing the component name inside of an application can have negative consequences for your users. Some examples are:

  • If the name of a main activity of your application is changed, any shortcuts the user made to it will no longer work. A shortcut is an Intent that directly specifies the ComponentName it should run.

  • If the name of a service implementing a Live Wallpaper changes, then a user who has enabled your Live Wallpaper will have their wallpaper revert to the system default when getting the new version of your app. The same is true for Input Methods, Accessibility Services, Honeycomb’s new advanced Widgets, and so on.

  • If the name of a receiver implementing a Device Admin changes, then as with the live wallpaper example, the device admin will be disabled when the application is updated. This also applies to other kinds of receivers, such as App Widgets.

These behaviors are an outcome of how the Intent system is used on Android. There are two main kinds of Intents:

  • Implicit Intents only specify “what” they should match, using actions, categories, data, MIME types, and so on. The exact components that they will find are only determined at run-time, by the Package Manager matching it against the current applications.

  • Explicit Intents specify a single explicit “who” they should match, through a ComponentName. Regardless of whatever else is in the Intent, it is only associated with the exact manifest package name and class name as given in its ComponentName.

Both of these types of Intents are important to how Android interacts with your application. A typical example of this is how users browse and select live wallpapers.

To let the user pick a live wallpaper, the first thing Android must do is show them a list of the available live wallpaper services. It does this by building an implicit Intent with the appropriate action for a live wallpaper and asking the Package Manager for all services that support this Intent. The result is then the list of live wallpapers shown to the user.

When the user actually selects a specific live wallpaper they want to use, however, Android now must build an explicit Intent that identifies that particular live wallpaper. This is what is handed to the WallpaperManager to tell it which wallpaper to show.

This is why changing the name of the component in your manifest will cause the wallpaper to disappear: the explicit Intent that was previously saved is now invalid because the ComponentName it references no longer exists. There is no information available to indicate what the new name of the component is. (For example consider if your application had two different live wallpaper services the user could select.) Instead, Android must treat that live wallpaper as uninstalled and revert to its default wallpaper.

This is how input methods, device administrators, account managers, app widgets, and even application shortcuts work. The ComponentName is the public unique name of the components you declare in your manifest, and must not change if they are visible to other applications.

In conclusion: There are some parts of your application that can not change. Please be careful.

Monday, 6 June 2011

New Editing Features in Eclipse plug-in for Android

At the Google I/O conference a month ago, we demonstrated the next version of the Android Development Tools (ADT) plugin. Today we’re happy to announce that version 11 is done and available for download!

ADT 11 focuses on editor improvements. First, it offers several new visual refactoring operations, such as “Extract Include” and “Extract Style,” which help automatically extract duplicated layout fragments and style attributes into reusable layouts, styles, and themes.

Second, the visual layout editor now supports fragments, palette configurations, and improved support for custom views.

Last, XML editing has been improved with new quick fixes, code completion in more file types and many “go to declaration” enhancements.

ADT 11 packs a long list of new features and enhancements. Please visit our ADT page for more details. For an in-depth demo, check out the video of our Android Development Tools session at Google I/O, below.

Please note that the visual layout editor depends on a layout rendering library that ships with each version of the platform component in the SDK. We are currently working on a number of improvements to this library as well, which we plan to release soon for all platform versions. When we release the updates, some new features in ADT 11 will be “unlocked” - such as support for ListView previewing - so keep an eye on this blog for further announcements.


Monday, 30 May 2011

Introducing ViewPropertyAnimator

[This post is by Chet Haase, an Android engineer who specializes in graphics and animation, and who occasionally posts videos and articles on these topics on his CodeDependent blog at graphics-geek.blogspot.com. — Tim Bray]

In an earlier article, Animation in Honeycomb, I talked about the new property animation system available as of Android 3.0. This new animation system makes it easy to animate any kind of property on any object, including the new properties added to the View class in 3.0. In the 3.1 release, we added a small utility class that makes animating these properties even easier.

First, if you’re not familiar with the new View properties such as alpha and translationX, it might help for you to review the section in that earlier article that discusses these properties entitled, rather cleverly, “View properties”. Go ahead and read that now; I’ll wait.

Okay, ready?

Refresher: Using ObjectAnimator

Using the ObjectAnimator class in 3.0, you could animate one of the View properties with a small bit of code. You create the Animator, set any optional properties such as the duration or repetition attributes, and start it. For example, to fade an object called myView out, you would animate the alpha property like this:

    ObjectAnimator.ofFloat(myView, "alpha", 0f).start();

This is obviously not terribly difficult, either to do or to understand. You’re creating and starting an animator with information about the object being animated, the name of the property to be animated, and the value to which it’s animating. Easy stuff.

But it seemed that this could be improved upon. In particular, since the View properties will be very commonly animated, we could make some assumptions and introduce some API that makes animating these properties as simple and readable as possible. At the same time, we wanted to improve some of the performance characteristics of animations on these properties. This last point deserves some explanation, which is what the next paragraph is all about.

There are three aspects of performance that are worth improving about the 3.0 animation model on View properties. One of the elements concerns the mechanism by which we animate properties in a language that has no inherent concept of “properties”. The other performance issues relate to animating multiple properties. When fading out a View, you may only be animating the alpha property. But when a view is being moved on the screen, both the x and y (or translationX and translationY) properties may be animated in parallel. And there may be other situations in which several properties on a view are animated in parallel. There is a certain amount of overhead per property animation that could be combined if we knew that there were several properties being animated.

The Android runtime has no concept of “properties”, so ObjectAnimator uses a technique of turning a String denoting the name of a property into a call to a setter function on the target object. For example, the String “alpha” gets turned into a reference to the setAlpha() method on View. This function is called through either reflection or JNI, mechanisms which work reliably but have some overhead. But for objects and properties that we know, like these properties on View, we should be able to do something better. Given a little API and knowledge about each of the properties being animated, we can simply set the values directly on the object, without the overhead associated with reflection or JNI.

Another piece of overhead is the Animator itself. Although all animations share a single timing mechanism, and thus don’t multiply the overhead of processing timing events, they are separate objects that perform the same tasks for each of their properties. These tasks could be combined if we know ahead of time that we’re running a single animation on several properties. One way to do this in the existing system is to use PropertyValuesHolder. This class allows you to have a single Animator object that animates several properties together and saves on much of the per-Animator overhead. But this approach can lead to more code, complicating what is essentially a simple operation. The new approach allows us to combine several properties under one animation in a much simpler way to write and read.

Finally, each of these properties on View performs several operations to ensure proper invalidation of the object and its parent. For example, translating a View in x invalidates the position that it used to occupy and the position that it now occupies, to ensure that its parent redraws the areas appropriately. Similarly, translating in y invalidates the before and after positions of the view. If these properties are both being animated in parallel, there is duplication of effort since these invalidations could be combined if we had knowledge of the multiple properties being animated. ViewPropertyAnimator takes care of this.

Introducing: ViewPropertyAnimator

ViewPropertyAnimator provides a simple way to animate several properties in parallel, using a single Animator internally. And as it calculates animated values for the properties, it sets them directly on the target View and invalidates that object appropriately, in a much more efficient way than a normal ObjectAnimator could.

Enough chatter: let’s see some code. For the fading-out view example we saw before, you would do the following with ViewPropertyAnimator:

    myView.animate().alpha(0);

Nice. It’s short and it’s very readable. And it’s also easy to combine with other property animations. For example, we could move our view in x and y to (500, 500) as follows:

    myView.animate().x(500).y(500);

There are a couple of things worth noting about these commands:

  • animate(): The magic of the system begins with a call to the new method animate() on the View object. This returns an instance of ViewPropertyAnimator, on which other methods are called which set the animation properties.


  • Auto-start: Note that we didn’t actually start() the animations. In this new API, starting the animations is implicit. As soon as you’re done declaring them, they will all begin. Together. One subtle detail here is that they will actually wait until the next update from the UI toolkit event queue to start; this is the mechanism by which ViewPropertyAnimator collects all declared animations together. As long as you keep declaring animations, it will keep adding them to the list of animations to start on the next frame. As soon as you finish and then relinquish control of the UI thread, the event queue mechanism kicks in and the animations begin.


  • Fluent: ViewPropertyAnimator has a Fluent interface, which allows you to chain method calls together in a very natural way and issue a multi-property animation command as a single line of code. So all of the calls such as x() and y() return the ViewPropertyAnimator instance, on which you can chain other method calls.


You can see from this example that the code is much simpler and more readable. But where do the performance improvements of ViewPropertyAnimator come in?

Performance Anxiety

One of the performance wins of this new approach exists even in this simple example of animating the alpha property. ViewPropertyAnimator uses no reflection or JNI techniques; for example, the alpha() method in the example operates directly on the underlying "alpha" field of a View, once per animation frame.

The other performance wins of ViewPropertyAnimator come in the ability to combine multiple animations. Let’s take a look at another example for this.

When you move a view on the screen, you might animate both the x and y position of the object. For example, this animation moves myView to x/y values of 50 and 100:

    ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();

This code creates two separate animations and plays them together in an AnimatorSet. This means that there is the processing overhead of setting up the AnimatorSet and running two Animators in parallel to animate these x/y properties. There is an alternative approach using PropertyValuesHolder that you can use to combine multiple properties inside of one single Animator:

    PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();

This approach avoids the multiple-Animator overhead, and is the right way to do this prior to ViewPropertyAnimator. And the code isn’t too bad. But using ViewPropertyAnimator, it all gets easier:

    myView.animate().x(50f).y(100f);

The code, once again, is simpler and more readable. And it has the same single-Animator advantage of the PropertyValuesHolder approach above, since ViewPropertyAnimator runs one single Animator internally to animate all of the properties specified.

But there’s one other benefit of the ViewPropertyAnimator example above that’s not apparent from the code: it saves effort internally as it sets each of these properties. Normally, when the setX() and setY() functions are called on View, there is a certain amount of calculation and invalidation that occurs to ensure that the view hierarchy will redraw the correct region affected by the view that moved. ViewPropertyAnimator performs this calculation once per animation frame, instead of once per property. It sets the underlying x/y properties of View directly and performs the invalidation calculations once for x/y (and any other properties being animated) together, avoiding the per-property overhead necessitated by the ObjectAnimator property approach.

An Example

I finished this article, looked at it ... and was bored. Because, frankly, talking about visual effects really begs having some things to look at. The tricky thing is that screenshots don’t really work when you’re talking about animation. (“In this image, you see that the button is moving. Well, not actually moving, but it was when I captured the screenshot. Really.”) So I captured a video of a small demo application that I wrote, and will through the code for the demo here.

Here’s the video. Be sure to turn on your speakers before you start it. The audio is really the best part.

In the video, the buttons on the upper left (“Fade In”, “Fade Out”, etc.) are clicked one after the other, and you can see the effect that those button clicks have on the button at the bottom (“Animating Button”). All of those animations happen thanks to the ViewPropertyAnimator API (of course). I’ll walk through the code for each of the individual animations below.

When the activity first starts, the animations are set up to use a longer duration than the default. This is because I wanted the animations to last long enough in the video for you to see. Changing the default duration for the animatingButton object is a one-line operation to retrieve the ViewPropertyAnimator for the button and set its duration:

    animatingButton.animate().setDuration(2000);

The rest of the code is just a series of OnClickListenerobjects set up on each of the buttons to trigger its specific animation. I’ll put the complete listener in for the first animation below, but for the rest of them I’ll just put the inner code instead of the listener boilerplate.

The first animation in the video happens when the Fade Out button is clicked, which causes Animating Button to (you guessed it) fade out. Here’s the listener for the fadeOut button which performs this action:

    fadeOut.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
animatingButton.animate().alpha(0);
}
});

You can see, in this code, that we simply tell the object to animate to an alpha of 0. It starts from whatever the current alpha value is.

The next button performs a Fade In action, returning the button to an alpha value of 1 (fully opaque):

    animatingButton.animate().alpha(1);

The Move Over and Move Back buttons perform animations on two properties in parallel: x and y. This is done by chaining calls to those property methods in the animator call. For the Move Over button, we have the following:

    int xValue = container.getWidth() - animatingButton.getWidth();
int yValue = container.getHeight() - animatingButton.getHeight();
animatingButton.animate().x(xValue).y(yValue);

And for the Move Back case (where we just want to return the button to its original place at (0, 0) in its container), we have this code:

    animatingButton.animate().x(0).y(0);

One nuance to notice from the video is that, after the Move Over and Move Back animations were run, I then ran them again, clicking the Move Back animation while the Move Over animation was still executing. The second animation on the same properties (x and y) caused the first animation to cancel and the second animation to start from that point. This is an intentional part of the functionality of ViewPropertyAnimator. It takes your command to animate a property and, if necessary, cancels any ongoing animation on that property before starting the new animation.

Finally, we have the 3D rotation effect, where the button spins twice around the Y (vertical) axis. This is obviously a more complicated action and takes a great deal more code than the other animations (or not):

    animatingButton.animate().rotationYBy(720);

One important thing to notice in the rotation animations in the video is that they happen in parallel with part of the Move animations. That is, I clicked on the Move Over button, then the Rotate button. This caused the movement to stat, and then the Rotation to start while it was moving. Since each animation lasted for two seconds, the rotation animation finished after the movement animation was completed. Same thing on the return trip - the button was still spinning after it settled into place at (0, 0). This shows how independent animations (animations that are not grouped together on the animator at the same time) create a completely separate ObjectAnimator internally, allowing the animations to happen independently and in parallel.

Play with the demo some more, check out the code, and groove to the awesome soundtrack for 16.75. And if you want the code for this incredibly complex application (which really is nothing more than five OnClick listeners wrapping the animator code above), you can download it from here.

And so...

For the complete story on ViewPropertyAnimator, you might want to see the SDK documentation. First, there’s the animate() method in View. Second, there’s the ViewPropertyAnimator class itself. I’ve covered the basic functionality of that class in this article, but there are a few more methods in there, mostly around the various properties of View that it animates. Thirdly, there’s ... no, that’s it. Just the method in View and the ViewPropertyAnimator class itself.

ViewPropertyAnimator is not meant to be a replacement for the property animation APIs added in 3.0. Heck, we just added them! In fact, the animation capabilities added in 3.0 provide important plumbing for ViewPropertyAnimator as well as other animation capabilities in the system overall. And the capabilities of ObjectAnimator provide a very flexible and easy to use facility for animating, well, just about anything! But if you want to easily animate one of the standard properties on View and the more limited capabilities of the ViewPropertyAnimator API suit your needs, then it is worth considering.

Note: I don’t want to get you too worried about the overhead of ObjectAnimator; the overhead of reflection, JNI, or any of the rest of the animator process is quite small compared to what else is going on in your program. it’s just that the efficiencies of ViewPropertyAnimator offer some advantages when you are doing lots of View property animation in particular. But to me, the best part about the new API is the code that you write. It’s the best kind of API: concise and readable. Hopefully you agree and will start using ViewPropertyAnimator for your view property animation needs.

Friday, 20 May 2011

ADK at Maker Faire

This weekend is Maker Faire, and Google is all over it.

Following up on yesterday’s ADK post, we should take this opportunity to note that the Faire has chased a lot of ADK-related activity out of the woodwork. The level of traction is pretty surprising giving that this stuff only decloaked last week.

Convenience Library

First, there’s a new open-source project called Easy Peripheral Controller. This is a bunch of convenience/abstraction code; its goal is to help n00bs make their first robot or hardware project with Android. It takes care of lots of the mysteries of microcontroller wrangling in general and Arduino in particular.

Bits and Pieces from Googlers at the Faire

Most of these are 20%-project output.

Project Tricorder: Using the ADK and Android to build a platform to support making education about data collection and scientific process more interesting.

Disco Droid: Modified a bugdroid with servos and the ADK to show off some Android dance moves.

Music Beta, by Google: Android + ADK + cool box with lights for a Music Beta demo.

Optical Networking: Optical network port connected to the ADK.

Interactive Game: Uses ultrasonic sensors and ADK to control an Android game.

Robot Arm: Phone controlling robot arm for kids to play with.

Bugdroids: Balancing Bugdroids running around streaming music from an Android phone.

The Boards

We gave away an ADK hardware dev kit sample to several hundred people at Google I/O, with the idea of showing manufacturers what kind of thing might be useful. This seems to have worked better than we’d expected; we know of no less than seven makers working on Android Accessory Development Kits. Most of these are still in “Coming Soon” mode, but you’ll probably be able to get your hands on some at the Faire.

  1. RT Technology's board is pretty much identical to the kit we handed out at I/O.

  2. SparkFun has one in the works, coming soon.

  3. Also, SparkFun’s existing IOIO product will be getting ADK-compatible firmware.

  4. Arduino themselves also have an ADK bun in the oven.

  5. Seeedstudio’s Seeeeduino Main Board.

  6. 3D Robotics’ PhoneDrone Board.

  7. Microchip’s Accessory Development Starter Kit.

It looks like some serious accessorized fun is in store!

Thursday, 19 May 2011

A Bright Idea: Android Open Accessories

[This post is by Justin Mattson, an Android Developer Advocate, and Erik Gilling, an engineer on the Android systems team. — Tim Bray]

Android’s USB port has in the past been curiously inaccessible to programmers. Last week at Google I/O we announced the Android Open Accessory APIs for Android. These APIs allow USB accessories to connect to Android devices running Android 3.1 or Android 2.3.4 without special licensing or fees. The new “accessory mode” does not require the Android device to support USB Host mode. This post will concentrate on accessory mode, but we also announced USB Host mode APIs for devices with hardware capable of supporting it.

To understand why having a USB port is not sufficient to support accessories let’s quickly look at how USB works. USB is an asymmetric protocol in that one participant acts as a USB Host and all other participants are USB Devices. In the PC world, a laptop or desktop acts as Host and your printer, mouse, webcam, etc., is the USB Device. The USB Host has two important tasks. The first is to be the bus master and control which device sends data at what times. The second key task is to provide power, since USB is a powered bus.

The problem with supporting accessories on Android in the traditional way is that relatively few devices support Host mode. Android’s answer is to turn the normal USB relationship on its head. In accessory mode the Android phone or tablet acts as the USB Device and the accessory acts as the USB Host. This means that the accessory is the bus master and provides power.

Establishing the Connection

Building an Open Accessory is simple as long as you include a USB host and can provide power to the Android device. The accessory needs to implement a simple handshake to establish a bi-directional connection with an app running on the Android device.

The handshake starts when the accessory detects that a device has been connected to it. The Android device will identify itself with the VID/PID that is appropriate based on the manufacturer and model of the device. The accessory then sends a control transaction to the Android device asking if it supports accessory mode.

Once the accessory confirms the Android device supports accessory mode, it sends a series of strings to the Android device using control transactions. These strings allow the Android device to identify compatible applications as well as provide a URL that Android will use if a suitable app is not found. Next the accessory sends a control transaction to the Android device telling it to enter accessory mode.

The Android device then drops off the bus and reappears with a new VID/PID combination. The new VID/PID corresponds to a device in accessory mode, which is Google’s VID 0x18D1, and PID 0x2D01 or 0x2D00. Once an appropriate application is started on the Android side, the accessory can now communicate with it using the first Bulk IN and Bulk OUT endpoints.

The protocol is easy to implement on your accessory. If you’re using the ADK or other USB Host Shield compatible Arduino you can use the AndroidAccessory library to implement the protocol. The ADK is one easy way to get started with accessory mode, but any accessory that has the required hardware and speaks the protocol described here and laid out in detail in the documentation can function as an Android Open Accessory.

Communicating with the Accessory

After the low-level USB connection is negotiated between the Android device and the accessory, control is handed over to an Android application. Any Android application can register to handle communication with any USB accessory. Here is how that would be declared in your AndroidManifest.xml:

<activity android:name=".UsbAccessoryActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
</intent-filter>

<meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
android:resource="@xml/accessory_filter" />
</activity>

Here's how you define the accessories the Activity supports:

<resources>
<usb-accessory manufacturer="Acme, Inc" model="Whiz Banger" version="7.0" />
</resources>

The Android system signals that an accessory is available by issuing an Intent and then the user is presented with a dialog asking what application should be opened. The accessory-mode protocol allows the accessory to specify a URL to present to the user if no application is found which knows how communicate with it. This URL could point to an application in Android Market designed for use with the accessory.

After the application opens it uses the Android Open Accessory APIs in the SDK to communicate with the accessory. This allows the opening of a single FileInputStream and single FileOutputStream to send and receive arbitrary data. The protocol that the application and accessory use is then up to them to define.

Here’s some basic example code you could use to open streams connected to the accessory:

public class UsbAccessoryActivity extends Activity {
private FileInputStream mInput;
private FileOutputStream mOutput;

private void openAccessory() {
UsbManager manager = UsbManager.getInstance(this);
UsbAccessory accessory = UsbManager.getAccessory(getIntent());

ParcelFileDescriptor fd = manager.openAccessory(accessory);

if (fd != null) {
mInput = new FileInputStream(fd);
mOutput = new FileOutputStream(fd);
} else {
// Oh noes, the accessory didn’t open!
}
}
}

Future Directions

There are a few ideas we have for the future. One issue we would like to address is the “power problem”. It’s a bit odd for something like a pedometer to provide power to your Nexus S while it’s downloading today’s walking data. We’re investigating ways that we could have the USB Host provide just the bus mastering capabilities, but not power. Storing and listening to music on a phone seems like a popular thing to do so naturally we’d like to support audio over USB. Finally, figuring out a way for phones to support common input devices would allow for users to be more productive. All of these features are exciting and we hope will be supported by a future version of Android.

Accessory mode opens up Android to a world of new possibilities filled with lots of new friends to talk to. We can’t wait to see what people come up with. The docs and samples are online; have at it!

[Android/USB graphic by Roman Nurik.]

Tuesday, 10 May 2011

Android 3.1 Platform, New SDK tools

As we announced at Google I/O, today we are releasing version 3.1 of the Android platform. Android 3.1 is an incremental release that builds on the tablet-optimized UI and features introduced in Android 3.0. It adds several new features for users and developers, including:

  • Open Accessory API. This new API provides a way for Android applications to integrate and interact with a wide range of accessories such as musical equipment, exercise equipment, robotics systems, and many others.
  • USB host API. On devices that support USB host mode, applications can now manage connected USB peripherals such as audio devices. input devices, communications devices, and more.
  • Input from mice, joysticks, and gamepads. Android 3.1 extends the input event system to support a variety of new input sources and motion events such as from mice, trackballs, joysticks, gamepads, and others.
  • Resizable Home screen widgets. Developers can now create Home screen widgets that are resizeable horizontally, vertically, or both.
  • Media Transfer Protocol (MTP) Applications can now receive notifications when external cameras are attached and removed, manage files and storage on those devices, and transfer files and metadata to and from them.
  • Real-time Transport Protocol (RTP) API for audio. Developers can directly manage on-demand or interactive data streaming to enable VOIP, push-to-talk, conferencing, and audio streaming.

For a complete overview of what’s new in the platform, see the Android 3.1 Platform Highlights.

To make the Open Accessory API available to a wide variety of devices, we have backported it to Android 2.3.4 as an optional library. Nexus S is the first device to offer support for this feature. For developers, the 2.3.4 version of the Open Accessory API is available in the updated Google APIs Add-On.

Alongside the new platforms, we are releasing an update to the SDK Tools (r11).

Visit the Android Developers site for more information about Android 3.1, Android 2.3.4, and the updated SDK tools. To get started developing or testing on the new platforms, you can download them into your SDK using the Android SDK Manager.