31 Jul 2010
Android Forums
Root Motorolla Cliq on a Mac
Can someone please help? I can't find anything in the search. Is there a way to root this on a Mac? Thanks
31 Jul 2010 3:08pm GMT
Apad video chat
Hi, does anyone know of a good program to use for Apad android video chat? I've heard of Movicha but can't find the file to download. Does Skype lite...
31 Jul 2010 1:35pm GMT
[HELP]Hero can not boot!
Hi all,I am a new user of android. Last night, I installed the wrong "radio" to my phone. After that,The phone can not boot, when I press the POWER...
31 Jul 2010 1:25pm GMT
is there a gnome-do like application for android?
In linux, for gnome desktop environment, there is an application to quick launch desired application. This saves much time one spends to browse...
31 Jul 2010 1:20pm GMT
Android 3.0 expectations
What would we like to see in Android 3.0 , I know we are just wrapping our head around 2.2 froyo, but with 3.0 slated from october release, what are...
31 Jul 2010 12:43pm GMT
Trivia app
Hi, Im the developer of the trivia app test. Dumbometer. Please try this game and let us know your reviews. Dumbometer is a simple...
31 Jul 2010 11:53am GMT
[YouTube]Enjoy Every Single day of Life with Dolphin Add-ons
I had found the wonderful video since I subscrible dolphinbrowser channel in YouTube. I WANT SHARE WIYH YOU. ...
31 Jul 2010 11:53am GMT
Dumbometer
Dumbometer is a simple addictive test based on months of research, study and analysis of human brain response time. It is the mother of all quiz and...
31 Jul 2010 11:39am GMT
No privacy on software
Hi , Currently Google said that there is not privacy on android phone marketplace. And google admits that many developers have asked to speak to...
31 Jul 2010 9:30am GMT
Help pls!!!
I bought an HTC Hero from carphonewarehouse with orange contract. The firmware version is 1.5 and the ROM version is 2.73.405.5. I heard that HTC has...
31 Jul 2010 8:53am GMT
Google Android News Android Forums
LogMeIn for Android Giveaway Contest Closed
Well, guys, the contest for winning LogMeIn's Ignition app for Android has now come to a close. Thanks to all those that submitted responses in our forum thread, and to all those that responded incorrectly… sorry, folks, but your entries wont be considered. Lots of entries came in on the app! Looks like everyone is excited [...]
For more information on Android and the current Android mobile phones, check out our Android Guides
LogMeIn for Android Giveaway Contest Closed
31 Jul 2010 5:01am GMT
Motorola releases Droid X antenna, quality FAQs
Remember Motorola's release of the "No Jacket Required" ad, taking a stab at Apple's Antenna deisgn problem? Well now, they have released a FAQ (Frequently Asked Questions) section to their site, along with specifications on their antenna design. A few of the highlights in the FAQ: Q: When Motorola is designing a new phone, how does [...]
For more information on Android and the current Android mobile phones, check out our Android Guides
Motorola releases Droid X antenna, quality FAQs
31 Jul 2010 2:58am GMT
Froyo coming out to unlocked European HTC Desire handests
Who isn't getting Froyo? Well, it looks like unlocked HTC Desire's in Europe are no longer in the ignore list, as there is now an official press release that states that they will be getting the long awaited 2.2 update. The upgrade is set to include: 720P Video Recording HTC Sense Updates App Share Improved Keyboard HTC's new phone features Sync features [...]
For more information on Android and the current Android mobile phones, check out our Android Guides
Froyo coming out to unlocked European HTC Desire handests
31 Jul 2010 2:37am GMT
McAfee acquires tenCube, makers of WaveSecure
Awhile back, we did a review and giveaway of WaveSecure, an app that allows you to remotelyloss and theft of your Android device. Now, tenCube, maker of WaveSecure, is set to be acquired by McAfee. According to the official announcement on McAfee's website, they say that the acquirement is set to: Further establish itself as the leader in mobile [...]
For more information on Android and the current Android mobile phones, check out our Android Guides
McAfee acquires tenCube, makers of WaveSecure
31 Jul 2010 1:39am GMT
30 Jul 2010
Google Android News Android Forums
Motorola Droid to receive Android 2.2 next week
According to an article over at engadget, they have received official word from Verizon that Froyo will be headed to the original Motorola Droid next week. It's entirely possible that this could be a hasty response to HTC's notice that the Evo will also be getting 2.2 (officially) on 8/3, but however it came about, [...]
For more information on Android and the current Android mobile phones, check out our Android Guides
Motorola Droid to receive Android 2.2 next week
30 Jul 2010 9:52pm GMT
Motorola M511 Flips into China
Adding to an impressive stable of phones and carriers, Motorola will be releasing the M511 (known as the FlipOut in Europe) onto Chinese carriers by the end of this month. In other words, today. The M511 will run Android 2.1 with MotoBlur, and will offer a full QWERY keyboard to perfectly complement its social network integration, which [...]
For more information on Android and the current Android mobile phones, check out our Android Guides
Motorola M511 Flips into China
30 Jul 2010 8:19pm GMT
Droid X source code released
Is today source code release day? Well not really but it sure seems like it considering Samsung released their Captivate source code today as well. Truth be told, Motorola actually released the source code two days ago, just nobody noticed, lol. Anyway, if you'd like to crawl through what makes the Droid X tick, then hit [...]
For more information on Android and the current Android mobile phones, check out our Android Guides
30 Jul 2010 8:03pm GMT
Samsung Captivate Code Goes Open Source
Developers anxious for the full open source coding of the Samsung Captivate were joyous today as they received the following message in their inboxes: Dear _____________, You can download the source code of SGH-I897 on this site in Mobile Category, SGH-I897 model. Thank you. Short, sweet, and to the point. This is excellent news for those intrepid ROM developers already [...]
For more information on Android and the current Android mobile phones, check out our Android Guides
Samsung Captivate Code Goes Open Source
30 Jul 2010 8:01pm GMT
Sony Ericsson Xperia X10 Mini & Mini Pro get rooted
Another one bites the dust! The Sony Ericsson Xperia X10 Mini & Mini Pro have been rooted. We'll skip right to the goodies and give you the instructions: You will need ADB from Android SDK and USB drivers for X10 mini (part of Sony Ericsson PC Companion). Enable USB debugging on the phone in Settings>Applications>Development and connect the phone [...]
For more information on Android and the current Android mobile phones, check out our Android Guides
Sony Ericsson Xperia X10 Mini & Mini Pro get rooted
30 Jul 2010 7:47pm GMT
Huawei releases 2 new Android phones
Despite some pretty harsh claims against the company, Huawei has moved forward with it's business, andis now officially launching two Android phones. The U8300: and the U8500: There is very little known about the specification of these two devices, other than that they are both 3G enabled and have Qualcomm chips.. Independantly, the 8300 is capable of 3G [...]
For more information on Android and the current Android mobile phones, check out our Android Guides
Huawei releases 2 new Android phones
30 Jul 2010 7:32pm GMT
27 Jul 2010
Android Developers Blog
Licensing Service Technology Highlights
We've just announced the introduction of a licensing server for Android Market. This should address one of the concerns we've heard repeatedly from the Android developer community.
The impact and intent, as outlined in the announcement, are straightforward. If you want to enable your app to use the licensing server, there's no substitute for reading the authoritative documentation: Licensing Your Applications. Here are some technical highlights.
-
This capability has been in the Android Market client app since 1.5, so you don't have to be running the latest Android flavor to use it.
-
It's secure, based on a public/private key pair. Your requests to the server are signed with the public key and the responses from the server with the private key. There's one key pair per publisher account.
-
Your app doesn't talk directly to the licensing server; it IPCs to the Android Market client, which in turn takes care of talking to the server.
-
There's a substantial tool-set that will ship with the SDK, the License Verification Library (LVL). It provides straightforward entry points for querying the server and handling results. Also, it includes modules that you can use to implement certain licensing policies that we expect to be popular.
-
LVL is provided in source form as an Android Library project. It also comes with a testing framework.
-
There's a Web UI on the publisher-facing part of the Market's Web site for key management; it includes setup for production and testing.
-
Obviously, you can't call out to the server when the device is off-network. In this situation you have to decide what to do; one option is to cache licensing status, and LVL includes prebuilt modules to support that.
We think this is a major improvement over the copy-protection option we've offered up to this point, and look forward to feedback from developers.
27 Jul 2010 9:00pm GMT
Licensing Service For Android Applications
[This post is by Eric Chu, Android Developer Ecosystem. - Tim Bray]
In my conversations with Android developers, I often hear that you'd like better protection against unauthorized use of your applications. So today, I'm pleased to announce the release of a licensing service for applications in Android Market.
This simple and free service provides a secure mechanism to manage access to all Android Market paid applications targeting Android 1.5 or higher. At run time, with the inclusion of a set of libraries provided by us, your application can query the Android Market licensing server to determine the license status of your users. It returns information on whether your users are authorized to use the app based on stored sales records.
This licensing service operating real time over the network provides more flexibility in choosing license-enforcement strategies, and a more secure approach in protecting your applications from unauthorized use, than copy protection.
The licensing service is available now; our plan is for it to replace the current Android Market copy-protection mechanism over the next few months. I encourage you to check out the Licensing Your Applications section of our Developer Guide and the Android Market Help Center to learn how you can take advantage of this new service immediately.
27 Jul 2010 5:00pm GMT
24 Jul 2010
Android Developers Blog
Adjustment to Market Legals
Please note that we have updated the Android Market Developer Distribution Agreement (DDA). This is in preparation for some work we're doing on introducing new payment options, which we think developers will like.
In the spirit of transparency, we wanted to highlight the changes:
-
In Section 13.1, "authorized carriers" have been added as an indemnified party.
-
Section 13.2 is new in its entirety, covering indemnity for payment processors for claims related to tax accrual.
These new terms apply immediately to anyone joining Android Market as a new publisher. Existing publishers have been notified of this change via email; they have up to 30 days to sign into the Android Market developer console to accept the new terms.
24 Jul 2010 12:24am GMT
19 Jul 2010
Android Developers Blog
Multithreading For Performance
[This post is by Gilles Debunne, an engineer in the Android group who loves to get multitasked. - Tim Bray]
A good practice in creating responsive applications is to make sure your main UI thread does the minimum amount of work. Any potentially long task that may hang your application should be handled in a different thread. Typical examples of such tasks are network operations, which involve unpredictable delays. Users will tolerate some pauses, especially if you provide feedback that something is in progress, but a frozen application gives them no clue.
In this article, we will create a simple image downloader that illustrates this pattern. We will populate a ListView with thumbnail images downloaded from the internet. Creating an asynchronous task that downloads in the background will keep our application fast.
An Image downloader
Downloading an image from the web is fairly simple, using the HTTP-related classes provided by the framework. Here is a possible implementation:
static Bitmap downloadBitmap(String url) {
final AndroidHttpClient client = AndroidHttpClient.newInstance("Android");
final HttpGet getRequest = new HttpGet(url);
try {
HttpResponse response = client.execute(getRequest);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w("ImageDownloader", "Error " + statusCode + " while retrieving bitmap from " + url);
return null;
}
final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
try {
inputStream = entity.getContent();
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (Exception e) {
// Could provide a more explicit error message for IOException or IllegalStateException
getRequest.abort();
Log.w("ImageDownloader", "Error while retrieving bitmap from " + url, e.toString());
} finally {
if (client != null) {
client.close();
}
}
return null;
}
A client and an HTTP request are created. If the request succeeds, the response entity stream containing the image is decoded to create the resulting Bitmap. Your applications' manifest must ask for the INTERNET to make this possible.
Note: a bug in the previous versions of BitmapFactory.decodeStream may prevent this code from working over a slow connection. Decode a new FlushedInputStream(inputStream) instead to fix the problem. Here is the implementation of this helper class:
static class FlushedInputStream extends FilterInputStream {
public FlushedInputStream(InputStream inputStream) {
super(inputStream);
}
@Override
public long skip(long n) throws IOException {
long totalBytesSkipped = 0L;
while (totalBytesSkipped < n) {
long bytesSkipped = in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L) {
int byte = read();
if (byte < 0) {
break; // we reached EOF
} else {
bytesSkipped = 1; // we read one byte
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}
This ensures that skip() actually skips the provided number of bytes, unless we reach the end of file.
If you were to directly use this method in your ListAdapter's getView method, the resulting scrolling would be unpleasantly jaggy. Each display of a new view has to wait for an image download, which prevents smooth scrolling.
Indeed, this is such a bad idea that the AndroidHttpClient does not allow itself to be started from the main thread. The above code will display "This thread forbids HTTP requests" error messages instead. Use the DefaultHttpClient instead if you really want to shoot yourself in the foot.
Introducing asynchronous tasks
The AsyncTask class provides one of the simplest ways to fire off a new task from the UI thread. Let's create an ImageDownloader class which will be in charge of creating these tasks. It will provide a download method which will assign an image downloaded from its URL to an ImageView:
public class ImageDownloader {
public void download(String url, ImageView imageView) {
BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
task.execute(url);
}
}
/* class BitmapDownloaderTask, see below */
}
The BitmapDownloaderTask is the AsyncTask which will actually download the image. It is started using execute, which returns immediately hence making this method really fast which is the whole purpose since it will be called from the UI thread. Here is the implementation of this class:
class BitmapDownloaderTask extends AsyncTask<String, Void, Bitmap> {
private String url;
private final WeakReference<ImageView> imageViewReference;
public BitmapDownloaderTask(ImageView imageView) {
imageViewReference = new WeakReference<ImageView>(imageView);
}
@Override
// Actual download method, run in the task thread
protected Bitmap doInBackground(String... params) {
// params comes from the execute() call: params[0] is the url.
return downloadBitmap(params[0]);
}
@Override
// Once the image is downloaded, associates it to the imageView
protected void onPostExecute(Bitmap bitmap) {
if (isCancelled()) {
bitmap = null;
}
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
The doInBackground method is the one which is actually run in its own process by the task. It simply uses the downloadBitmap method we implemented at the beginning of this article.
onPostExecute is run in the calling UI thread when the task is finished. It takes the resulting Bitmap as a parameter, which is simply associated with the imageView that was provided to download and was stored in the BitmapDownloaderTask. Note that this ImageView is stored as a WeakReference, so that a download in progress does not prevent a killed activity's ImageView from being garbage collected. This explains why we have to check that both the weak reference and the imageView are not null (i.e. were not collected) before using them in onPostExecute.
This simplified example illustrates the use on an AsyncTask, and if you try it, you'll see that these few lines of code actually dramatically improved the performance of the ListView which now scrolls smoothly. Read Painless threading for more details on AsyncTasks.
However, a ListView-specific behavior reveals a problem with our current implementation. Indeed, for memory efficiency reasons, ListView recycles the views that are displayed when the user scrolls. If one flings the list, a given ImageView object will be used many times. Each time it is displayed the ImageView correctly triggers an image download task, which will eventually change its image. So where is the problem? As with most parallel applications, the key issue is in the ordering. In our case, there's no guarantee that the download tasks will finish in the order in which they were started. The result is that the image finally displayed in the list may come from a previous item, which simply happened to have taken longer to download. This is not an issue if the images you download are bound once and for all to given ImageViews, but let's fix it for the common case where they are used in a list.
Handling concurrency
To solve this issue, we should remember the order of the downloads, so that the last started one is the one that will effectively be displayed. It is indeed sufficient for each ImageView to remember its last download. We will add this extra information in the ImageView using a dedicated Drawable subclass, which will be temporarily bind to the ImageView while the download is in progress. Here is the code of our DownloadedDrawable class:
static class DownloadedDrawable extends ColorDrawable {
private final WeakReference<BitmapDownloaderTask> bitmapDownloaderTaskReference;
public DownloadedDrawable(BitmapDownloaderTask bitmapDownloaderTask) {
super(Color.BLACK);
bitmapDownloaderTaskReference =
new WeakReference<BitmapDownloaderTask>(bitmapDownloaderTask);
}
public BitmapDownloaderTask getBitmapDownloaderTask() {
return bitmapDownloaderTaskReference.get();
}
}
This implementation is backed by a ColorDrawable, which will result in the ImageView displaying a black background while its download is in progress. One could use a "download in progress" image instead, which would provide feedback to the user. Once again, note the use of a WeakReference to limit object dependencies.
Let's change our code to take this new class into account. First, the download method will now create an instance of this class and associate it with the imageView:
public void download(String url, ImageView imageView) {
if (cancelPotentialDownload(url, imageView)) {
BitmapDownloaderTask task = new BitmapDownloaderTask(imageView);
DownloadedDrawable downloadedDrawable = new DownloadedDrawable(task);
imageView.setImageDrawable(downloadedDrawable);
task.execute(url, cookie);
}
}
The cancelPotentialDownload method will stop the possible download in progress on this imageView since a new one is about to start. Note that this is not sufficient to guarantee that the newest download is always displayed, since the task may be finished, waiting in its onPostExecute method, which may still may be executed after the one of this new download.
private static boolean cancelPotentialDownload(String url, ImageView imageView) {
BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
if (bitmapDownloaderTask != null) {
String bitmapUrl = bitmapDownloaderTask.url;
if ((bitmapUrl == null) || (!bitmapUrl.equals(url))) {
bitmapDownloaderTask.cancel(true);
} else {
// The same URL is already being downloaded.
return false;
}
}
return true;
}
cancelPotentialDownload uses the cancel method of the AsyncTask class to stop the download in progress. It returns true most of the time, so that the download can be started in download. The only reason we don't want this to happen is when a download is already in progress on the same URL in which case we let it continue. Note that with this implementation, if an ImageView is garbage collected, its associated download is not stopped. A RecyclerListener might be used for that.
This method uses a helper getBitmapDownloaderTask function, which is pretty straigthforward:
private static BitmapDownloaderTask getBitmapDownloaderTask(ImageView imageView) {
if (imageView != null) {
Drawable drawable = imageView.getDrawable();
if (drawable instanceof DownloadedDrawable) {
DownloadedDrawable downloadedDrawable = (DownloadedDrawable)drawable;
return downloadedDrawable.getBitmapDownloaderTask();
}
}
return null;
}
Finally, onPostExecute has to be modified so that it will bind the Bitmap only if this ImageView is still associated with this download process:
if (imageViewReference != null) {
ImageView imageView = imageViewReference.get();
BitmapDownloaderTask bitmapDownloaderTask = getBitmapDownloaderTask(imageView);
// Change bitmap only if this process is still associated with it
if (this == bitmapDownloaderTask) {
imageView.setImageBitmap(bitmap);
}
}
With these modifications, our ImageDownloader class provides the basic services we expect from it. Feel free to use it or the asynchronous pattern it illustrates in your applications to ensure their responsiveness.
Demo
The source code of this article is available online on Google Code. You can switch between and compare the three different implementations that are described in this article (no asynchronous task, no bitmap to task association and the final correct version). Note that the cache size has been limited to 10 images to better demonstrate the issues.
Future work
This code was simplified to focus on its parallel aspects and many useful features are missing from our implementation. The ImageDownloader class would first clearly benefit from a cache, especially if it is used in conjuction with a ListView, which will probably display the same image many times as the user scrolls back and forth. This can easily be implemented using a Least Recently Used cache backed by a LinkedHashMap of URL to Bitmap SoftReferences. More involved cache mechanism could also rely on a local disk storage of the image. Thumbnails creation and image resizing could also be added if needed.
Download errors and time-outs are correctly handled by our implementation, which will return a null Bitmap in these case. One may want to display an error image instead.
Our HTTP request is pretty simple. One may want to add parameters or cookies to the request as required by certain web sites.
The AsyncTask class used in this article is a really convenient and easy way to defer some work from the UI thread. You may want to use the Handler class to have a finer control on what you do, such as controlling the total number of download threads which are running in parallel in this case.
19 Jul 2010 6:41pm GMT
16 Jul 2010
Android Developers Blog
Market Statistics Adjustments
If you look closely today, you'll notice that some per-app Android Market statistics have lower values; not big differences, but noticeable in a few cases. We discovered last week that, starting in early June, certain events had been double-counted: installs, uninstalls, impressions, and so on. The most obvious symptom was (for paid apps) a discrepancy between the number of installs and the number of reported sales through Checkout.
The underlying problem has been corrected and following data repair, the reported statistics should now be accurate. Our apologies for the glitch.
16 Jul 2010 5:52am GMT
Android Market Welcomes Korea!
As of today, Android Market is open for business to application buyers in the Republic of Korea. We hope that this will make the outstanding Android devices now available in that nation even more useful and fun. We welcome the people of Korea, acknowledged everywhere as one of the world's most-wired societies, to the world of Android.
16 Jul 2010 4:33am GMT
12 Jul 2010
Android Developers Blog
How to have your (Cup)cake and eat it too
[This post is by Adam Powell, his second touchy-feely outing in just a few weeks. I asked him to send me a better picture than we ran last time, and got this in response. Photo by our own Romain Guy. - Tim Bray]
Android developers concerned with targeting every last device with their apps are no doubt familiar with this chart:
On July 1, 2010 this was the breakdown of active devices running different versions of the Android platform. With all of the new platform features added to the Android SDK in each version, this chart has many developers shouting the F-word when they are forced to choose between integrating newer platform features and providing their app to the widest possible audience.
Savvy Android developers already know that these two options aren't really mutually exclusive, but that straddling between them can be painful. In this post I'm going to show you that it doesn't have to be that way.
Several weeks ago we took a look at how to handle multitouch on Android 2.0 (Eclair) and above, and by the end we had a simple demo app. That app uses features exclusive to Android 2.2 (Froyo) which as of this writing hasn't had a chance to reach many devices yet. In this post we're going to refactor that demo to run on devices all the way back to Android 1.5 (Cupcake). If you'd like to follow along, start off by grabbing the code in the trunk of the android-touchexample project on Google Code.
The problem manifests
The uses-sdk tag in your AndroidManifest.xml can specify both a minSdkVersion and a targetSdkVersion. You can use this to declare that while your app is prepared to run on an older version of the platform, it knows about newer versions. Your app can now build against newer SDKs. However, if your code accesses newer platform functionality directly you will probably see something like this in the system log of devices running an older version of Android:
E/dalvikvm( 792): Could not find method android.view.MotionEvent.getX, referenced from method com.example.android.touchexample.TouchExampleView.onTouchEvent
W/dalvikvm( 792): VFY: unable to resolve virtual method 17: Landroid/view/MotionEvent;.getX (I)F
W/dalvikvm( 792): VFY: rejecting opcode 0x6e at 0x0006
W/dalvikvm( 792): VFY: rejected Lcom/example/android/touchexample/TouchExampleView;.onTouchEvent (Landroid/view/MotionEvent;)Z
W/dalvikvm( 792): Verifier rejected class Lcom/example/android/touchexample/TouchExampleView;
D/AndroidRuntime( 792): Shutting down VM
W/dalvikvm( 792): threadid=3: thread exiting with uncaught exception (group=0x4000fe70)
We broke the contract of minSdkVersion, and here is the result. When we build our app against SDK 8 (Froyo) but declare minSdkVersion="3" (Cupcake) we promise the system that we know what we're doing and we won't try to access anything that doesn't exist. If we mess this up, we see the above, and our users see an ugly error message.
Cue a lot of frustrated users and one-star ratings on Market. We need a safe way of accessing newer platform functionality without making the verifier angry on older platform versions.
Stop and reflect
Many Android developers are already familiar with the practice of accomplishing this through reflection. Reflection lets your code interface with the runtime, detect when certain methods or classes are present, and invoke or instantiate them without touching them directly.
The prospect of querying each platform feature individually and conditionally invoking it using reflection isn't pretty. It's ugly. It's slow. It's cumbersome. Most of all, heavy use can turn your app's codebase into an unmaintainable mess. What if I said there is a way to write Android apps that target Android 1.5 (Cupcake) through 2.2 (Froyo) and beyond with a single codebase and no reflection at all?
Lazy Loading
Computer science researcher Bill Pugh published and popularized a method of writing singletons in Java that takes advantage of the laziness of ClassLoaders. Wikipedia explains his solution further. The code looks like this:
public class Singleton {
// Private constructor prevents instantiation from other classes
private Singleton() {}
/**
* SingletonHolder is loaded on the first execution of Singleton.getInstance()
* or the first access to SingletonHolder.INSTANCE, not before.
*/
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
There is a very important guaranteed behavior at work here explained by the comment above SingletonHolder. Java classes are loaded and initialized on first access - instantiating the class or accessing one of its static fields or methods for the first time. This is relevant to us because classes are verified by the VM when they are loaded, not before. We now have everything we need to write Android apps that span versions without reflection.
Designing for compatibility
As it turns out this is fairly simple to apply. You generally will want your app to degrade gracefully on older platform versions, dropping features or providing alternate functionality when the platform support isn't available. Since Android platform features are tied to the API level you have only one axis to consider when designing for compatibility.
In most cases this version support can be expressed as a simple class hierarchy. You can design your app to access version-sensitive functionality through a version-independent interface or abstract class. Subclasses of that interface intended to run on newer platform versions will support newer platform features, and subclasses intended for older versions might need to present alternate ways for your users to access app functionality.
Your app can use a factory method, abstract factory, or other object creation pattern to instantiate the proper subclass at runtime based on the information exposed by android.os.Build.VERSION. This last step insures that the system will never attempt to load a class it can't verify, preserving compatibility.
The principle in practice
At the beginning of this post I said that we are going to refactor the touch example app from Making Sense of Multitouch to be compatible from API level 3 (Cupcake) on through API level 8 (Froyo). In that post I pointed out that GestureDetectors can be a useful pattern for abstracting the processing of touch events. At the time I didn't realize how soon that statement would be put to the test. We can refactor the version-specific elements of the demo app's touch handling into an abstract GestureDetector.
Before we begin the real work, we need to change our manifest to declare that we support API level 3 devices with minSdkVersion in the uses-sdk tag. Keep in mind that we're still targeting SDK 8, both with targetSdkVersion in our manifest and in our project configuration. Our manifest now looks like this:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.android.touchexample"
android:versionCode="1"
android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<activity android:name=".TouchExampleActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="3" android:targetSdkVersion="8" />
</manifest>
Our TouchExampleView class isn't compatible with Android versions prior to Froyo thanks to its use of ScaleGestureDetector, and it isn't compatible with versions prior to Eclair thanks to its use of the newer MotionEvent methods that return multitouch data. We need to abstract that functionality out into classes that will not be loaded on versions of the platform that don't support it. To do this, we will create the abstract class VersionedGestureDetector.
The example app allows the user to perform two gestures, drag and scale. VersionedGestureDetector will therefore publish two events to an attached listener, onDrag and onScale. TouchExampleView will obtain a VersionedGestureDetector instance appropriate to the platform version, filter incoming touch events through it, and respond to the resulting onDrag and onScale events accordingly.
The first pass of VersionedGestureDetector looks like this:
public abstract class VersionedGestureDetector {
OnGestureListener mListener;
public abstract boolean onTouchEvent(MotionEvent ev);
public interface OnGestureListener {
public void onDrag(float dx, float dy);
public void onScale(float scaleFactor);
}
}
We'll start with the simplest functionality first, the VersionedGestureDetector for Cupcake. For simplicity's sake in this example we will implement each version as a private static inner class of VersionedGestureDetector. You can organize this however you please, of course, as long as you use the lazy loading technique shown above or some equivalent. Don't touch any class that directly accesses functionality not supported by your platform version.
private static class CupcakeDetector extends VersionedGestureDetector {
float mLastTouchX;
float mLastTouchY;
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
mLastTouchX = ev.getX();
mLastTouchY = ev.getY();
break;
}
case MotionEvent.ACTION_MOVE: {
final float x = ev.getX();
final float y = ev.getY();
mListener.onDrag(x - mLastTouchX, y - mLastTouchY);
mLastTouchX = x;
mLastTouchY = y;
break;
}
}
return true;
}
}
This simple implementation dispatches onDrag events whenever a pointer is dragged across the touchscreen. The values it passes are the X and Y distances traveled by the pointer.
In Eclair and later we will need to properly track pointer IDs during drags so that our draggable object doesn't jump around as extra pointers enter and leave the touchscreen. The base implementation of onTouchEvent in CupcakeDetector can handle drag events for us with a few tweaks. We'll add the methods getActiveX and getActiveY to fetch the appropriate touch coordinates and override them in EclairDetector to get the coordinates from the correct pointer:
private static class CupcakeDetector extends VersionedGestureDetector {
float mLastTouchX;
float mLastTouchY;
float getActiveX(MotionEvent ev) {
return ev.getX();
}
float getActiveY(MotionEvent ev) {
return ev.getY();
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
mLastTouchX = getActiveX(ev);
mLastTouchY = getActiveY(ev);
break;
}
case MotionEvent.ACTION_MOVE: {
final float x = getActiveX(ev);
final float y = getActiveY(ev);
mListener.onDrag(x - mLastTouchX, y - mLastTouchY);
mLastTouchX = x;
mLastTouchY = y;
break;
}
}
return true;
}
}
And now EclairDetector, overriding the new getActiveX and getActiveY methods. Most of this code should be familiar from the original touch example:
private static class EclairDetector extends CupcakeDetector {
private static final int INVALID_POINTER_ID = -1;
private int mActivePointerId = INVALID_POINTER_ID;
private int mActivePointerIndex = 0;
@Override
float getActiveX(MotionEvent ev) {
return ev.getX(mActivePointerIndex);
}
@Override
float getActiveY(MotionEvent ev) {
return ev.getY(mActivePointerIndex);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
switch (action & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mActivePointerId = ev.getPointerId(0);
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
mActivePointerId = INVALID_POINTER_ID;
break;
case MotionEvent.ACTION_POINTER_UP:
final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK)
>> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
final int pointerId = ev.getPointerId(pointerIndex);
if (pointerId == mActivePointerId) {
// This was our active pointer going up. Choose a new
// active pointer and adjust accordingly.
final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
mActivePointerId = ev.getPointerId(newPointerIndex);
mLastTouchX = ev.getX(newPointerIndex);
mLastTouchY = ev.getY(newPointerIndex);
}
break;
}
mActivePointerIndex = ev.findPointerIndex(mActivePointerId);
return super.onTouchEvent(ev);
}
}
EclairDetector calls super.onTouchEvent after determining the active pointer index and lets CupcakeDetector take care of dispatching the drag event. Supporting multiple platform versions doesn't have to mean code duplication.
Finally, let's add scale gesture support for Froyo devices that have ScaleGestureDetector. We'll need a couple more changes to CupcakeDetector first; we don't want to drag normally while scaling. Some devices have touchscreens that don't deal well with it, and we would want to handle it differently on devices that do anyway. We'll add a shouldDrag method to CupcakeDetector that we'll check before dispatching onDrag events.
The final CupcakeDetector:
private static class CupcakeDetector extends VersionedGestureDetector {
float mLastTouchX;
float mLastTouchY;
float getActiveX(MotionEvent ev) {
return ev.getX();
}
float getActiveY(MotionEvent ev) {
return ev.getY();
}
boolean shouldDrag() {
return true;
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN: {
mLastTouchX = getActiveX(ev);
mLastTouchY = getActiveY(ev);
break;
}
case MotionEvent.ACTION_MOVE: {
final float x = getActiveX(ev);
final float y = getActiveY(ev);
if (shouldDrag()) {
mListener.onDrag(x - mLastTouchX, y - mLastTouchY);
}
mLastTouchX = x;
mLastTouchY = y;
break;
}
}
return true;
}
}
EclairDetector remains unchanged. FroyoDetector is below. shouldDrag will return true as long as we do not have a scale gesture in progress:
private static class FroyoDetector extends EclairDetector {
private ScaleGestureDetector mDetector;
public FroyoDetector(Context context) {
mDetector = new ScaleGestureDetector(context,
new ScaleGestureDetector.SimpleOnScaleGestureListener() {
@Override public boolean onScale(ScaleGestureDetector detector) {
mListener.onScale(detector.getScaleFactor());
return true;
}
});
}
@Override
boolean shouldDrag() {
return !mDetector.isInProgress();
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
mDetector.onTouchEvent(ev);
return super.onTouchEvent(ev);
}
}
Now that we have our detector implementations in order we need a way to create them. Let's add a factory method to VersionedGestureDetector:
public static VersionedGestureDetector newInstance(Context context,
OnGestureListener listener) {
final int sdkVersion = Integer.parseInt(Build.VERSION.SDK);
VersionedGestureDetector detector = null;
if (sdkVersion < Build.VERSION_CODES.ECLAIR) {
detector = new CupcakeDetector();
} else if (sdkVersion < Build.VERSION_CODES.FROYO) {
detector = new EclairDetector();
} else {
detector = new FroyoDetector(context);
}
detector.mListener = listener;
return detector;
}
Since we're targeting Cupcake, we don't have access to Build.VERSION.SDK_INT yet. We have to parse the now-deprecated Build.VERSION.SDK instead. But why is accessing Build.VERSION_CODES.ECLAIR and Build.VERSION_CODES.FROYO safe? As primitive static final int constants, these are inlined by the compiler at build time.
Our VersionedGestureDetector is ready. Now we just need to hook it up to TouchExampleView, which has become considerably shorter:
public class TouchExampleView extends View {
private Drawable mIcon;
private float mPosX;
private float mPosY;
private VersionedGestureDetector mDetector;
private float mScaleFactor = 1.f;
public TouchExampleView(Context context) {
this(context, null, 0);
}
public TouchExampleView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TouchExampleView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mIcon = context.getResources().getDrawable(R.drawable.icon);
mIcon.setBounds(0, 0, mIcon.getIntrinsicWidth(), mIcon.getIntrinsicHeight());
mDetector = VersionedGestureDetector.newInstance(context, new GestureCallback());
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
mDetector.onTouchEvent(ev);
return true;
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.save();
canvas.translate(mPosX, mPosY);
canvas.scale(mScaleFactor, mScaleFactor);
mIcon.draw(canvas);
canvas.restore();
}
private class GestureCallback implements VersionedGestureDetector.OnGestureListener {
public void onDrag(float dx, float dy) {
mPosX += dx;
mPosY += dy;
invalidate();
}
public void onScale(float scaleFactor) {
mScaleFactor *= scaleFactor;
// Don't let the object get too small or too large.
mScaleFactor = Math.max(0.1f, Math.min(mScaleFactor, 5.0f));
invalidate();
}
}
}
Wrapping up
We've now adapted the touch example app to work from Android 1.5 on through the latest and greatest, taking advantage of newer platform features as available without a single reflective call. The same principles shown here can apply to any new Android feature that you want to use while still allowing your app to run on older platform versions:
-
The
ClassLoaderloads classes lazily and will only load and verify classes on first access. -
Factor out app functionality that can differ between platform versions with a version-independent interface or abstract class.
-
Instantiate a version-dependent implementation of it based on the platform version detected at runtime. This keeps the
ClassLoaderfrom ever touching a class that it will not be able to verify.
To see the final cross-version touch example app, check out the "cupcake" branch of the android-touchexample project on Google Code.
Extra Credit
In this example we didn't provide another way for pre-Froyo users to zoom since ScaleGestureDetector was only added as a public API for 2.2. For a real app we would want to offer some alternate affordance to users. Traditionally Android offers a set of small tappable zoom buttons along the bottom of the screen. The ZoomControls and ZoomButtonsController classes in the framework can help you present these controls to the user in a standard way. Implementing this is left as an exercise for the reader.
12 Jul 2010 10:29pm GMT
08 Jul 2010
Android Developers Blog
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_UNAVAILABLEwith 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_AVAILABLEwith 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.
08 Jul 2010 10:07pm GMT
Android 2.2 SDK refresh
As you may have noticed, the source code for Android 2.2, which we call Froyo, has been released.
The Android 2.2 SDK that was released at Google I/O contained a preview of the Froyo system image and today, we are releasing an update to bring it into sync with the system image pushed to Nexus One devices.
I encourage all developers to use the SDK manager to update to this version.
08 Jul 2010 6:00pm GMT
07 Jul 2010
Android Developers Blog
Android Love at OSCON
Android developers who aren't already going should take a moment to check out the OSCON 2010 schedule, and give serious thought to a trip to Portland in a couple of weeks. OSCON is one of the world's premiere events for those who care about Open Source, and one of my personal favorite conferences, with a powerful community vibe. And this year, the Android drums are sounding.
There are a bunch of mobile and Android-related sessions, both pure and extremely impure; for example, I bet both Steve Jobs and I are dubious about Cross-Compiling Android Applications to the iPhone. There's a full-dress Android for Java Developers tutorial. And (the one I helped cook up) there's the Android Hands-On; last I heard, registration for that is approaching 200 and, since O'Reilly found us a big room, it's not full up; but it will be.
On top of which, there are going to be a herd of Googlers at OSCON, and a sub-herd of Androiders, including Dan Morrill and Justin Mattson and me. This isn't surprising; what does surprise me is that OSCON hasn't previously been an Android love-fest. Because if you're interested in mobile devices and have a hankering for Open Source, Android is for you.
07 Jul 2010 8:39pm GMT
24 Jun 2010
Android Developers Blog
Exercising Our Remote Application Removal Feature
[This post is by Rich Cannings, Android Security Lead. - Tim Bray]
Every now and then, we remove applications from Android Market due to violations of our Android Market Developer Distribution Agreement or Content Policy. In cases where users may have installed a malicious application that poses a threat, we've also developed technologies and processes to remotely remove an installed application from devices. If an application is removed in this way, users will receive a notification on their phone.
Recently, we became aware of two free applications built by a security researcher for research purposes. These applications intentionally misrepresented their purpose in order to encourage user downloads, but they were not designed to be used maliciously, and did not have permission to access private data - or system resources beyond permission.INTERNET. As the applications were practically useless, most users uninstalled the applications shortly after downloading them.
After the researcher voluntarily removed these applications from Android Market, we decided, per the Android Market Terms of Service, to exercise our remote application removal feature on the remaining installed copies to complete the cleanup.
The remote application removal feature is one of many security controls Android possesses to help protect users from malicious applications. In case of an emergency, a dangerous application could be removed from active circulation in a rapid and scalable manner to prevent further exposure to users. While we hope to not have to use it, we know that we have the capability to take swift action on behalf of users' safety when needed.
This remote removal functionality - along with Android's unique Application Sandbox and Permissions model, Over-The-Air update system, centralized Market, developer registrations, user-submitted ratings, and application flagging - provides a powerful security advantage to help protect Android users in our open environment.
24 Jun 2010 5:35am GMT
23 Jun 2010
Android Developers Blog
Android Market Problem
Earlier today we had a brief outage in Android Market. For a period of about thirty minutes, some users were unable to find any apps. The problem was detected and corrected, and we believe the user experience is now back to normal. We apologize for the outage.
23 Jun 2010 10:08pm GMT
The Froyo Code Drop
[This post is by Jean-Baptiste Queru, who moves truck-loads of source code in and out of the Googleplex. - Tim Bray]
Today is one of those days that has my heart racing; we've just released the source code for Android 2.2. This is a big step forward for the entire Android ecosystem. Please don't melt the servers down again while trying to download that latest source code.
This blog typically talks about developing Android applications using the SDK and NDK. However, the skills of a platform contributor aren't fundamentally different from those of an application developer. Those are simply different roles using the same skill set. I'm providing an update here to the experienced Android programmers all around the world on some of the recent developments in the Android Open-Source Project.
For Google engineers working on Android, releases are mostly known by their code names which are chosen alphabetically after tasty treats. I'll call Android 2.2 "Froyo" throughout this post, since that was its code name. Raw version numbers don't make me salivate as much as the thought of a cold dessert in the California summer.
Let's have a look at some cool aspects of the new Froyo source, and let's then take a few steps back to look at other noteworthy aspects of the Android Open-Source Project.
I had been increasingly involved in all previous open-source releases of Android, from testing the initial code drop to doing all the open-source-related git-level work in Eclair. Following that path, Froyo is the first release where my primary focus has been the Android Open-Source Project from start to finish. I thank the entire Android team for helping me all along with much of that work. Here are some aspects of Froyo that I am proud of, and that kept me busy for the last few months:
-
Hundreds of platform changes that people everywhere uploaded to the Android Open-Source Project were accepted and merged into Froyo. That process is now a well-oiled machine and will translate well to future contributions.
-
The open-source release happened in a single step. The whole source tree for the entire Android 2.2 platform is now available, with its full change history. That will accelerate everyone's migration to Froyo from older releases. It is also already fully merged into the open-source master tree. Consequently, we can immediately review and accept platform contributions based on Froyo. That will therefore reduce the risk of merge conflicts between contributions to the open-source tree and changes in Google's internal master tree where those contributions are meant to end up.
-
In order to make it easier for device manufacturers and custom system builders to use Froyo, we've restructured our source tree to better separate closed-source modules from open-source ones. We've made many changes to the open-source code itself to remove unintentional dependencies on closed-source software. We've also incorporated into the core platform all the configuration files necessary to build the source code of Android Open-Source Project on its own. You can now build and boot a fully open-source system image out of the box, for the emulator, as well as for Dream (ADP1), Sapphire (ADP2), and Passion (Nexus One).
-
Speaking of device support, we also open-sourced several additional hardware-related libraries that had been closed-source in previous releases, which will open the door to more contributions. Some examples are the recovery UI code for Dream, Sapphire and Passion, and the interface between the media framework and Qualcomm chipsets.
Besides the Froyo source code release, I wanted to mention several other improvements in the Android Open-Source Project:
-
We've been receiving contributions from more than twenty different companies, and many individuals. We have close to 4,000 registered users on the Gerrit code review server, with an average of 2 contributions per user. Those contributions have been in all areas of the system, from the depth of the C library all the way to the UI of the lock screen. They've covered the full range of complexities, from fixing typos in the documentation or reformatting code to adding developer-visible APIs or user-visible features. I want to thank everyone who got involved for their work and patience.
-
We're now responding to platform contributions faster, with most changes currently getting looked at within a few business days of being uploaded, and few changes staying inactive for more than a few weeks at a time. We're trying to review early and review often. As I'm typing this, only about a dozen platform contributions haven't been looked at yet, with the oldest of those being 3 days old. More than 90% of contributions to the platform code itself have been actively looked at during the last 2 weeks. I hope that the speedy process will lead to more interactivity during the code reviews. I realize nevertheless that time differences around the world can make real-time communication a challenge.
-
Over the last 2 months, we've reached a final decision on more than 1,000 changes that were uploaded to our public Gerrit server. That means that those changes were either accepted or rejected after being reviewed. The high quality of the contributions we've been receiving throughout the history of the Android Open-Source Project has allowed us to steadily merge about 80% of them into the main repository, from where they migrate to official releases. That means that an average of 20 changes have been accepted through the Android Open-Source Project into the public git repositories every business day over those last 2 months.
-
We recently created two new official Google Groups related to the Android Open-Source Project. Android-building is meant to specifically discuss build issues (be sure to search the archives thoroughly before posting). Android-contrib is used to discuss actual contributions (don't post if you don't really intend to contribute and follow through on the review process, and if you haven't already spent an hour or two researching things on your own).
-
We're developing the developer tools directly in the open-source project, with no work in those areas happening behind closed doors. This covers the Eclipse plug-in and the emulator, and more than a dozen other SDK-related tools.
-
Once a platform version is open-sourced, all improvements to the Compatibility Test Suite related to that version are made directly to the open-source tree. In fact, release 2 of the 2.1 CTS was done 100% that way, with the development, testing and release process all happening straight in the open-source tree. This is now true for Froyo as well, and we are now accepting contributions into the Froyo branch of the CTS project.
I believe that those last two aspects are important to application developers. If you're an application developer and you'd like to improve the tools that you and your fellow developers use, the process to make changes in that area is now a lot more transparent. Similarly, if during application development you find incompatibilities between devices and believe that those incompatibilities aren't within the letter or the spirit of Android compatibility, you can help improve the situation by contributing a CTS test for that area.
With Android 2.2 now being available to the open-source world, and with the review process working smoothly, I'm looking forward to seeing a lot more high-quality contributions that will be used to build future versions of Android. My sweetest dream, which is also my worst nightmare, is to have so many contributions that I can't keep up with them. Please don't wake me up.
23 Jun 2010 3:35pm GMT
22 Jun 2010
Android Developers Blog
Hands-on at OSCON
This year at OSCON we and O'Reilly are co-presenting Android Hands-on. The event is on the evening of Wednesday, July 21 after the Expo-hall reception. Led by Google Android experts, the Hands-on will run from 7:00 pm-10:00 pm, and will be intense, technical, and structured. The goal is that you leave the room with foundation skills for writing interesting code for an open-source stack that runs on a pocket-sized Internet-connected device.
Some specific topics we'll cover:
-
Porting existing C codebases to Android
-
Integrating Android apps with RESTful web interfaces
-
UI patterns and best practices
Sign-up in advance is required, and is restricted to registered full conference attendees and speakers. Spaces are limited and will be given out on a first-come-first-served basis.
If you're considering participating, you might want to keep these things in mind:
-
Android apps are written in the Java programming language, with the exception of some performance-critical code (typically for games) written in C and C++. If you aren't familiar with at least one of these languages, you won't benefit much from the session.
-
To prepare, you might want to go to developer.android.com and download the SDK (available for Linux, Mac, and even Windows). Try building the HelloAndroid app and running it on the emulator.
-
You might also benefit from attending the Android for Java developers tutorial on Monday and/or Dan Morrill's Android: The Whats and Wherefores session on Wednesday morning.
22 Jun 2010 9:22pm GMT
21 Jun 2010
Android Developers Blog
Future-Proofing Your App
[This post is by Reto Meier AKA @retomeier, who wrote the book on Android App development. - Tim Bray]
As a developer, I'm excited by Android's potential as a single development platform that can make my apps available on a wide range of devices. From smartphones to televisions, Android is now being used on an increasingly diverse collection of hardware.
Last year's Android SDK 1.6 release was the first to introduce support for variations in device hardware, paving the way for devices like the HTC Tattoo - a small screen device with a non-autofocus camera. Future devices, like Google TV, may not include some of the hardware features that we now expect, such a accelerometers and telephony.
We all want our apps available on as many devices as possible, but on some hardware they might just not make sense, so it's important that apps are available only on the devices where they do.
Android Market Rule #1: Don't let existing applications break on new devices
As curators of the Android Market, one of our most important responsibilities is ensuring consumers and developers can trust the Market to only deliver applications to devices capable of running them.
The Android SDK includes built-in support for specifying which hardware features your application needs, ensuring that when we see more hardware variations, the Market will make sure your apps are available everywhere (and only where) they make sense.
Specify the hardware your app needs using the application Manifest
That includes the target and minimum SDK versions, supported screen sizes, and the required hardware features without which your app will "break". You can specify the hardware features your app requires by adding a uses-feature node to your manifest.
<uses-feature android:name="android.hardware.microphone" />
By updating your manifest now to include all the hardware features you require, you effectively opt out of future hardware that won't be capable of properly supporting your app.
Android Market Rule #2: Don't let existing applications break on new devices
In extreme cases - such as the introduction of small screen sizes in Android 1.6 - developers will be required to explicitly opt in their apps before they will be made visible in the Market on these new devices.
In other cases the Android Market will analyze the permissions requested by an app to determine if it implies a dependence on any particular hardware. For example, requiring the CALL_PHONE permission strongly implies the need for telephony hardware.
Until we provide a more convenient tool, you can use AAPT in the SDK to analyze your apps (2.2 SDK required) and see which device requirements are being implicitly added to your application:
aapt dump badging myApp.apk
Where your app uses a particular hardware feature, but you know (and have tested) that it will still work without it, you can specify it as optional by setting the required attribute to false.
<uses-feature android:name="android.hardware.telephony" android:required="false" />
Ensure your application manifest correctly identifies what hardware your app needs, and what is optional
With the uses-feature name strings now available, you can ensure right now that your app appears in the Market, where appropriate, on current and future hardware devices rather than waiting for the devices to be released.
It's in your interest as a developer to ensure your apps work well, and are available, on as many devices as possible and appropriate. Now is the time to test your applications and update your Manifest to opt in to all hardware configurations which you support, and opt out of those that don't make sense.
21 Jun 2010 5:30pm GMT
15 Jun 2010
Android Developers Blog
Game Development for Android: A Quick Primer
[This post is by Chris Pruett, an outward-facing Androider who focuses on the world of games. - Tim Bray]
If you attended Google I/O this year, you might have noticed the large number of game developers showing off their stuff in the Android part of the Developer Sandbox. Unity, EA, Com2Us, Polarbit, Laminar Research, and several others demonstrated high-end games running on Android devices. Part of my role as a Game Developer Advocate for Android is to field requests for information about Android from game developers, and in the last six months the number of requests has gone through the roof. Since there's clearly a huge amount of interest in Android game development, here's an overview of how Android games work and what you as a developer should know.
Step One: Decide on a Target Device Class
There are basically two types of devices running Android that you should consider: lower-end devices like the G1 (which I'll call "first generation" devices), and high-end devices like the Nexus One ("second generation" devices). Though there are a lot of different Android phones on the market, they fall rather neatly into these two classes when it comes to CPU and graphics performance, which are the variables that game developers usually care the most about.
First generation devices are generally phones with HVGA screens, running Android 1.5 or 1.6 (though a few are starting to make their way to 2.1), typically with an 500mhz CPU and hardware accelerated OpenGL ES 1.0 backend. A large number of devices sport internals similar to the G1 (Qualcomm MSM7K CPU/GPU at ~500mhz), so the G1 is representative of this class (and can be safely considered the low end of the spectrum). Based on my tests, these devices can push about 5000 textured, colored, unlit vertices per frame and still maintain 30 frames per second. Using OpenGL ES to draw, I can get just over 250 animating sprites on the screen at 30 frames per second (at 60 fps I can draw just over 100 sprites per frame). These aren't hard numbers; my benchmarks are fairly primitive, and I'm sure that they can be improved (for example, I haven't done tests using the GL_OES_point_sprite extension, which the G1 supports). But they should give you an idea of what the first generation class of devices can do.
Second generation devices generally have WVGA screens, much faster CPUs and GPUs, and support for OpenGL ES 2.0. The Nexus One and Verizon Droid by Motorola are both good examples of this class. These devices seem to be about 5x faster than the first generation devices when it comes to raw OpenGL 1.0 performance (I can get at least 27,000 textured unlit colored vertices per frame at 30 frames per second on all of the second generation devices I've tested). Using OpenGL ES 2.0 can be even faster, as these devices typically incur some overhead translating OpenGL ES 1.0 commands to their 2.0-native graphics hardware. However, the large screens on these devices often mean that they are fill-bound: the cost of filling the screen with pixels is high enough that it's often not possible to draw faster than 30 frames per second, regardless of scene complexity.
Since there is a pretty wide performance delta between the first generation class of devices and the second, you should be careful when selecting a target. Based on our metrics about Android versions, first generation devices represent over half of all of the Android phones on the market (as of this writing, anyway; 2.0 devices are growing very quickly). Those games that are able to scale between the first and second generation devices have the largest audience.
Step Two: Pick a Language
If you're an Android app programmer who's thinking about getting into game development, chances are you are planning on writing code in Java. If you're a game development veteran who's thinking of bringing games to Android, it's likely that you prefer to do everything in C++.
The side-scrolling action game that I wrote, Replica Island, is entirely Java. It uses OpenGL ES 1.0 to draw and is backwards compatible to Android 1.5. It runs at a good frame rate (close to 60 fps on the G1) across almost all Android devices. In fact, many of the popular games on Android Market were written in Java, so if you're the type of person who finds coding in C++ like speaking in tongues, you can rest easy in the knowledge that Java on Android is perfectly viable for games.
That said, native code is the way to go if your game needs to run as fast as possible. We've just released the fourth revision of our Native Development Kit for Android, and it includes a number of improvements that are particularly useful to game developers. Using the NDK, you can compile your code into a shared library, wrap it in a thin Java shell to manage input and lifecycle events, and do all of the heavy lifting in C++ with regular OpenGL ES APIs. As of Revision 4, you can also draw directly into Java Bitmap pixel buffers from native code, which should be faster than loading bitmaps as GL textures every frame for 2D games that want to do their own scene compositing. Revision 4 also (finally!) includes gdb support for debugging your native code on the device.
You should know that when using the NDK, you don't have access to Android Framework APIs. There's no way, for example, to play audio from C++ (though we announced at Google I/O our intention to support OpenSL ES in the future). Some developers use the AudioTrack API to share a direct buffer with native code that mixes and generates a PCM stream on the fly, and many call from C++ into the Java SoundPool interface. Just be aware that for this type of work, a jump through JNI back into Java code is required.
Step Three: Carefully Design the Best Game Ever
Once you have a target system spec and have decided on a development environment, you're off and running. But before you get too deep into your epic ragdoll physics-based space marine action online RPG with branching endings and a morality system, take a minute to think about your end users. Specifically, there are two areas that require consideration for Android games that you might not be used to: texture compression and input systems.
Texture compression is a way to (surprise!) compress your texture data. It can improve draw performance and let you pack more texture into vram. The problem with texture compression is that different graphics card vendors support different texture formats. The G1 and other MSM7k devices support ATI's ATITC compression format. The Droid supports PowerVR's PVRTC format. Nvidia's Tegra2 platform supports the DXT format. The bad news is, these formats are not compatible. The good news is, all OpenGL ES 2.0 devices (including the Snapdragon-based Nexus One, the OMAP3-based Droid, and Tegra2 devices) support a common format called ETC1. ETC1 isn't the best texture format (it lacks support for alpha channels), and it isn't supported on the first generation devices, but it's the most common format supported (the Android SDK provides a compressor utility (see sdk/tools/etc1tool) and runtime tools for this format).
The bottom line is that if you compress your textures, you'll need to somehow provide different versions of those textures compressed with different formats. You could do this all in a single apk, or you could download textures from a web site over HTTP, or you could use ETC1 and restrict yourself to only OpenGL ES 2.0 devices. For Replica Island, I just chose not to compress my textures at all and had no problems. You can query the GL_EXTENSIONS string to see what the device you are currently running on supports.
String extensions = " " + gl.glGetString(GL10.GL_EXTENSIONS) + " ";
String version = gl.glGetString(GL10.GL_VERSION);
String renderer = gl.glGetString(GL10.GL_RENDERER);
boolean isSoftwareRenderer = renderer.contains("PixelFlinger");
// On 1.6 and newer, we could use ActivityManager.getDeviceConfigurationInfo() to get the GL version.
// To include 1.5, I'll use the GL version string.
boolean isOpenGL10 = version.contains(" 1.0");
boolean supportsDrawTexture =
extensions.contains(" GL_OES_draw_texture "); // draw_texture extension
boolean supportsETC1 =
extensions.contains(" GL_OES_compressed_ETC1_RGB8_texture "); // standard ETC1 support extension
// VBOs are guaranteed in GLES1.1, but they were an extension under 1.0.
// There's no point in using VBOs when using the software renderer (though they are supported).
boolean supportsVBOs =
!isSoftwareRenderer && (!isOpenGL10 || extensions.contains("vertex_buffer_object "));
You should also think carefully about how your game will be played. Some phones have a trackball, some have a directional pad, some have a hardware keyboard, some support multitouch screens. Others have none of those things. Per the Compatibility Definition Document, all Android devices that have Android Market are required to have a touch screen and three-axis accelerometer, so if you can get away with just tilt and single touch, you don't need to worry about input much. If you want to take advantage of the various input devices that these phones support (which, based on several thousand comments on Android Market about Replica Island, I wholeheartedly recommend), the Android API will package the events up for you in a standard way.
That said, one of the most dramatic lessons I learned after shipping Replica Island is that users want customizable controls. Even if you have added perfect support for every phone, many users will want to go in and tweak it. Or they prefer the hardware keyboard over their phone's dpad. Or they prefer tilt controls over trackball controls. My advice: plan on providing customizable controls, both so that you can support phones that have input configurations that you didn't consider, and also so that you can allow users to tweak the experience to match their preferences.
Step Four: Profit!
The rest is up to you. But before you go, here are a few resources that might come in handy:
-
HeightMapProfiler. This is a simple 3D benchmarking tool that I wrote. It is the source of the performance numbers in this post. You can also use it to test how various GL state affects performance on your device (texture size, texture filtering, mip-mapping, etc).
-
SpriteMethodTest. Another simple benchmarking tool, this one for sprite drawing. This code is also useful as a 2D game skeleton application.
-
GLSurfaceView. This is a Java class that makes it trivial to set up an OpenGL ES application. You can use this code in combination with the NDK or with Java alone.
-
Quake Port. The complete source for an Android port of Quake has been made available by Jack Palevich, an Android team engineer. It's a great sample of how to mix Java and native code, how to download textures to the sdcard over HTTP, and all kinds of other cool stuff (check out his memory-mapped-to-sdcard texture manager).
-
Replica Island. Here's the complete source to my game, released under Apache2. Use it as a reference, or to make your own games.
15 Jun 2010 5:33pm GMT











