Pages

Sunday 24 March 2013

Application Visibility Issues

Recently we became aware that some Android applications were not visible on the Android Market. While we were internally troubleshooting and qualifying the fix and communicating with our hardware partners, developers were trying hard to get our help through various technical support sites. Regrettably, we fell short of our own standard for customer support by not communicating the issue to our developers and how we were working to resolve it.

We’re pleased to say that the issue looks to be resolved with a patch, and to our best knowledge, all apps that were previously impacted are up and visible again. Again, apologies for the delay and inconvenience this created.

Apps on SD Card: The Details

[This post is by Suchi Amalapurapu, an engineer who worked on this feature. — Tim Bray]

Android 2.2 supports application installation on external storage devices like the SD card. This should give users room for many more apps, and will also benefit certain categories, like games, that need huge assets.

(Note that not all of the contents of an “SD-card-resident” APK are actually on the card; the dex files, private data directories, and native shared libraries remain in internal storage.)

The “Manage Applications” screen in the Settings app now has an “On SD Card” tab. The sizes listed in Manage Applications only include the space taken by the application on internal storage.

The Application Info screen now has either a “move to SD card” or “move to phone” button, but this is often disabled. Copy-protected apps and updates to system apps can’t be moved to the SD card, nor can those which are don’t specify that they work on the SD card.

Controlling Installation Preference

SD-card installation is an optional feature on Android 2.2, is under the control of the developer not the user, and will not affect any applications built prior to Android 2.2.

Application developers can set the field android:installLocation in the root manifest element to one of these values:

  • internalOnly: Install the application on internal storage only. This will result in storage errors if the device runs low on internal storage.

  • preferExternal: The android system tries to install the application on external storage. If that is full, the application is installed on internal storage.

  • auto: Let the Android system decide the best install location for the application. The default system policy is to install the application on internal storage first. If the system is running low on storage, the application is then installed on external storage.

If the installLocation is not specified (as is the case for all applications prior to Android 2.2), the application is installed on internal storage. Application updates will by default try to retain their install location, but application developers may change the installLocation field in an update. Installing an application with this new attribute on older devices will not break compatibility and these applications will be installed on internal storage only.

Application developers can also explicitly install under-development code on external storage via adb install flags, which override the installLocation field: -f for internal storage, and -s for external storage. They can also override the default install location to verify and test application installation on SD card with an adb shell pm command:

adb shell pm setInstallLocation option

Where option is one of:

  • 0 [auto] Let the system decide.

  • 1 [internal only]

  • 2 [external]

The current install location can be retrieved via
adb shell pm getInstallLocation
Note that changing this default can cause applications to misbehave if they’re not prepared to live on the SD card.

USB Mass Storage interactions

The Android system stores the SD-card-resident applications’ APKs in a secure application-specific container. A new flag FLAG_EXTERNAL_STORAGE in ApplicationInfo object indicates that an application is currently installed on the SD card. This storage is removed when an SD-card-resident app is uninstalled.

When an Android device’s SD card is unmounted, applications installed on it are no longer available. Their internal storage is still there and such apps can be uninstalled without replacing the SD card.

The Android framework provides several broadcast intents to support the (small) class of applications, such as launchers, that access other applications’ resources:

  • When the SD card is unmounted, ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE with a list of the disabled applications and a list of corresponding application uid’s via extra attributes in the broadcast intent.

  • When the SD card is mounted, ACTION_EXTERNAL_APPLICATIONS_AVAILABLE with a list of enabled applications and a list of corresponding application uid’s via extra attributes in the broadcast intent.

Applications that handle broadcast intents like ACTION_PACKAGE_ADDED, ACTION_PACKAGE_REMOVED may also want to handle these additional notifications.

When an application gets moved between internal to external storage and vice versa, the application is disabled first (which includes broadcasting intent ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE), the asset resources are copied, and then the application is enabled (which includes broadcasting intent ACTION_EXTERNAL_APPLICATIONS_AVAILABLE).

Security and Performance Implications

Applications on SD card are mounted via Linux’s loopback interface and encrypted via a device-specific key, so they cannot be decrypted on any other device. Note that this is security measure and does not provide copy protection; the apps are world readable just like the resources of normal applications installed on the device’s internal storage. Copy-protected applications cannot be installed on external media. In the interests of stability, updates to system applications also cannot be installed on the external media. The application resources stored on external storage are read-only and hence there are no performance issues with loading or launching applications on SD card.

Swapping or Transferring SD Card Contents

It has always been the case that when you swap SD cards on an Android device, if you physically copy the contents of the old card to the new one, the system will use the data on the new card as if nothing had changed. This is also true of apps which have been installed on the SD card.

When not to install on SD card?

The advantage of installing on SD card is easy to understand: contention for storage space is reduced. There are costs, the most obvious being that your app is disabled when the SD card is either removed or in USB Mass Storage mode; this includes running Services, not just interactive Activities. Aside from this, device removal disables an application’s Widgets, Input methods, Account Managers, Device administrators, Live wallpapers, and Live folders, and may require explicit user action to re-enable them.

Application Stats on Android Market

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

On the Android Market team, it’s been our goal to bring you improved ways of seeing and understanding the installation performance of your published applications. We know that this information is critical in helping you tune your development and marketing efforts. Today I’m pleased to let you know about an important new feature that we’ve added to Android Market called Application Statistics.

Application Statistics is a new type of dashboard in the Market Developer Console that gives you an overview of the installation performance of your apps. It provides charts and tables that summarize each app’s active installation trend over time, as well as its distribution across key dimensions such as Android platform versions, devices, user countries, and user languages. For additional context, the dashboard also shows the comparable aggregate distribution for all app installs from Android Market (numbering in the billions). You could use this data to observe how your app performs relative to the rest of Market or decide what to develop next.

To start with, we’ve seeded the application Statistics dashboards with data going back to December 22, 2010. Going forward, we’ll be updating the data daily.

We encourage you to check out these new dashboards and we hope they’ll give you new and useful insights into your apps’ installation performance. You can access the Statistics dashboards from the main Listings page in the Developer Console.

Watch for more announcements soon. We are continuing to work hard to deliver more reporting features to help you manage your products successfully on Android Market.

Announcing: Apps for Android

Screenshot of WikiNotes for AndroidWe are pleased to announce that a new open source project has been created on Google code hosting called apps-for-android. Our goal is to share some sample applications that demonstrate different aspects of the Android platform.

The first application to be included in the new project is called WikiNotes for Android.

For anyone not familiar with the concept of a wiki, it is a simple way to link up pages of information using WikiWords (words that use CamelCase). For example, in the previous sentence, both WikiWords and CamelCase would become live links in a Wiki, and would take you to pages of information.

WikiNotes for Android is a form of wiki known as a personal wiki. These run on desktops or (in this case) mobile computing devices, and many people like them. They bring a bit more structure to your notes than just a list of subjects. You can choose to link notes or pages up in any manner you like.

This particular implementation uses a regular expression to match WikiWords and turn them into links that fire Intents to go to other notes. Because of the way the links are implemented, the application will also create links out of telephone numbers that take you to the dialer and URLs that start up the browser.

Search by title and content is also implemented, so even if you forget the structure, you can still find that all-important note about where you left your car in the airport car park.

This wiki has a view mode and an edit mode. In view mode, the links become active and allow you to navigate to other notes, or to other activities like dialer and web browser. In edit mode, you see a plain text view that you can edit, and when you confirm the changes it goes back to view mode. There is both a menu entry and keyboard shortcut to switch to edit view, so that you can very quickly make changes. And, if you get lost in the note structure, there is also an option to take you back to the start page.

WikiNotes for Android was written to demonstrate a number of core concepts in Android, including:

  • Multiple Activities in an Application (View, Edit, Search, etc.)
  • Default intent filters for View/Edit/Search based on MIME types
  • Life cycle of Activities
  • Message passing via Bundles in Intents
  • Use of Linkify to add Intent-firing links to text data
  • Using Intents within an application
  • Using Intents to use an Activity within another application
  • Writing a custom ContentProvider that implements search by note title
  • Registration of ReST-like URIs to match titles, and do contents searches
  • SQLite implementations for insert, retrieve, update, delete and search
  • UI layout and creation for multiple activities
  • Menus and keyboard shortcuts

The application remains small in size and features to make it easy to understand. In time, more features will be added to the application to make it more useful, but a sample version with the minimal functionality will always be available for developers new to the Android platform.

If you believe that firing an Intent for every link that is clicked is sub-optimal and will waste resources, please take a look at the running application using DDMS. You will see how efficiently Android re-uses the running Activities and indeed, this is one of the main reasons WikiNotes for Android was written. It demonstrates that using the Android Activities and Intents infrastructure not only makes construction of component-based applications easy, but efficient as well.

There will also be a series of technical articles about the application right here on the Android Developer blog.

And please, keep an eye on the apps-for-android project, as more sample applications will be added to it soon.

Happy wiki-ing.

Announcing the Winners of ADC 2

Back in May at Google I/O, we announced ADC 2 -- the second Android Developer Challenge -- to encourage the development of cool apps that delight mobile users. We received many interesting and high-quality applications -- everything from exciting arcade games to nifty productivity utilities. We also saw apps that took advantage of openness of Android to enhance system behavior at a deep level to provide users with a greater degree of customization and utility. We were particularly pleased to see submissions from many smaller and independent developers.

Over the last couple of months, tens of thousands of Android users around the world reviewed and scored these applications. There were many great apps and the scores were very close. Together with our official panel of judges, these users have spoken and selected our winners!

I am pleased to present the ADC 2 winners gallery, which includes not only the top winners overall and in each category, but also all of the applications that made it to the top 200. There are a lot of great applications in addition to the top winners.

Thanks to everyone who submitted applications or helped us judge the entrants. We encourage all developers to submit their applications to Android Market where their app can be downloaded and enjoyed by Android users around the world.

Apps that work together

Android applications can easily be linked together using intents. One example of this involves Shazam, MySpace, and the Amazon MP3 Store. Once Shazam has identified a song, you can also search for the artist's official MySpace profile page or buy the song via via the Amazon MP3 app. Here, the three developers behind these apps talk about how they accomplished this:

To hear more about how the MySpace app for Android was built and lessons learned, watch Matt Kanninen:

Tomasz Zawada of Shazam also talks about his opinions on the Android platform and has some tips for developers building Android apps:

These and the other Android app developer videos can be found here.

Avoiding memory leaks

Android applications are, at least on the T-Mobile G1, limited to 16 MB of heap. It's both a lot of memory for a phone and yet very little for what some developers want to achieve. Even if you do not plan on using all of this memory, you should use as little as possible to let other applications run without getting them killed. The more applications Android can keep in memory, the faster it will be for the user to switch between his apps. As part of my job, I ran into memory leaks issues in Android applications and they are most of the time due to the same mistake: keeping a long-lived reference to a Context.

On Android, a Context is used for many operations but mostly to load and access resources. This is why all the widgets receive a Context parameter in their constructor. In a regular Android application, you usually have two kinds of Context, Activity and Application. It's usually the first one that the developer passes to classes and methods that need a Context:

@Overrideprotected void onCreate(Bundle state) { super.onCreate(state);  TextView label = new TextView(this); label.setText("Leaks are bad");  setContentView(label);}

This means that views have a reference to the entire activity and therefore to anything your activity is holding onto; usually the entire View hierarchy and all its resources. Therefore, if you leak the Context ("leak" meaning you keep a reference to it thus preventing the GC from collecting it), you leak a lot of memory. Leaking an entire activity can be really easy if you're not careful.

When the screen orientation changes the system will, by default, destroy the current activity and create a new one while preserving its state. In doing so, Android will reload the application's UI from the resources. Now imagine you wrote an application with a large bitmap that you don't want to load on every rotation. The easiest way to keep it around and not having to reload it on every rotation is to keep in a static field:

private static Drawable sBackground;@Overrideprotected void onCreate(Bundle state) { super.onCreate(state);  TextView label = new TextView(this); label.setText("Leaks are bad");  if (sBackground == null) { sBackground = getDrawable(R.drawable.large_bitmap); } label.setBackgroundDrawable(sBackground);  setContentView(label);}

This code is very fast and also very wrong; it leaks the first activity created upon the first screen orientation change. When a Drawable is attached to a view, the view is set as a callback on the drawable. In the code snippet above, this means the drawable has a reference to the TextView which itself has a reference to the activity (the Context) which in turns has references to pretty much anything (depending on your code.)

This example is one of the simplest cases of leaking the Context and you can see how we worked around it in the Home screen's source code (look for the unbindDrawables() method) by setting the stored drawables' callbacks to null when the activity is destroyed. Interestingly enough, there are cases where you can create a chain of leaked contexts, and they are bad. They make you run out of memory rather quickly.

There are two easy ways to avoid context-related memory leaks. The most obvious one is to avoid escaping the context outside of its own scope. The example above showed the case of a static reference but inner classes and their implicit reference to the outer class can be equally dangerous. The second solution is to use the Application context. This context will live as long as your application is alive and does not depend on the activities life cycle. If you plan on keeping long-lived objects that need a context, remember the application object. You can obtain it easily by calling Context.getApplicationContext() or Activity.getApplication().

In summary, to avoid context-related memory leaks, remember the following:

  • Do not keep long-lived references to a context-activity (a reference to an activity should have the same life cycle as the activity itself)
  • Try using the context-application instead of a context-activity
  • Avoid non-static inner classes in an activity if you don't control their life cycle, use a static inner class and make a weak reference to the activity inside. The solution to this issue is to use a static inner class with a WeakReference to the outer class, as done in ViewRoot and its W inner class for instance
  • A garbage collector is not an insurance against memory leaks

Note: This article was originally posted on my personal blog.

Back and other hard keys: three stories

Android 2.0 introduces new behavior and support for handling hard keys such as BACK and MENU, including some special features to support the virtual hard keys that are appearing on recent devices such as Droid.

This article will give you three stories on these changes: from the most simple to the gory details. Pick the one you prefer.

Story 1: Making things easier for developers

If you were to survey the base applications in the Android platform, you would notice a fairly common pattern: add a little bit of magic to intercept the BACK key and do something different. To do this right, the magic needs to look something like this:

@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { // do something on back. return true; } return super.onKeyDown(keyCode, event);}

How to intercept the BACK key in an Activity is also one of the common questions we see developers ask, so as of 2.0 we have a new little API to make this more simple and easier to discover and get right:

@Overridepublic void onBackPressed() {// do something on back.return;}

If this is all you care about doing, and you're not worried about supporting versions of the platform before 2.0, then you can stop here. Otherwise, read on.

Story 2: Embracing long press

One of the fairly late addition to the Android platform was the use of long press on hard keys to perform alternative actions. In 1.0 this was long press on HOME for the recent apps switcher and long press on CALL for the voice dialer. In 1.1 we introduced long press on SEARCH for voice search, and 1.5 introduced long press on MENU to force the soft keyboard to be displayed as a backwards compatibility feature for applications that were not yet IME-aware.

(As an aside: long press on MENU was only intended for backwards compatibility, and thus has some perhaps surprising behavior in how strongly the soft keyboard stays up when it is used. This is not intended to be a standard way to access the soft keyboards, and all apps written today should have a more standard and visible way to bring up the IME if they need it.)

Unfortunately the evolution of this feature resulted in a less than optimal implementation: all of the long press detection was implemented in the client-side framework's default key handling code, using timed messages. This resulted in a lot of duplication of code and some behavior problems; since the actual event dispatching code had no concept of long presses and all timing for them was done on the main thread of the application, the application could be slow enough to not update within the long press timeout.

In Android 2.0 this all changes, with a real KeyEvent API and callback functions for long presses. These greatly simplify long press handling for applications, and allow them to interact correctly with the framework. For example: you can override Activity.onKeyLongPress() to supply your own action for a long press on one of the hard keys, overriding the default action provided by the framework.

Perhaps most significant for developers is a corresponding change in the semantics of the BACK key. Previously the default key handling executed the action for this key when it was pressed, unlike the other hard keys. In 2.0 the BACK key is now execute on key up. However, for existing apps, the framework will continue to execute the action on key down for compatibility reasons. To enable the new behavior in your app you must set android:targetSdkVersion in your manifest to 5 or greater.

Here is an example of code an Activity subclass can use to implement special actions for a long press and short press of the CALL key:

@Overridepublic boolean onKeyLongPress(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_CALL) { // a long press of the call key. // do our work, returning true to consume it. by // returning true, the framework knows an action has // been performed on the long press, so will set the // canceled flag for the following up event. return true; } return super.onKeyLongPress(keyCode, event);}
@Overridepublic boolean onKeyUp(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_CALL && event.isTracking() && !event.isCanceled()) { // if the call key is being released, AND we are tracking // it from an initial key down, AND it is not canceled, // then handle it. return true; } return super.onKeyUp(keyCode, event);}

Note that the above code assumes we are implementing different behavior for a key that is normally processed by the framework. If you want to implement long presses for another key, you will also need to override onKeyDown to have the framework track it:

@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_0) { // this tells the framework to start tracking for // a long press and eventual key up. it will only // do so if this is the first down (not a repeat). event.startTracking(); return true; } return super.onKeyDown(keyCode, event);}

Story 3: Making a mess with virtual keys

Now we come to the story of our original motivation for all of these changes: support for virtual hard keys, as seen on the Droid and other upcoming devices. Instead of physical buttons, these devices have a touch sensor that extends outside of the visible screen, creating an area for the "hard" keys to live as touch sensitive areas. The low-level input system looks for touches on the screen in this area, and turns these into "virtual" hard key events as appropriate.

To applications these basically look like real hard keys, though the generated events will have a new FLAG_VIRTUAL_HARD_KEY bit set to identify them. Regardless of that flag, in nearly all cases an application can handle these "hard" key events in the same way it has always done for real hard keys.

However, these keys introduce some wrinkles in user interaction. Most important is that the keys exist on the same surface as the rest of the user interface, and they can be easily pressed with the same kind of touches. This can become an issue, for example, when the virtual keys are along the bottom of the screen: a common gesture is to swipe up the screen for scrolling, and it can be very easy to accidentally touch a virtual key at the bottom when doing this.

The solution for this in 2.0 is to introduce a concept of a "canceled" key event. We've already seen this in the previous story, where handling a long press would cancel the following up event. In a similar way, moving from a virtual key press on to the screen will cause the virtual key to be canceled when it goes up.

In fact the previous code already takes care of this — by checking isCanceled() on the key up, canceled virtual keys and long presses will be ignored. There are also individual flags for these two cases, but they should rarely be used by applications and always with the understanding that in the future there may be more reasons for a key event to be canceled.

For existing application, where BACK key compatibility is turned on to execute the action on down, there is still the problem of accidentally detecting a back press when intending to perform a swipe. Though there is no solution for this except to update an application to specify it targets SDK version 5 or later, fortunately the back key is generally positioned on a far side of the virtual key area, so the user is much less likely to accidentally hit it than some of the other keys.

Writing an application that works well on pre-2.0 as well as 2.0 and later versions of the platform is also fairly easy for most common cases. For example, here is code that allows you to handle the back key in an activity correctly on all versions of the platform:

@Overridepublic boolean onKeyDown(int keyCode, KeyEvent event) { if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.ECLAIR && keyCode == KeyEvent.KEYCODE_BACK && event.getRepeatCount() == 0) { // Take care of calling this method on earlier versions of // the platform where it doesn't exist. onBackPressed(); } return super.onKeyDown(keyCode, event);}@Overridepublic void onBackPressed() { // This will be called either automatically for you on 2.0 // or later, or by the code above on earlier versions of the // platform. return;}

For the hard core: correctly dispatching events

One final topic that is worth covering is how to correctly handle events in the raw dispatch functions such as onDispatchEvent() or onPreIme(). These require a little more care, since you can't rely on some of the help the framework provides when it calls the higher-level functions such as onKeyDown(). The code below shows how you can intercept the dispatching of the BACK key such that you correctly execute your action when it is release.

@Overridepublic boolean dispatchKeyEvent(KeyEvent event) { if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) { if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { // Tell the framework to start tracking this event. getKeyDispatcherState().startTracking(event, this); return true; } else if (event.getAction() == KeyEvent.ACTION_UP) { getKeyDispatcherState().handleUpEvent(event); if (event.isTracking() && !event.isCanceled()) { // DO BACK ACTION HERE return true; } } return super.dispatchKeyEvent(event); } else { return super.dispatchKeyEvent(event); }}

The call to getKeyDispatcherState() returns an object that is used to track the current key state in your window. It is generally available on the View class, and an Activity can use any of its views to retrieve the object if needed.

Backward compatibility for Android applications

Android 1.5 introduced a number of new features that application developers can take advantage of, like virtual input devices and speech recognition. As a developer, you need to be aware of backward compatibility issues on older devices—do you want to allow your application to run on all devices, or just those running newer software? In some cases it will be useful to employ the newer APIs on devices that support them, while continuing to support older devices.

If the use of a new API is integral to the program—perhaps you need to record video—you should add a manifest entry to ensure your app won't be installed on older devices. For example, if you require APIs added in 1.5, you would specify 3 as the minimum SDK version:

  ...  ... 

If you want to add a useful but non-essential feature, such as popping up an on-screen keyboard even when a hardware keyboard is available, you can write your program in a way that allows it to use the newer features without failing on older devices.

Using reflection

Suppose there's a simple new call you want to use, like android.os.Debug.dumpHprofData(String filename). The android.os.Debug class has existed since the first SDK, but the method is new in 1.5. If you try to call it directly, your app will fail to run on older devices.

The simplest way to call the method is through reflection. This requires doing a one-time lookup and caching the result in a Method object. Using the method is a matter of calling Method.invoke and un-boxing the result. Consider the following:

public class Reflect { private static Method mDebug_dumpHprofData; static { initCompatibility(); }; private static void initCompatibility() { try { mDebug_dumpHprofData = Debug.class.getMethod( "dumpHprofData", new Class[] { String.class } ); /* success, this is a newer device */ } catch (NoSuchMethodException nsme) { /* failure, must be older device */ } } private static void dumpHprofData(String fileName) throws IOException { try { mDebug_dumpHprofData.invoke(null, fileName); } catch (InvocationTargetException ite) { /* unpack original exception when possible */ Throwable cause = ite.getCause(); if (cause instanceof IOException) { throw (IOException) cause; } else if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } else if (cause instanceof Error) { throw (Error) cause; } else { /* unexpected checked exception; wrap and re-throw */ throw new RuntimeException(ite); } } catch (IllegalAccessException ie) { System.err.println("unexpected " + ie); } } public void fiddle() { if (mDebug_dumpHprofData != null) { /* feature is supported */ try { dumpHprofData("/sdcard/dump.hprof"); } catch (IOException ie) { System.err.println("dump failed!"); } } else { /* feature not supported, do something else */ System.out.println("dump not supported"); } }}

This uses a static initializer to call initCompatibility, which does the method lookup. If that succeeds, it uses a private method with the same semantics as the original (arguments, return value, checked exceptions) to do the call. The return value (if it had one) and exception are unpacked and returned in a way that mimics the original. The fiddle method demonstrates how the application logic would choose to call the new API or do something different based on the presence of the new method.

For each additional method you want to call, you would add an additional private Method field, field initializer, and call wrapper to the class.

This approach becomes a bit more complex when the method is declared in a previously undefined class. It's also much slower to call Method.invoke() than it is to call the method directly. These issues can be mitigated by using a wrapper class.

Using a wrapper class

The idea is to create a class that wraps all of the new APIs exposed by a new or existing class. Each method in the wrapper class just calls through to the corresponding real method and returns the same result.

If the target class and method exist, you get the same behavior you would get by calling the class directly, with a small amount of overhead from the additional method call. If the target class or method doesn't exist, the initialization of the wrapper class fails, and your application knows that it should avoid using the newer calls.

Suppose this new class were added:

public class NewClass { private static int mDiv = 1; private int mMult; public static void setGlobalDiv(int div) { mDiv = div; } public NewClass(int mult) { mMult = mult; } public int doStuff(int val) { return (val * mMult) / mDiv; }}

We would create a wrapper class for it:

class WrapNewClass { private NewClass mInstance; /* class initialization fails when this throws an exception */ static { try { Class.forName("NewClass"); } catch (Exception ex) { throw new RuntimeException(ex); } } /* calling here forces class initialization */ public static void checkAvailable() {} public static void setGlobalDiv(int div) { NewClass.setGlobalDiv(div); } public WrapNewClass(int mult) { mInstance = new NewClass(mult); } public int doStuff(int val) { return mInstance.doStuff(val); }}

This has one method for each constructor and method in the original, plus a static initializer that tests for the presence of the new class. If the new class isn't available, initialization of WrapNewClass fails, ensuring that the wrapper class can't be used inadvertently. The checkAvailable method is used as a simple way to force class initialization. We use it like this:

public class MyApp { private static boolean mNewClassAvailable; /* establish whether the "new" class is available to us */ static { try { WrapNewClass.checkAvailable(); mNewClassAvailable = true; } catch (Throwable t) { mNewClassAvailable = false; } } public void diddle() { if (mNewClassAvailable) { WrapNewClass.setGlobalDiv(4); WrapNewClass wnc = new WrapNewClass(40); System.out.println("newer API is available - " + wnc.doStuff(10)); } else { System.out.println("newer API not available"); } }}

If the call to checkAvailable succeeds, we know the new class is part of the system. If it fails, we know the class isn't there, and adjust our expectations accordingly. It should be noted that the call to checkAvailable will fail before it even starts if the bytecode verifier decides that it doesn't want to accept a class that has references to a nonexistent class. The way this code is structured, the end result is the same whether the exception comes from the verifier or from the call to Class.forName.

When wrapping an existing class that now has new methods, you only need to put the new methods in the wrapper class. Invoke the old methods directly. The static initializer in WrapNewClass would be augmented to do a one-time check with reflection.

Testing is key

You must test your application on every version of the Android framework that is expected to support it. By definition, the behavior of your application will be different on each. Remember the mantra: if you haven't tried it, it doesn't work.

You can test for backward compatibility by running your application in an emulator from an older SDK, but as of the 1.5 release there's a better way. The SDK allows you to specify "Android Virtual Devices" with different API levels. Once you create the AVDs, you can test your application with old and new versions of the system, perhaps running them side-by-side to see the differences. More information about emulator AVDs can be found in the SDK documentation and from emulator -help-virtual-device.


Learn about Android 1.5 and more at Google I/O. Members of the Android team will be there to give a series of in-depth technical sessions and to field your toughest questions.

Announcing the Android 1.0 SDK, release 1

About this time last year, my colleagues and I were preparing for the first of the "early look" SDK releases. I remember being a little freaked out—November 12 was starting to sound awfully close! But I think I can safely speak for the entire Android team when I say that we were all very excited about that upcoming release. In the year since, we've run and concluded the first Android Developer Challenge, given away $5,000,000, released more SDK builds, and worked with our partners to prepare the first device for users. It's been quite the whirlwind of a year.

In one of those strange cosmic symmetries, here we are a year later, and we're once again very excited about an upcoming release. I'm referring, of course, to the first Android-powered device that our colleagues at T-Mobile have just announced—the T-Mobile G1. We can't wait to see our hard work on store shelves and in the hands of users, but today we're almost as excited because we're announcing the brand-new Android 1.0 SDK, release 1.

Yes, that means we're officially at 1.0. Of course the SDK won't remain static—we'll keep improving the tools by adding features and fixing bugs. But now developers can rely on the APIs in the SDK, and can update their applications to run on Android 1.0-compatible devices. The Android Market beta will also launch with the T-Mobile G1, providing developers an easy and open way to distribute their applications on that and later devices. I've already seen a lot of applications that have me stoked, and I can't wait to see things really come together as developers cross that final mile to prepare their applications for Android 1.0.

So what's next for us? Well, we'll keep working on the SDK, as I said. But we're also working hard with our partners in the Open Handset Alliance on the open-source release, with the aim of making the code available in the fourth quarter. The second Android Developer Challenge is also on the horizon—watch this space for more details. We're also already working on the future of the Android platform, and on more devices. We've updated the Developer Roadmap, and we'll keep updating it as more information becomes available.

It has indeed been quite an exciting road to get to where we are today. The road stretches on ahead though, and we're not slowing down for a moment. I look forward to meeting and working with many of you developers out there—and trying out your apps on my phone!

Happy Coding!

Saturday 23 March 2013

Android SDK Updates

Today we are releasing updates to multiple components of the Android SDK:

  • Android 2.0.1, revision 1
  • Android 1.6, revision 2
  • SDK Tools, revision 4

Android 2.0.1 is a minor update to Android 2.0. This update includes several bug fixes and behavior changes, such as application resource selection based on API level and changes to the value of some Bluetooth-related constants. For more detailed information, please see the Android 2.0.1 release notes.

To differentiate its behavior from Android 2.0, the API level of Android 2.0.1 is 6. All Android 2.0 devices will be updated to 2.0.1 before the end of the year, so developers will no longer need to support Android 2.0 at that time. Of course, developers of applications affected by the behavior changes should start compiling and testing their apps immediately.

We are also providing an update to the Android 1.6 SDK component. Revision 2 includes fixes to the compatibility mode for applications that don't support multiple screen sizes, as well as SDK fixes. Please see the Android 1.6, revision 2 release notes for the full list of changes.

Finally, we are also releasing an update to the SDK Tools, now in revision 4. This is a minor update with mostly bug fixes in the SDK Manager. A new version of the Eclipse plug-in that embeds those fixes is also available. For complete details, please see the SDK Tools, revision 4 and ADT 0.9.5 release notes.

One more thing: you can now follow us on twitter @AndroidDev.

Android’s HTTP Clients

Jesse Wilson

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


Most network-connected Android apps will use HTTP to send and receive data. Android includes two HTTP clients: HttpURLConnection and Apache HTTP Client. Both support HTTPS, streaming uploads and downloads, configurable timeouts, IPv6 and connection pooling.

Apache HTTP Client

DefaultHttpClient and its sibling AndroidHttpClient are extensible HTTP clients suitable for web browsers. They have large and flexible APIs. Their implementation is stable and they have few bugs.

But the large size of this API makes it difficult for us to improve it without breaking compatibility. The Android team is not actively working on Apache HTTP Client.

HttpURLConnection

HttpURLConnection is a general-purpose, lightweight HTTP client suitable for most applications. This class has humble beginnings, but its focused API has made it easy for us to improve steadily.

Prior to Froyo, HttpURLConnection had some frustrating bugs. In particular, calling close() on a readable InputStream could poison the connection pool. Work around this by disabling connection pooling:

private void disableConnectionReuseIfNecessary() { // HTTP connection reuse which was buggy pre-froyo if (Integer.parseInt(Build.VERSION.SDK) < Build.VERSION_CODES.FROYO) { System.setProperty("http.keepAlive", "false"); }}

In Gingerbread, we added transparent response compression. HttpURLConnection will automatically add this header to outgoing requests, and handle the corresponding response:

Accept-Encoding: gzip

Take advantage of this by configuring your Web server to compress responses for clients that can support it. If response compression is problematic, the class documentation shows how to disable it.

Since HTTP’s Content-Length header returns the compressed size, it is an error to use getContentLength() to size buffers for the uncompressed data. Instead, read bytes from the response until InputStream.read() returns -1.

We also made several improvements to HTTPS in Gingerbread. HttpsURLConnection attempts to connect with Server Name Indication (SNI) which allows multiple HTTPS hosts to share an IP address. It also enables compression and session tickets. Should the connection fail, it is automatically retried without these features. This makes HttpsURLConnection efficient when connecting to up-to-date servers, without breaking compatibility with older ones.

In Ice Cream Sandwich, we are adding a response cache. With the cache installed, HTTP requests will be satisfied in one of three ways:

  • Fully cached responses are served directly from local storage. Because no network connection needs to be made such responses are available immediately.

  • Conditionally cached responses must have their freshness validated by the webserver. The client sends a request like “Give me /foo.png if it changed since yesterday” and the server replies with either the updated content or a 304 Not Modified status. If the content is unchanged it will not be downloaded!

  • Uncached responses are served from the web. These responses will get stored in the response cache for later.

Use reflection to enable HTTP response caching on devices that support it. This sample code will turn on the response cache on Ice Cream Sandwich without affecting earlier releases:

private void enableHttpResponseCache() { try { long httpCacheSize = 10 * 1024 * 1024; // 10 MiB File httpCacheDir = new File(getCacheDir(), "http"); Class.forName("android.net.http.HttpResponseCache") .getMethod("install", File.class, long.class) .invoke(null, httpCacheDir, httpCacheSize); } catch (Exception httpResponseCacheNotAvailable) { }}

You should also configure your Web server to set cache headers on its HTTP responses.

Which client is best?

Apache HTTP client has fewer bugs on Eclair and Froyo. It is the best choice for these releases.

For Gingerbread and better, HttpURLConnection is the best choice. Its simple API and small size makes it great fit for Android. Transparent compression and response caching reduce network use, improve speed and save battery. New applications should use HttpURLConnection; it is where we will be spending our energy going forward.

Android Security Update

Recently, there’s been a lot of news coverage of malware in the mobile space. Over on our Mobile blog, Hiroshi Lockheimer, VP of Android engineering, has posted Android and Security. We think most Android developers will find it interesting reading.

Android's First 5 Months

Originally by Sung Hu Kim, Product Marketing Manager for Android, Google mobile team

As some of you may have heard, Wireless Week has chosen the Open Handset Alliance and Android for its Emerging Technology Award, noting that "Android's potential promises openness and innovation, perhaps changing not only the mobile Internet but the Internet itself."

We at Google would like to congratulate all the members of the Open Handset Alliance and the fantastic Android developer community for this well deserved recognition. Android's growing momentum is the result of an amazing effort and collaboration among many different people. Coincidentally, this week marks five months since the Open Handset Alliance and Android first went public. A lot has happened in this short period of time. Among the things of note:
  • We released an early look at the Android software development kit (SDK), allowing anyone to learn and start creating apps for the platform.
  • Feedback from developers has contributed to numerous fixes, improvements, new tools, and major updates to the SDK, the latest version of which you can find here.
  • Google announced the Android Developer Challenge, which will provide $10 million in total awards for the best Android apps—and the first phase has nearly wrapped up. (Be sure to get your submissions in by April 14!)
  • Several companies gave the first working demonstrations of Android in February.
These have been an exciting first 5 months, and we look forward to making the coming months even better.

Animation in Honeycomb

[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]

One of the new features ushered in with the Honeycomb release is a new animation system, a set of APIs in a whole new package (android.animation) that makes animating objects and properties much easier than it was before.

"But wait!" you blurt out, nearly projecting a mouthful of coffee onto your keyboard while reading this article, "Isn't there already an animation system in Android?"

Animation Prior to Honeycomb

Indeed, Android already has animation capabilities: there are several classes and lots of great functionality in the android.view.animation package. For example, you can move, scale, rotate, and fade Views and combine multiple animations together in an AnimationSet object to coordinate them. You can specify animations in a LayoutAnimationController to get automatically staggered animation start times as a container lays out its child views. And you can use one of the many Interpolator implementations like AccelerateInterpolator and Bounce to get natural, nonlinear timing behavior.

But there are a couple of major pieces of functionality lacking in the previous system.

For one thing, you can animate Views... and that's it. To a great extent, that's okay. The GUI objects in Android are, after all, Views. So as long as you want to move a Button, or a TextView, or a LinearLayout, or any other GUI object, the animations have you covered. But what if you have some custom drawing in your view that you'd like to animate, like the position of a Drawable, or the translucency of its background color? Then you're on your own, because the previous animation system only understands how to manipulate View objects.

The previous animations also have a limited scope: you can move, rotate, scale, and fade a View... and that's it. What about animating the background color of a View? Again, you're on your own, because the previous animations had a hard-coded set of things they were able to do, and you could not make them do anything else.

Finally, the previous animations changed the visual appearance of the target objects... but they didn't actually change the objects themselves. You may have run into this problem. Let's say you want to move a Button from one side of the screen to the other. You can use a TranslateAnimation to do so, and the button will happily glide along to the other side of the screen. And when the animation is done, it will gladly snap back into its original location. So you find the setFillAfter(true) method on Animation and try it again. This time the button stays in place at the location to which it was animated. And you can verify that by clicking on it - Hey! How come the button isn't clicking? The problem is that the animation changes where the button is drawn, but not where the button physically exists within the container. If you want to click on the button, you'll have to click the location that it used to live in. Or, as a more effective solution (and one just a tad more useful to your users), you'll have to write your code to actually change the location of the button in the layout when the animation finishes.

It is for these reasons, among others, that we decided to offer a new animation system in Honeycomb, one built on the idea of "property animation."

Property Animation in Honeycomb

The new animation system in Honeycomb is not specific to Views, is not limited to specific properties on objects, and is not just a visual animation system. Instead, it is a system that is all about animating values over time, and assigning those values to target objects and properties - any target objects and properties. So you can move a View or fade it in. And you can move a Drawable inside a View. And you can animate the background color of a Drawable. In fact, you can animate the values of any data structure; you just tell the animation system how long to run for, how to evaluate between values of a custom type, and what values to animate between, and the system handles the details of calculating the animated values and setting them on the target object.

Since the system is actually changing properties on target objects, the objects themselves are changed, not simply their appearance. So that button you move is actually moved, not just drawn in a different place. You can even click it in its animated location. Go ahead and click it; I dare you.

I'll walk briefly through some of the main classes at work in the new system, showing some sample code when appropriate. But for a more detailed view of how things work, check out the API Demos in the SDK for the new animations. There are many small applications written for the new Animations category (at the top of the list of demos in the application, right before the word App. I like working on animation because it usually comes first in the alphabet).

In fact, here's a quick video showing some of the animation code at work. The video starts off on the home screen of the device, where you can see some of the animation system at work in the transitions between screens. Then the video shows a sampling of some of the API Demos applications, to show the various kinds of things that the new animation system can do. This video was taken straight from the screen of a Honeycomb device, so this is what you should see on your system, once you install API Demos from the SDK.

Animator

Animator is the superclass of the new animation classes, and has some of the common attributes and functionality of the subclasses. The subclasses are ValueAnimator, which is the core timing engine of the system and which we'll see in the next section, and AnimatorSet, which is used to choreograph multiple animators together into a single animation. You do not use Animator directly, but some of the methods and properties of the subclasses are exposed at this superclass level, like the duration, startDelay and listener functionality.

The listeners tend to be important, because sometimes you want to key some action off of the end of an animation, such as removing a view after an animation fading it out is done. To listen for animator lifecycle events, implement the AnimatorListener interface and add your listener to the Animator in question. For example, to perform an action when the animator ends, you could do this:

 anim.addListener(new Animator.AnimatorListener() { public void onAnimationStart(Animator animation) {} public void onAnimationEnd(Animator animation) { // do something when the animation is done } public void onAnimationCancel(Animator animation) {} public void onAnimationRepeat(Animator animation) {} });

As a convenience, there is an adapter class, AnimatorListenerAdapter, that stubs out these methods so that you only need to override the one(s) that you care about:

 anim.addListener(new AnimatorListenerAdapter() { public void onAnimationEnd(Animator animation) { // do something when the animation is done } });

ValueAnimator

ValueAnimator is the main workhorse of the entire system. It runs the internal timing loop that causes all of a process's animations to calculate and set values and has all of the core functionality that allows it to do this, including the timing details of each animation, information about whether an animation repeats, listeners that receive update events, and the capability of evaluating different types of values (see TypeEvaluator for more on this). There are two pieces to animating properties: calculating the animated values and setting those values on the object and property in question. ValueAnimator takes care of the first part; calculating the values. The ObjectAnimator class, which we'll see next, is responsible for setting those values on target objects.

Most of the time, you will want to use ObjectAnimator, because it makes the whole process of animating values on target objects much easier. But sometimes you may want to use ValueAnimator directly. For example, the object you want to animate may not expose setter functions necessary for the property animation system to work. Or perhaps you want to run a single animation and set several properties from that one animated value. Or maybe you just want a simple timing mechanism. Whatever the case, using ValueAnimator is easy; you just set it up with the animation properties and values that you want and start it. For example, to animate values between 0 and 1 over a half-second, you could do this:

 ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f); anim.setDuration(500); anim.start();

But animations are a bit like the tree in the forest philosophy question ("If a tree falls in the forest and nobody is there to hear it, does it make a sound?"). If you don't actually do anything with the values, does the animation run? Unlike the tree question, this one has an answer: of course it runs. But if you're not doing anything with the values, it might as well not be running. If you started it, chances are you want to do something with the values that it calculates along the way. So you add a listener to it, to listen for updates at each frame. And when you get the callback, you call getAnimatedValue(), which returns an Object, to find out what the current value is.

 anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { public void onAnimationUpdate(ValueAnimator animation) { Float value = (Float) animation.getAnimatedValue(); // do something with value... } });

Of course, you don't necessarily always want to animate float values. Maybe you need to animate something that's an integer instead:

 ValueAnimator anim = ValueAnimator.ofInt(0, 100);

or in XML:

 

In fact, maybe you need to animate something entirely different, like a Point, or a Rect, or some custom data structure of your own. The only types that the animation system understands by default are float and int, but that doesn't mean that you're stuck with those two types. You can to use the Object version of the factory method, along with a TypeEvaluator (explained later), to tell the system how to calculate animated values for this unknown type:

 Point p0 = new Point(0, 0); Point p1 = new Point(100, 200); ValueAnimator anim = ValueAnimator.ofObject(pointEvaluator, p0, p1);

There are other animation attributes that you can set on a ValueAnimator besides duration, including:

  • setStartDelay(long): This property controls how long the animation waits after a call to start() before it starts playing.
  • setRepeatCount(int) and setRepeatMode(int): These functions control how many times the animation repeats and whether it repeats in a loop or reverses direction each time.
  • setInterpolator(TimeInterpolator): This object controls the timing behavior of the animation. By default, animations accelerate into and decelerate out of the motion, but you can change that behavior by setting a different interpolator. This function acts just like the one of the same name in the previous Animation class; it's just that the type of the parameter (TimeInterpolator) is different from that of the previous version (Interpolator). But the TimeInterpolator interface is just a super-interface of the existing Interpolator interface in the android.view.animation package, so you can use any of the existing Interpolator implementations, like Bounce, as arguments to this function on ValueAnimator.

ObjectAnimator

ObjectAnimator is probably the main class that you will use in the new animation system. You use it to construct animations with the timing and values that ValueAnimator takes, and also give it a target object and property name to animate. It then quietly animates the value and sets those animated values on the specified object/property. For example, to fade out some object myObject, we could animate the alpha property like this:

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

Note, in this example, a special feature that you can use to make your animations more succinct; you can tell it the value to animate to, and it will use the current value of the property as the starting value. In this case, the animation will start from whatever value alpha has now and will end up at 0.

You could create the same thing in an XML resource as follows:

 

Note, in the XML version, that you cannot set the target object; this must be done in code after the resource is loaded:

 ObjectAnimator anim = AnimatorInflator.loadAnimator(context, resID); anim.setTarget(myObject); anim.start();

There is a hidden assumption here about properties and getter/setter functions that you have to understand before using ObjectAnimator: you must have a public "set" function on your object that corresponds to the property name and takes the appropriate type. Also, if you use only one value, as in the example above, your are asking the animation system to derive the starting value from the object, so you must also have a public "get" function which returns the appropriate type. For example, the class of myObject in the code above must have these two public functions in order for the animation to succeed:

 public void setAlpha(float value); public float getAlpha();

So by passing in a target object of some type and the name of some property foo supposedly on that object, you are implicitly declaring a contract that that object has at least a setFoo() function and possibly also a getFoo() function, both of which handle the type used in the animation declaration. If all of this is true, then the animation will be able to find those setter/getter functions on the object and set values during the animation. If the functions do not exist, then the animation will fail at runtime, since it will be unable to locate the functions it needs. (Note to users of ProGuard, or other code-stripping utilities: If your setter/getter functions are not used anywhere else in the code, make sure you tell the utility to leave the functions there, because otherwise they may get stripped out. The binding during animation creation is very loose and these utilities have no way of knowing that these functions will be required at runtime.)

View properties

The observant reader, or at least the ones that have not yet browsed on to some other article, may have pinpointed a flaw in the system thus far. If the new animation framework revolves around animating properties, and if animations will be used to animate, to a large extent, View objects, then how can they be used against the View class, which exposes none of its properties through set/get functions?

Excellent question: you get to advance to the bonus round and keep reading.

The way it works is that we added new properties to the View class in Honeycomb. The old animation system transformed and faded View objects by just changing the way that they were drawn. This was actually functionality handled in the container of each View, because the View itself had no transform properties to manipulate. But now it does: we've added several properties to View to make it possible to animate Views directly, allowing you to not only transform the way a View looks, but to transform its actual location and orientation. Here are the new properties in View that you can set, get and animate directly:

  • translationX and translationY: These properties control where the View is located as a delta from its left and top coordinates which are set by its layout container. You can run a move animation on a button by animating these, like this: ObjectAnimator.ofFloat(view, "translationX", 0f, 100f);.
  • rotation, rotationX, and rotationY: These properties control the rotation in 2D (rotation) and 3D around the pivot point.
  • scaleX and scaleY: These properties control the 2D scaling of a View around its pivot point.
  • pivotX and pivotY: These properties control the location of the pivot point, around which the rotation and scaling transforms occur. By default, the pivot point is centered at the center of the object.
  • x and y: These are simple utility properties to describe the final location of the View in its container, as a sum of the left/top and translationX/translationY values.
  • alpha: This is my personal favorite property. No longer is it necessary to fade out an object by changing a value on its transform (a process which just didn't seem right). Instead, there is an actual alpha value on the View itself. This value is 1 (opaque) by default, with a value of 0 representing full transparency (i.e., it won't be visible). To fade a View out, you can do this: ObjectAnimator.ofFloat(view, "alpha", 0f);

Note that all of the "properties" described above are actually available in the form of set/get functions (e.g., setRotation() and getRotation() for the rotation property). This makes them both possible to access from the animation system and (probably more importantly) likely to do the right thing when changed. That is, you don't want to scale an object and have it just sit there because the system didn't know that it needed to redraw the object in its new orientation; each of the setter functions takes care to run the appropriate invalidation step to make the rendering work correctly.

AnimatorSet

This class, like the previous AnimationSet, exists to make it easier to choreograph multiple animations. Suppose you want several animations running in tandem, like you want to fade out several views, then slide in other ones while fading them in. You could do all of this with separate animations and either manually starting the animations at the right times or with startDelays set on the various delayed animations. Or you could use AnimatorSet to do all of that for you. AnimatorSet allows you to animations that play together, playTogether(Animator...), animations that play one after the other, playSequentially(Animator...), or you can organically build up a set of animations that play together, sequentially, or with specified delays by calling the functions in the AnimatorSet.Builder class, with(), before(), and after(). For example, to fade out v1 and then slide in v2 while fading it, you could do something like this:

 ObjectAnimator fadeOut = ObjectAnimator.ofFloat(v1, "alpha", 0f); ObjectAnimator mover = ObjectAnimator.ofFloat(v2, "translationX", -500f, 0f); ObjectAnimator fadeIn = ObjectAnimator.ofFloat(v2, "alpha", 0f, 1f); AnimatorSet animSet = new AnimatorSet().play(mover).with(fadeIn).after(fadeOut);; animSet.start();

Like ValueAnimator and ObjectAnimator, you can create AnimatorSet objects in XML resources as well.

TypeEvaluator

I wanted to talk about just one more thing, and then I'll leave you alone to explore the code and play with the API demos. The last class I wanted to mention is TypeEvaluator. You may not use this class directly for most of your animations, but you should that it's there in case you need it. As I said earlier, the system knows how to animate float and int values, but otherwise it needs some help knowing how to interpolate between the values you give it. For example, if you want to animate between the Point values in one of the examples above, how is the system supposed to know how to interpolate the values between the start and end points? Here's the answer: you tell it how to interpolate, using TypeEvaluator.

TypeEvaluator is a simple interface that you implement that the system calls on each frame to help it calculate an animated value. It takes a floating point value which represents the current elapsed fraction of the animation and the start and end values that you supplied when you created the animation and it returns the interpolated value between those two values at that fraction. For example, here's the built-in FloatEvaluator class used to calculate animated floating point values:

 public class FloatEvaluator implements TypeEvaluator { public Object evaluate(float fraction, Object startValue, Object endValue) { float startFloat = ((Number) startValue).floatValue(); return startFloat + fraction * (((Number) endValue).floatValue() - startFloat); } }

But how does it work with a more complex type? For an example of that, here is an implementation of an evaluator for the Point class, from our earlier example:

 public class PointEvaluator implements TypeEvaluator { public Object evaluate(float fraction, Object startValue, Object endValue) { Point startPoint = (Point) startValue; Point endPoint = (Point) endValue; return new Point(startPoint.x + fraction * (endPoint.x - startPoint.x), startPoint.y + fraction * (endPoint.y - startPoint.y)); } }

Basically, this evaluator (and probably any evaluator you would write) is just doing a simple linear interpolation between two values. In this case, each 'value' consists of two sub-values, so it is linearly interpolating between each of those.

You tell the animation system to use your evaluator by either calling the setEvaluator() method on ValueAnimator or by supplying it as an argument in the Object version of the factory method. To continue our earlier example animating Point values, you could use our new PointEvaluator class above to complete that code:

 Point p0 = new Point(0, 0); Point p1 = new Point(100, 200); ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), p0, p1);

One of the ways that you might use this interface is through the ArgbEvaluator implementation, which is included in the Android SDK. If you animate a color property, you will probably either use this evaluator automatically (which is the case if you create an animator in an XML resource and supply colors as values) or you can set it manually on the animator as described in the previous section.

But Wait, There's More!

There's so much more to the new animation system that I haven't gotten to. There's the repetition functionality, the listeners for animation lifecycle events, the ability to supply multiple values to the factory methods to get animations between more than just two endpoints, the ability to use the Keyframe class to specify a more complex time/value sequence, the use of PropertyValuesHolder to specify multiple properties to animate in parallel, the LayoutTransition class for automating simple layout animations, and so many other things. But I really have to stop writing soon and get back to working on the code. I'll try to post more articles in the future on some of these items, but also keep an eye on my blog at graphics-geek.blogspot.com for upcoming articles, tutorials, and videos on this and related topics. Until then, check out the API demos, read the overview of Property Animation posted with the 3.0 SDK, dive into the code, and just play with it.

Android University

Spring is on the way, and temperatures are rising. We're no exception, and things are starting to heat up over here in Android-land, too.

The Android Developer Challenge deadline is approaching quickly. Wow, that's strange to me. On one hand, we've come so far that the first announcement back on November 12 seems like a prior geologic era, but on the other hand it seems like the Challenge just started! But it's been five months, so it's time to finish your code, polish your UI, and submit your application. Remember to submit by midnight on April 14th, PST (GMT-8).

But after the Challenge, what's next? Well, on the 28th and 29th of May we have Google I/O. This is the biggest Google developer event of the year, and you can bet that the Androids will be there in numbers.

Here are the sessions we've prepared on Android.

  • Android 101: Building an Application
  • Anatomy & Physiology of an Android
  • Dalvik Internals
  • Inside the Android Application Framework
  • Building Great UIs with Android
  • Internationalizing Android Applications
  • Location, Location, Location
  • Mobile Mashups
For more details on these sessions, visit the Google I/O site. Please do, in fact—I'm really excited by some of these because we're going to go into a level of detail that we haven't before. Ever wanted to hear the tech lead on Dalvik talk about Dalvik? Ever wanted an exhaustive review of the i18n/resource system? Then don't miss this event.

Besides the technical sessions, there will be a Fireside Chat with as many members of the Android team as we can rustle up, and an Android section in the demo and coding area. (Personally, I'm looking forward to that the most: it's shaping up to be a code festival of mammoth proportions.) If you need a break from Android, there are also tons of sessions on other developer technologies from Google, too.

We intend this to be the premier developer event for Android, this year. If you only go to one Android event, we humbly suggest that you consider this one. Early-bird registration ends TODAY (April 4th), so be sure to sign up soon.

I'll see you there!

Thursday 21 March 2013

Android NDK r3

The third release of the Android Native Development Kit (NDK) is now available for download from the Android developer site.

It can be used to target devices running Android 1.5 and higher. In addition to a few bug fixes and improvements, this release includes the following new features:

Toolchain improvement

The toolchain binaries have been refreshed for this release with GCC 4.4.0, which should generate slightly more compact and efficient machine code than the previous one (4.2.1).

Note that the GCC 4.4.0 C++ frontend is more pedantic, and may refuse to compile certain rare and invalid template declarations that were accepted by 4.2.1. To alleviate the problem, this NDK still provides the 4.2.1 binaries, which can optionally be used to build your machine code.

OpenGL ES 2.0 support

Applications targeting Android 2.0 (API level 5) or higher can now directly access OpenGL ES 2.0 features. This brings the ability to control graphics rendering through vertex and fragment shader programs, using the GLSL shading language.

A new trivial sample, named "hello-gl2", demonstrates how to render a simple triangle using both shader types.

Name simplification

This NDK release is just called "r3", for "Revision 3", to indicate that it is not limited to a specific Android platform/API level. Some developers thought that the previous release's name (1.6_r1) was confusing and indicated that it could only be used to target Android 1.6, which was not true.

Enjoy!

Android SDK m5-rc14 now available

On behalf of the entire Android team, I'm happy to let you know that an updated version of the Android SDK – we're calling it m5-rc14 – is now available. Today, we're continuing the early look at the Android SDK that we started back in November by providing updates to the Android APIs and the developer tools based, in part, on the great feedback and suggestions developers have been giving us. We're excited about the progress that we've made and look forward to making additional updates in the future as the platform evolves towards production-readiness.

There are a couple of changes in m5-rc14 I'd like to highlight:

  • New user interface - As I mentioned when we introduced the m3 version of the Android SDK, we're continuing to refine the UI that's available for Android. m5-rc14 replaces the previous placeholder with a new UI, but as before, work on it is still in-progress.
  • Layout animations - Developers can now create layout animations for their applications using the capabilities introduced in the android.view.animation package. Check out the LayoutAnimation*.java files in the APIDemos sample code for examples of how this works.
  • Geo-coding - android.location.Geocoder enables developers to forward and reverse geo-code (i.e. translate an address into a coordinate and vice-versa), and also search for businesses.
  • New media codecs - The MediaPlayer class has added support for the OGG Vorbis, MIDI, XMF, iMelody, RTTL/RTX, and OTA audio file formats.
  • Updated Eclipse plug-in - A new version of ADT is available and provides improvements to the Android developer experience. In particular, check out the new Android Manifest editor.

You can find more information about what's changed in a couple of documents that we've published. First is an overview of the changes to the Android APIs in API Changes Overview. If you want a more granular view of what's changed, an API diff between m3-rc37 and m5-rc14 is also available. Finally, Upgrading the SDK provides links to the two previously referenced documents and the release notes, as well as instructions on how to upgrade your development environment.

We still need your help in shaping the platform, so if you find issues with the Android APIs or the developer tools, please let us know through the Android Issue Tracker. If you have general comments or questions, please head on over to the Android groups to get in touch.

We're looking forward to all the applications that developers will create using this new version of the Android SDK. Of course, you can use m5-rc14 or any older version of the SDK for your Android Developers Challenge submission.

Android SDK Tools, Revision 20

[This post is by Xavier Ducrohet, Tech Lead for the Android developer tools]

Along with the preview of the Android 4.1 (Jelly Bean) platform, we launched Android SDK Tools R20 and ADT 20.0.0. Here are a few things that we would like to highlight.
    Application templates: Android ADT supports a new application templates for creating new application, blank activity, master-detail flow, and custom view. These templates support the Android style guide thus making it faster and easier to build beautiful apps. More templates will be added over time.

    Tracer for GLES: With this new tool you can capture the entire sequence of OpenGL calls made by an app into a trace file on the host and replay the captured trace and display the GL state at any point in time.
    Device Monitor: To help you to easily debug your apps, all the Android debugging tools like DDMS, traceview, hierarchyviewer and Tracer for GLES are now built into one single application.
    Systrace: Improving app performance does not have to be a guesswork any more. Systrace for Jelly Bean and above lets you easily optimize your app. You can capture a slice of system activity plus additional information tagged from the Settings > Developer Options > Monitoring: Enable traces or with specific calls added to your application code.

To learn more on the layout editor, XML editing, build system & SDK Manager improvements, please read the ADT 20.0.0 and SDK Tools R20 release notes.

Join us today, June 28th, at the “What’s new in Android developer tools” session for some fun tool demos and a sneak-peak into what’s coming next.

Android SDK update: m5-rc15 released

Earlier today we released an update to the Android SDK – we're calling it m5-rc15. With this update, the SDK now includes all of the incremental changes we've been making to the online documentation since m5-rc14 was released in mid-February. In addition to the latest documentation, we've also fixed a security issue involving handling of image files.

We recommend that you install m5-rc15 at your earliest convenience. The update doesn't change any of the Android APIs or introduce any new ones. Eclipse users don't need to update the ADT plug-in either.

Once you've unzipped the file on your machine, you will want to update things like your PATH variable and, if you're using Eclipse, the SDK location setting for ADT (hint: Preferences > Android).

Android Photostream

I'm pleased to announce that a new open source sample application—called Photostream—has been added to the apps-for-android project. Photostream is a simple photos browser and viewer for Flickr. All you need to use it is a Flickr screen name or user name (the application offers a default user name if you just want to try it.)

This application serves as an illustrative example of several Android features and APIs:

  • Activity aliases
  • Adding custom shortcuts to Home
  • Adding a new wallpaper chooser to the system
  • Custom layouts
  • Custom XML attributes
  • Use of themes
  • Use of styles
  • Use of text colors
  • Use of
  • Use of bitmap and layer drawables from XML
  • Use of HttpClient
  • Proper interaction between background threads and the UI thread
  • Efficient display rotation (using the new onRetainNonConfigurationInstance() API)
  • Animations and layout animations
  • Cropping an image
  • Image manipulation

My favorite feature is the ability to add a new shortcut type in Home, to create a shortcut to any Flickr account. The shortcut shows a custom icon, downloaded from the Flickr user profile:

If you plan on reusing the source code to access Flickr in your own application, you should modify the Flickr.java file to replace the existing API key with your own. The application source code also contains a very handy class called UserTask.java. This class is designed to help you easily write background operations that interact with the UI thread.