<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-9106822915308030165</id><updated>2012-01-27T21:23:04.506-08:00</updated><category term='logcat'/><category term='xml'/><category term='instrumentation'/><category term='io'/><category term='aidl'/><category term='android'/><category term='java'/><category term='imap'/><category term='g1'/><category term='rss'/><category term='unit testing'/><category term='email'/><category term='andriod'/><category term='oha'/><category term='five'/><category term='vogue'/><category term='vnc'/><category term='concurrency'/><category term='google'/><category term='httpclient'/><title type='text'>devtcg</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>21</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-6284079361024140657</id><published>2010-04-13T15:02:00.001-07:00</published><updated>2010-04-13T15:48:00.192-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='logcat'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Logcat, Improved.</title><content type='html'>Logcat is a staple for most Android developers out there and I'm certainly no exception.  I often have at least one terminal dedicated to logcat with sometimes many more with various combinations of options to control how I'm filtering the output.&lt;br /&gt;&lt;br /&gt;Recently it occurred to me that most of this work is designed to separate my program from the noise of the entire platform.  The numeric argument printed after the tag in the logcat output is the pid responsible for that log line which I had used in the past to do this sort of filtering but it was a pain when the app crashed or was reinstalled because the pid would change.&lt;br /&gt;&lt;br /&gt;Enter my &lt;a href="http://github.com/jasta/android-dev-tools/blob/master/proclogcat"&gt;proclogcat&lt;/a&gt; script.  This script tracks the pid as the process is killed and restarted and takes care of automating the &lt;code&gt;adb shell ps | grep &amp;lt;process&amp;gt;&lt;/code&gt; logic on first launch.  The best part is the script can be combined with Jeffrey Sharkey's excellent &lt;a href="http://jsharkey.org/blog/2009/04/22/modifying-the-android-logcat-stream-for-full-color-debugging/"&gt;coloredlogcat&lt;/a&gt; script (or my &lt;a href="http://github.com/jasta/android-dev-tools/blob/master/coloredlogcat.py"&gt;modified version&lt;/a&gt; of it) for beautiful results.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_hzaKggjtxDQ/S8Tyi7AmNMI/AAAAAAAAB4Y/a50klioU7wo/s1600/proclogcat-small.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 129px;" src="http://4.bp.blogspot.com/_hzaKggjtxDQ/S8Tyi7AmNMI/AAAAAAAAB4Y/a50klioU7wo/s400/proclogcat-small.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5459755330049553602" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight:bold;"&gt;Download:&lt;/span&gt; &lt;a href="http://github.com/jasta/android-dev-tools/blob/master/proclogcat"&gt;proclogcat&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;To use, simply copy it somewhere in your &lt;code&gt;PATH&lt;/code&gt; and invoke either manually as &lt;code&gt;adb logcat | proclogcat &amp;lt;process&amp;gt;&lt;/code&gt; or in a function as is discussed in the script source code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-6284079361024140657?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/6284079361024140657/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=6284079361024140657' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/6284079361024140657'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/6284079361024140657'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2010/04/logcat-improved.html' title='Logcat, Improved.'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_hzaKggjtxDQ/S8Tyi7AmNMI/AAAAAAAAB4Y/a50klioU7wo/s72-c/proclogcat-small.png' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-3550650097749163360</id><published>2009-12-15T07:29:00.000-08:00</published><updated>2009-12-15T07:29:26.519-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Gracefully supporting multiple Android platform versions in a single release</title><content type='html'>The Android platform has been aggressively updating since version 1.0 and now we're starting to a see a much more interesting mix of device types, manufacturers, and even platform versions out in the wild.  Unfortunately sometimes this can be frustrating for developers wanting to look forward to support new features and conveniences, but to still support devices that are on longer update cycles (like with the G1).&lt;br /&gt;&lt;br /&gt;The pattern shown here will deal with multiple platform versions although can easily be applied in other situations.  First of all, let's start with a preface about &lt;a href="http://developer.android.com/guide/topics/manifest/uses-sdk-element.html"&gt;minSdkVersion&lt;/a&gt;, &lt;a href="http://developer.android.com/guide/topics/manifest/uses-sdk-element.html"&gt;targetSdkVersion&lt;/a&gt;, and the Eclipse target platform.  The *SdkVersion attributes are defined in the manifest &lt;a href="http://developer.android.com/guide/topics/manifest/uses-sdk-element.html"&gt;&amp;lt;uses-sdk&amp;gt;&lt;/a&gt; tag and define the minimum platform version your app can be installed onto (and tested on!), and the highest version that you tested to and were aware of during development.  It is important that you test your application on all versions between and including min and target.  The Eclipse target platform is the specific version that Eclipse will be compiling against, this is what permits us to compile code that actually does link specifically against the newer platform features.  This is usually set the same as your targetSdkVersion.&lt;br /&gt;&lt;br /&gt;Now let's consider a practical example of a music player application which needs to implement a service in the foreground state during playback.  Prior to API level 5, this was done with the &lt;a href="http://developer.android.com/reference/android/app/Service.html#setForeground(boolean)"&gt;Service.setForeground&lt;/a&gt; call, but level 5 and beyond deprecated this method due to widespread abuse.  Instead, a new method was introduced (&lt;a href="http://developer.android.com/reference/android/app/Service.html#startForeground(int, android.app.Notification)"&gt;Service.startForeground&lt;/a&gt;) which can be used to achieve this affect as well as setting an ongoing notification in the status bar.  In many ways this is handy as the notification and foreground state were naturally already tied together, now there's an API combining them.  But problems start when you try to test new code using this method on platform versions below 2.0 (API level 5).  Specifically, Dalvik will throw a VerifyError when attempting to initialize the class containing the call to startForeground for the first time, even if the call is in a conditional statement.  This method does not exist on pre-2.0 devices, and so cannot be included in your code in this way.&lt;br /&gt;&lt;br /&gt;A naive approach would be to simply use reflection to test for and execute startForeground, but thankfully Java offers a much more elegant design pattern for just this sort of thing.  The basic idea is to create an abstract API that the rest of your application can access which hides the specific implementation of what's being performed, and does so in such a way that prevents the VM from initializing an unsupported class on an older platform.  So you might try defining something like this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint java-html"&gt;&lt;code&gt;&lt;br /&gt;public abstract class PlayerNotification {&lt;br /&gt;    public static PlayerNotification getInstance() {&lt;br /&gt;        if (Integer.parseInt(Build.VERSION.SDK) &lt;= 4)&lt;br /&gt;            return PreEclair.Holder.sInstance;&lt;br /&gt;        else&lt;br /&gt;            return EclairAndBeyond.Holder.sInstance;&lt;br /&gt;    }&lt;br /&gt;    &lt;br /&gt;    public abstract void showNotification(Service context, int id, Notification notification);&lt;br /&gt;    public abstract void hideNotification(Service context, int id);&lt;br /&gt;&lt;br /&gt;    private static class PreEclair extends PlayerNotification {&lt;br /&gt;        ...&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static class EclairAndBeyond extends PlayerNotification {&lt;br /&gt;        ...&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Now your service could be modified to make use of this new abstract API as such:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint java-html"&gt;&lt;code&gt;&lt;br /&gt;public MyService extends Service {&lt;br /&gt;    private static final int NOTIF_PLAYING = 1;&lt;br /&gt;    private final PlayerNotification mNotification =&lt;br /&gt;        PlayerNotification.getInstance();&lt;br /&gt;&lt;br /&gt;    ...&lt;br /&gt;    &lt;br /&gt;    public void setForegroundAndShowNotification(Notification n) {&lt;br /&gt;        mNotification.showNotification(this, NOTIF_PLAYING, n);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public void stopForegroundAndHideNotification() {&lt;br /&gt;        mNotification.hideNotification(this, NOTIF_PLAYING);&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;Great, this sounds very simple and easy to follow.  Let's return to the full implementation of PlayerNotification:&lt;br /&gt;&lt;br /&gt;&lt;pre class="prettyprint java-html"&gt;&lt;code&gt;&lt;br /&gt;    private static class PreEclair extends PlayerNotification {&lt;br /&gt;        private static class Holder {&lt;br /&gt;            private static final PreEclair sInstance = new PreEclair();&lt;br /&gt;        }&lt;br /&gt;        private NotificationManager getNotificationManager(Context context) {&lt;br /&gt;            return (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);&lt;br /&gt;        }&lt;br /&gt;        public void showNotification(Service context, int id, Notification n) {&lt;br /&gt;            context.setForeground(true);&lt;br /&gt;            getNotificationManager(context).notify(id, n);&lt;br /&gt;        }&lt;br /&gt;        public void hideNotification(Service context, int id) {&lt;br /&gt;            context.setForeground(false);&lt;br /&gt;            getNotificationManager(context).cancel(id);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    private static class EclairAndBeyond extends PlayerNotification {&lt;br /&gt;        private static class Holder {&lt;br /&gt;            private static final EclairAndBeyond sInstance = new EclairAndBeyond();&lt;br /&gt;        }&lt;br /&gt;        public void showNotification(Service context, int id, Notification n) {&lt;br /&gt;            context.startForeground(id, n);&lt;br /&gt;        }&lt;br /&gt;        public void hideNotification(Service context, int id) {&lt;br /&gt;            context.stopForeground(id);&lt;br /&gt;        }&lt;br /&gt;    }&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And that's it as far as code goes!  Assuming that you have already updated your AndroidManifest.xml to include the appropriate &lt;a href="http://developer.android.com/guide/topics/manifest/uses-sdk-element.html"&gt;&amp;lt;uses-sdk&amp;gt;&lt;/a&gt; attributes, you're ready to start testing.  Use the Android SDK tools to create AVDs for each of the major platform releases from your minimum supported version to your current target and deploy your app on each to make sure you have not made any mistakes.&lt;br /&gt;&lt;br /&gt;For further reading about how Java guarantees this approach, read about the &lt;a href="http://en.wikipedia.org/wiki/Initialization_on_demand_holder_idiom"&gt;initialization on demand holder idiom&lt;/a&gt;.  This is what allows us to prevent the wrong implementing class from initializing in the VM (and thus causing verification errors).&lt;br /&gt;&lt;br /&gt;You can find two working examples of this pattern in my &lt;a href="http://five.googlecode.com"&gt;Five&lt;/a&gt; app: &lt;a href="http://github.com/jasta/five-android/blob/master/src/org/devtcg/five/provider/util/AcquireProvider.java"&gt;one using reflection&lt;/a&gt; and &lt;a href="http://github.com/jasta/five-android/blob/master/src/org/devtcg/five/service/PlayerNotification.java"&gt;one matching the explained example&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-3550650097749163360?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/3550650097749163360/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=3550650097749163360' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3550650097749163360'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3550650097749163360'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2009/12/gracefully-supporting-multiple-android.html' title='Gracefully supporting multiple Android platform versions in a single release'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-3732290766889702777</id><published>2009-03-17T20:40:00.000-07:00</published><updated>2009-07-24T12:36:38.186-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Building, running, and debugging Android source</title><content type='html'>There is a lot of confusion surrounding the work flow in the Android source tree, so allow me to simplify:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;Follow the initial instructions for downloading the source at:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://source.android.com/download"&gt;http://source.android.com/download&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Set up your environment to build the engineering build for the generic device and generic product.  This is similar to the SDK, but with a few pieces missing.&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ source build/envsetup.sh&lt;br /&gt;$ lunch 1&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;To build for the first time:&lt;code&gt;&lt;br /&gt;&lt;br /&gt;$ make&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;If you have a multi-core system, you can build with &lt;code&gt;make -jN&lt;/code&gt; where N is twice the number of cores on your machine.  This should speed up the first build considerably.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;To launch the emulator from your build&lt;span style="font-family:monospace;"&gt;:&lt;/span&gt;&lt;code&gt;&lt;br /&gt;&lt;br /&gt;$ ./out/host/&amp;lt;your-machine-type&amp;gt;/bin/emulator&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;On my system &lt;code&gt;&amp;lt;your-machine-type&amp;gt;&lt;/code&gt; is &lt;code&gt;linux-x86&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;NOTE:&lt;/span&gt; The emulator knows where to find system and data images as a result of running &lt;code&gt;lunch 1&lt;/code&gt; above.  This sets the environment variable &lt;code&gt;ANDROID_PRODUCT_OUT&lt;/code&gt; to point to the target directory.  For this example, it should be &lt;code&gt;out/target/product/generic/&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;If you wish to make changes to the source code, there are handy utilities that have been exposed to your environment by &lt;code&gt;source build/envsetup.sh&lt;/code&gt; above.  For example, if you modify the Email app and just want to rebuild it:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ mmm packages/apps/Email&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;To see your changes in the emulator you can run:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ adb remount&lt;br /&gt;$ adb sync&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Which will copy the regenerated &lt;code&gt;Email.apk&lt;/code&gt; file into the emulator's &lt;code&gt;/system/app&lt;/code&gt; folder, triggering the &lt;code&gt;PackageManager&lt;/code&gt; to automatically reinstall it.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Or if you change framework resources in &lt;code&gt;frameworks/base/core/res/res/&lt;/code&gt; you could regenerate &lt;code&gt;framework-res.apk&lt;/code&gt; with:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ mmm frameworks/base/core/res&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Or if you modified even the framework itself you could run:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ mmm frameworks/base&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;To sync these changes you must restart the running framework and sync, as with this handy sequence:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ adb remount&lt;br /&gt;$ adb shell stop&lt;br /&gt;$ adb sync&lt;br /&gt;$ adb shell start&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;&lt;/li&gt;&lt;li&gt;Finally, to debug your changes you can use the DDMS tool to select a process for debug and then attach Eclipse to it.  If you have the Eclipse Android Development plugin installed, there is a special DDMS perspective which you can use to choose the process for debug.  To attach Eclipse to it, see these instructions:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://source.android.com/using-eclipse"&gt;http://source.android.com/using-eclipse&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;This document also describes how to use Eclipse for development.  Any IDE should work with the proper finagling though.  Just note that the IDE won't really be an integrated environment: the final output of APKs, &lt;code&gt;system.img&lt;/code&gt;, and even the generation of &lt;code&gt;R.java&lt;/code&gt; files will have to be done by &lt;code&gt;make&lt;/code&gt;!&lt;br /&gt;&lt;br /&gt;A note about the processes in Android:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;system_process&lt;/code&gt; houses all things under &lt;code&gt;frameworks/base/services&lt;/code&gt;.  This includes the PackageManagerService, StatusBarService, etc.  It has many, many threads (one for each service, and then one main UI thread), so be wary when debugging.&lt;/li&gt;&lt;li&gt;&lt;code&gt;com.android.acore&lt;/code&gt; hosts Launcher (home), Contacts, etc.  You can determine the apps/providers that run here by looking for &lt;code&gt;android:process="android.process.acore"&lt;/code&gt; in the various &lt;code&gt;AndroidManifest.xml&lt;/code&gt; files in packages/.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Also remember that the "framework" (under &lt;code&gt;frameworks/base/core/java&lt;/code&gt;) is not hosted by any one process.  It is a library used by most processes, so to debug code there you can usually use a simple demo app that takes advantage of whatever you changed and debug that app's process.  A useful trick for setting up your debug connection is to call &lt;code&gt;Debug.waitForDebugger()&lt;/code&gt; during some startup part of an application or system service.&lt;br /&gt;&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;&lt;strong&gt;UPDATE 2009-07-24: &lt;/strong&gt;The original &lt;code&gt;ONE_SHOT_MAKEFILE&lt;/code&gt; line I gave for rebuilding the framework has been deprecated.  &lt;code&gt;mmm frameworks/base&lt;/code&gt; is now the recommended way to rebuild the framework code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-3732290766889702777?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/3732290766889702777/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=3732290766889702777' title='18 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3732290766889702777'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3732290766889702777'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2009/03/building-running-and-debugging-android.html' title='Building, running, and debugging Android source'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-1172552868995046456</id><published>2009-01-07T18:00:00.000-08:00</published><updated>2009-03-17T16:03:36.198-07:00</updated><title type='text'>Push services: Implementing persistent mobile TCP connections</title><content type='html'>As a result of my work on IMAP IDLE support in Android's default mail application, I have been experimenting with various strategies for implementing long-lived services and persistent connections that operate efficiently in a variety of circumstances.  Several quirks about Android and mobile devices in general arose that could be of value to anyone implementing similar services.&lt;br /&gt;&lt;br /&gt;For most protocols, you will need to implement some type of client-initiated keep alive at the application layer.  For my purposes with IMAP I simply complied with the RFC and elected to leave IDLE mode then re-enter after 28 minutes of inactivity.  On Android, you must use the &lt;a href="http://code.google.com/android/reference/android/app/AlarmManager.html"&gt;AlarmManager&lt;/a&gt; service to wake the CPU for this task.  You might be tempted to use a &lt;a href="http://code.google.com/android/reference/android/os/Handler.html"&gt;Handler&lt;/a&gt; for timing or even a simple thread with a looped sleep() however it should be noted that unless your application otherwise holds a &lt;a href="http://code.google.com/android/reference/android/os/PowerManager.WakeLock.html"&gt;WakeLock&lt;/a&gt; you cannot rely on any timing mechanism other than the &lt;a href="http://code.google.com/android/reference/android/app/AlarmManager.html"&gt;AlarmManager&lt;/a&gt;.  Once the screen goes blank, the CPU may sleep and once it does other timing mechanisms will block until the CPU wakes up again, regardless of any timeout paramters you supply.&lt;br /&gt;&lt;br /&gt;After running my test for several days I noticed Android was mysteriously killing processes, claiming that the services implemented in them have "died", then restarting them just a few minutes later.  No call to the service's &lt;a href="http://code.google.com/android/reference/android/app/Service.html#onDestroy%28%29"&gt;onDestroy&lt;/a&gt; method will occur, and even on service restart you will only see a call to &lt;a href="http://code.google.com/android/reference/android/app/Service.html#onCreate%28%29"&gt;onCreate&lt;/a&gt; and not &lt;a href="http://code.google.com/android/reference/android/app/Service.html#onStart%28android.content.Intent,%20int%29"&gt;onStart&lt;/a&gt;.  In order to compensate for this you are expected to store your state persistently and check for a discrepency during onCreate and then invoke &lt;a href="http://code.google.com/android/reference/android/content/Context.html#startService%28android.content.Intent%29"&gt;startService&lt;/a&gt; for yourself if necessary.  The &lt;a href="http://code.google.com/android/reference/android/content/SharedPreferences.html"&gt;SharedPreferences&lt;/a&gt; system can be handy for this.&lt;br /&gt;&lt;br /&gt;Source code for a functional demonstration on this topic can be found at my &lt;a href="http://android-random.googlecode.com/"&gt;android-random project&lt;/a&gt; page, under the module &lt;a href="http://code.google.com/p/android-random/source/browse/#svn/trunk/TestKeepAlive"&gt;TestKeepAlive&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-1172552868995046456?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/1172552868995046456/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=1172552868995046456' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/1172552868995046456'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/1172552868995046456'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2009/01/push-services-implementing-persistent.html' title='Push services: Implementing persistent mobile TCP connections'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-9031381140438149472</id><published>2008-10-23T21:12:00.000-07:00</published><updated>2008-10-23T21:24:54.084-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='email'/><category scheme='http://www.blogger.com/atom/ns#' term='imap'/><category scheme='http://www.blogger.com/atom/ns#' term='andriod'/><category scheme='http://www.blogger.com/atom/ns#' term='g1'/><title type='text'>Working on IMAP IDLE support for Android's Email app</title><content type='html'>For all those screaming about the lack of push e-mail updates for regular IMAP accounts with the basic Email app in Android, I have been digging into the code for the past few days and am preparing a patch for IMAP IDLE support.  For those that do not know, IMAP IDLE allows a client to maintain a persistent, light connection to the server that is then notified of new messages as they arrive.  Many IMAP servers support this extension, including Microsoft Exchange which would thus allow push e-mail for those that need corporate e-mail options on the G1.&lt;br /&gt;&lt;br /&gt;I will post an APK for folks to try once I have the support working well.  Stay tuned...&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-9031381140438149472?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/9031381140438149472/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=9031381140438149472' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/9031381140438149472'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/9031381140438149472'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2008/10/working-on-imap-idle-support-for.html' title='Working on IMAP IDLE support for Android&apos;s Email app'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-5108814380345226468</id><published>2008-08-27T12:24:00.000-07:00</published><updated>2008-08-27T12:36:11.297-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='aidl'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Generate Callback Listener Helpers from AIDL</title><content type='html'>As I redesign &lt;a href="http://five.googlecode.com/"&gt;Five&lt;/a&gt; I find myself tweaking/expanding the callback listeners in my interface which are handled through the RemoteCallbackList class in the service implementation.  This class is great, however for each call code must be written similar to:&lt;br /&gt;&lt;pre class="prettyprint java-html"&gt;&lt;code&gt;&lt;br /&gt;int N = mCallbacks.beginBroadcast();&lt;br /&gt;&lt;br /&gt;for (int i = 0; i &lt; N; i++) {&lt;br /&gt;  try {&lt;br /&gt;    mCallbacks.getBroadcastItem(i).onSomeEvent();&lt;br /&gt;  } catch (RemoteException e) {}&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;mCallbacks.finishBroadcast();&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;This can quickly pollute the service implementation, and even if you factor these calls out to a separate class it can be a pain to create and maintain them.  So, I came up with a solution in the form of a Perl script which takes as input an AIDL file defining the callback interface and outputs a class implementing the extended RemoteCallbackList.  To use, simply type:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ ./aidl-cbliststub.pl &amp;lt; IFooListener.aidl &amp;gt; IFooListenerCallbackList.java&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Download: &lt;/span&gt;&lt;a href="http://android-random.googlecode.com/svn/trunk/aidl-cblistsub/aidl-cbliststub.pl"&gt;aidl-cblistsub.pl&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-5108814380345226468?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/5108814380345226468/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=5108814380345226468' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/5108814380345226468'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/5108814380345226468'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2008/08/generate-callback-listener-helpers-from.html' title='Generate Callback Listener Helpers from AIDL'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-397362007185813155</id><published>2008-08-25T06:57:00.000-07:00</published><updated>2008-08-25T06:57:14.946-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='unit testing'/><category scheme='http://www.blogger.com/atom/ns#' term='instrumentation'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><category scheme='http://www.blogger.com/atom/ns#' term='five'/><title type='text'>Android Instrumentation Example</title><content type='html'>As Android approaches maturity with its recent &lt;code&gt;0.9r1&lt;/code&gt; release, I began to think its time that my main project updates to match.  I decided to take another look at Android's instrumentation and unit testing features to build robust tests for my critical services and activities.  Unfortunately, there isn't anything new in the way of documentation however there is now is an example we can use in ApiDemos.&lt;br /&gt;&lt;br /&gt;Looking at the new ApiDemos we see that there is a new &lt;code&gt;tests&lt;/code&gt; directory which contains a second &lt;code&gt;AndroidManifest.xml&lt;/code&gt; with no user activities defined.  This is important as this structure allows us to have two separate APKs, one for production and one for testing, so our main distribution and build doesn't need to be polluted.  Unfortunately, this approach is not compatible with the Eclipse plugin, and so we must define everything in an external build environment.&lt;br /&gt;&lt;br /&gt;For convenience, I packaged the complete ApiDemos project with my Ant build environment here: &lt;a href="http://android-random.googlecode.com/files/ApiDemos-instrumentation-build.tar.gz"&gt;ApiDemos-instrumentation-build.tar.gz&lt;/a&gt;.  To build, start the emulator and run the following commands:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ adb shell rm /data/app/ApiDemos.apk&lt;br /&gt;$ ant install&lt;br /&gt;$ cd tests &amp;amp;&amp;amp; ant install&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;It is essential above that you remove the old ApiDemos.apk as the instrumentation APK must be signed with the same key as the package it tests.&lt;br /&gt;&lt;br /&gt;Once we've got both APKs installed we can begin running our unit tests.  There is no UI in Android for this, however it can be invoked more conveniently through adb as such:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ adb shell am instrument -w com.android.samples.tests/android.test.InstrumentationTestRunner&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;This will run all defined tests and print a dot character for each successful test, F for failure, or E for invocation error.  See the javadoc in &lt;code&gt;tests/src/com/android/samples/AllTests.java&lt;/code&gt; for more sample command lines to run individual test cases or specific tests within them.&lt;br /&gt;&lt;br /&gt;My main project, &lt;a href="http://five.googlecode.com"&gt;Five&lt;/a&gt;, has recently been updated to include unit tests in the five-client component, with more test coverage to follow in the next few weeks.  For a non-trivial test case, see my &lt;a href="http://code.google.com/p/five/source/browse/trunk/five-client/tests/src/org/devtcg/five/service/CacheServiceTest.java"&gt;CacheServiceTest&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;NOTE: &lt;/span&gt;Previously, I was using the &lt;a href="http://masa.googlecode.com"&gt;masa Android plugin&lt;/a&gt; for Maven, however it has not yet been updated to support &lt;code&gt;0.9r1&lt;/code&gt;.  I feel that using Maven for this would have been cleaner, but the Ant approach is sufficient for this simple demonstration.  Once updated, I will return here and finish this example with a more sophisticated build environment to automate testing.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-397362007185813155?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/397362007185813155/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=397362007185813155' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/397362007185813155'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/397362007185813155'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2008/08/android-instrumentation-example.html' title='Android Instrumentation Example'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-3714696714688914973</id><published>2008-08-07T00:27:00.000-07:00</published><updated>2008-08-07T00:42:38.440-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vogue'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Android on the HTC Vogue</title><content type='html'>As many of you know, the Vogue can run Android quite nicely with support for sending/reciving SMS, incoming and outgoing calls, GPRS, touch screen, etc thanks to dzo over at Xda-Developers.  See his posts and materials here: &lt;a href="http://it029000.massey.ac.nz/vogue/"&gt;http://it029000.massey.ac.nz/vogue/&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Several folks from freenode/#android have access to this device, myself included, and have been developing tools and applications to further explore the platform on real hardware.  Those tools are being hosted at the &lt;a href="http://android-random.googlecode.com/"&gt;android-random project page&lt;/a&gt;.  There is a simple file manager (Glance), a much-improved threaded text messaging app (Messages), and perhaps most importantly of all a RemoteLogcat tool that allows us to observe the running devices logcat (normally accessible through &lt;code&gt;adb logcat&lt;/code&gt;) by piping it to a server on the public Internet.&lt;br /&gt;&lt;br /&gt;Recently, I created an emulator skin that can be used to simulate this device's resolution during development.  Simply download &lt;a href="http://android-random.googlecode.com/files/vogue-skin.tar"&gt;vogue-skin.tar&lt;/a&gt; and unpack it into &lt;code&gt;$ANDROID_SDK/tools/lib/images/skins&lt;/code&gt; along with the other default skins.  Then fire up the emulator as:&lt;br /&gt;&lt;code&gt;&lt;br /&gt;$ emulator -skin vogue&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;The skin has no decorations, just a simple 240x320px layout, but this should give you a pretty good idea how different Android can be on this device.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-3714696714688914973?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/3714696714688914973/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=3714696714688914973' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3714696714688914973'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3714696714688914973'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2008/08/android-on-htc-vogue.html' title='Android on the HTC Vogue'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-2128289668570937047</id><published>2008-07-31T18:00:00.000-07:00</published><updated>2008-07-31T21:59:01.635-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='java'/><category scheme='http://www.blogger.com/atom/ns#' term='httpclient'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><category scheme='http://www.blogger.com/atom/ns#' term='concurrency'/><title type='text'>Interruptible I/O example using HttpClient</title><content type='html'>Recently I found myself considering some of the gotchas of threaded, blocking I/O as I've been using it on Android.  Specifically, how do we gracefully handle interruptions demanded by the user or the system to free resources?  After some thought there seems to be three basic strategies with Java:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;1. Use non-blocking I/O, which is generally clumsy and unintuitive for most Java engineers.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;2. Cancel blocking I/O threads by simply setting a stop flag and discarding the reference to the thread.  The thread will clean itself up after an arbitrary length of time up to its transmit or connect timeout.&lt;/li&gt;&lt;li&gt;3. Close the socket owning the input stream on which the blocking thread is waiting.&lt;/li&gt;&lt;/ul&gt;It seems that #2 is the most popular choice on Android however I would like to make a case for #3 as a cleaner method of tidying resources on user request.  With this approach, we can be certain to quickly close any open files, relinquish database, object, or file locks, and allow the thread to clean up its resources quickly.  As it turns out, using HttpClient makes this approach relatively painless, but there are a few gotchas in this pattern that we must watch out for.&lt;br /&gt;&lt;br /&gt;So, to get started we need to create our &lt;code&gt;StoppableDownloadThread&lt;/code&gt; class which allows us to encapsulate our interrupt logic.&lt;br /&gt;&lt;pre class="prettyprint java-html"&gt;public class StoppableDownloadThread extends Thread&lt;br /&gt;{&lt;br /&gt;  private String mURL;&lt;br /&gt; &lt;br /&gt;  private HttpGet mMethod = null;&lt;br /&gt; &lt;br /&gt;  /* Volatile stop flag used to coordinate state between the two&lt;br /&gt;   * threads involved in this example. */&lt;br /&gt;  protected volatile boolean mStopped = false;&lt;br /&gt; &lt;br /&gt;  /* Synchronizes access to mMethod to prevent an unlikely race&lt;br /&gt;   * condition when stopDownload() is called before mMethod has&lt;br /&gt;    been committed. */&lt;br /&gt;  private Object lock = new Object();&lt;br /&gt; &lt;br /&gt;  public StoppableDownloadThread(String url)&lt;br /&gt;  {&lt;br /&gt;     mURL = url;&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This simply outlines our basic strategy for stopping and synchronization.  A simple volatile boolean flag and a monitor lock to share the HttpGet handle should do just fine.  Now let's continue with the implementation of the run() method:&lt;br /&gt;&lt;pre class="prettyprint java-html"&gt;public void run()&lt;br /&gt;{&lt;br /&gt;  HttpClient cli = new DefaultHttpClient();&lt;br /&gt;  HttpGet method;&lt;br /&gt; &lt;br /&gt;  try {&lt;br /&gt;     method = new HttpGet(mURL);&lt;br /&gt;  } catch (URISyntaxException e) {&lt;br /&gt;     e.printStackTrace();&lt;br /&gt;     return;&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  /* It's important that we pause here to check if we've been stopped&lt;br /&gt;   * already.  Otherwise, we would happily progress, seemingly ignoring&lt;br /&gt;   * the stop request. */&lt;br /&gt;  if (mStopped == true)&lt;br /&gt;     return;&lt;br /&gt; &lt;br /&gt;  synchronized(lock) {&lt;br /&gt;     mMethod = method;&lt;br /&gt;  }&lt;br /&gt; &lt;br /&gt;  HttpResponse resp = null;&lt;br /&gt;  HttpEntity ent = null;&lt;br /&gt;  InputStream in = null;&lt;br /&gt; &lt;br /&gt;  try {&lt;br /&gt;     resp = cli.execute(mMethod);&lt;br /&gt; &lt;br /&gt;     if (mStopped == true)&lt;br /&gt;        return;&lt;br /&gt; &lt;br /&gt;     StatusLine status = resp.getStatusLine();&lt;br /&gt; &lt;br /&gt;     if ((ent = resp.getEntity()) != null)&lt;br /&gt;     {&lt;br /&gt;        long len;&lt;br /&gt;        if ((len = ent.getContentLength()) &gt;= 0)&lt;br /&gt;           mHandler.sendSetLength(len);&lt;br /&gt; &lt;br /&gt;        in = ent.getContent();&lt;br /&gt; &lt;br /&gt;        byte[] b = new byte[2048];&lt;br /&gt;        int n;&lt;br /&gt;        long bytes = 0;&lt;br /&gt; &lt;br /&gt;        /* Note that for most applications, sending a handler message&lt;br /&gt;         * after each read() would be unnecessary.  Instead, a timed&lt;br /&gt;         * approach should be utilized to send a message at most every&lt;br /&gt;         * x seconds. */&lt;br /&gt;        while ((n = in.read(b)) &gt;= 0)&lt;br /&gt;        {&lt;br /&gt;           bytes += n;&lt;br /&gt;           System.out.println("Read " + bytes + " bytes...");&lt;br /&gt;        }&lt;br /&gt;     }&lt;br /&gt;  } catch (Exception e) {&lt;br /&gt;     /* We expect a SocketException on cancellation.  Any other type of&lt;br /&gt;      * exception that occurs during cancellation is ignored regardless&lt;br /&gt;      * as there would be no need to handle it. */&lt;br /&gt;     if (mStopped == false)&lt;br /&gt;        e.printStackTrace();&lt;br /&gt;  } finally {&lt;br /&gt;     if (in != null)&lt;br /&gt;        try { in.close(); } catch (IOException e) {}&lt;br /&gt; &lt;br /&gt;     synchronized(lock) {&lt;br /&gt;        mMethod = null;&lt;br /&gt;     }&lt;br /&gt; &lt;br /&gt;     /* Close the socket (if it's still open) and cleanup. */&lt;br /&gt;     cli.getConnectionManager().shutdown();&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;This is a pretty standard example of an HTTP GET using HttpClient4, however do note that we have strategically placed checks against our stop flag to avoid leaving the download thread in an inconsistent state when it's being cancelled.  We're not done yet though as we still need to implement the stop part of the interface so that our main thread (or any other thread) can abort the download thread:&lt;br /&gt;&lt;pre class="prettyprint java-html"&gt;&lt;code&gt;public void stopDownload()&lt;br /&gt;{&lt;br /&gt;&lt;/code&gt;   &lt;code&gt;if (mStopped == true)&lt;br /&gt;&lt;/code&gt;   &lt;code&gt;   return;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;   /* Flag to instruct the downloading thread to halt at the next&lt;br /&gt;&lt;/code&gt;   &lt;code&gt; * opportunity. */&lt;br /&gt;&lt;/code&gt;   &lt;code&gt;mStopped = true;&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;  &lt;code&gt;/* Interrupt the blocking thread.  This won't break out of a blocking&lt;br /&gt;&lt;/code&gt;   &lt;code&gt; * I/O request, but will break out of a wait or sleep call.  While in&lt;br /&gt;&lt;/code&gt;   &lt;code&gt; * this case we know that no such condition is possible, it is always a&lt;br /&gt;&lt;/code&gt;   &lt;code&gt; * good idea to include an interrupt to avoid assumptions about the&lt;br /&gt;&lt;/code&gt;   &lt;code&gt; * thread in question. */&lt;br /&gt;&lt;/code&gt;   &lt;code&gt;interrupt();&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;  &lt;code&gt;/* A synchronized lock is necessary to avoid catching mMethod in&lt;br /&gt;&lt;/code&gt;   &lt;code&gt; * an uncommitted state from the download thread. */&lt;br /&gt;&lt;/code&gt;   &lt;code&gt;synchronized(lock) {&lt;br /&gt;&lt;/code&gt;   &lt;code&gt;   /* This closes the socket handling our blocking I/O, which will&lt;br /&gt;&lt;/code&gt;   &lt;code&gt;    * interrupt the request immediately.  This is not the same as&lt;br /&gt;&lt;/code&gt;   &lt;code&gt;    * closing the InputStream yieled by HttpEntity#getContent, as the&lt;br /&gt;&lt;/code&gt;   &lt;code&gt;    * stream is synchronized in such a way that would starve our main&lt;br /&gt;&lt;/code&gt;   &lt;code&gt;    * thread. */&lt;br /&gt;&lt;/code&gt;   &lt;code&gt;   if (mMethod != null)&lt;br /&gt;&lt;/code&gt;   &lt;code&gt;      mMethod.abort();&lt;br /&gt;&lt;/code&gt;   &lt;code&gt;}&lt;br /&gt;&lt;/code&gt;&lt;code&gt;}&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;This completes our basic interface, but we still don't have a usable example here.  There's no communication between our download thread back to the user in any meaningful way as would be required for an Android application.  For that I have modified the above code slightly and introduced an Android layer in the form of a working demo.  Source code for the full example: &lt;a href="http://android-random.googlecode.com/files/CancelHttpGet.tar.gz"&gt;CancelHttpGet.tar.gz&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-2128289668570937047?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/2128289668570937047/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=2128289668570937047' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/2128289668570937047'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/2128289668570937047'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2008/07/interruptible-io-example-using.html' title='Interruptible I/O example using HttpClient'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-2009536028411390343</id><published>2008-05-30T10:22:00.000-07:00</published><updated>2008-05-30T12:56:24.405-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='oha'/><category scheme='http://www.blogger.com/atom/ns#' term='io'/><category scheme='http://www.blogger.com/atom/ns#' term='google'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Details on the next public SDK</title><content type='html'>I had hoped to reserve judgment until after an official announcement from Google, however after speaking with Dan Morrill and Jason Chen at Google I/O, it seemed clear that the OHA, up the corporate chain, has not taken the development community seriously.  I have confirmed that the ADC winners have now received an updated version of the SDK which they are bound by NDA to keep private.  These projects are thus forced to be closed until the NDA restrictions are lifted, which include no source release, performance benchmarking, discussion of new features, screenshots, etc.  These restrictions are expected to last until the next public SDK is dropped.&lt;br /&gt;&lt;br /&gt;So, when is the next public release?  Surely after over 3 months since M5 and only a few major releases so far it should be close, perhaps landing after round 2 of the ADC is over?  Not so.   The SDK is not expected until either shortly before handset launch later this year, or perhaps on or after that date.  We can rest assured that there will be significant changes in this release: modified and new APIs, new core SDK features (like Wi-Fi, bluetooth, etc), modified UI, and of course many important bug fixes.  As a result, our applications will require substantial revision to work [well] on this new version, reducing the likelihood that losing ADC entries will be able to "compete" for visibility on the handsets as they launch.  Not to mention, generally stressing the larger development community with excessive unnecessary work and "wandering" development with no clear indication of what's coming and when.&lt;br /&gt;&lt;br /&gt;I see this as a serious problem, running directly counter to the claims of openness and developer support, however Google and the OHA apparently do not feel that a commitment to openness is binding in the face of proprietary inconvenience.&lt;br /&gt;&lt;br /&gt;So, I feel there is no choice but to suspend my development on the current platform and await the launch of handsets.  Hopefully I will be able to catch up quickly and still offer a stable and feature-rich application within the first few months of handset availability.  That said, I will now be starting on the desktop client for my &lt;a href="http://five.googlecode.com/"&gt;media streaming system&lt;/a&gt;.  If anyone is interested, my project is currently open source and I am actively interested in contributors, even if you want to work on the Android component using M5 *grin*.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-2009536028411390343?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/2009536028411390343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=2009536028411390343' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/2009536028411390343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/2009536028411390343'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2008/05/detail-of-next-public-sdk.html' title='Details on the next public SDK'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-1852037059819969320</id><published>2008-04-15T08:31:00.000-07:00</published><updated>2008-04-15T13:08:47.605-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><category scheme='http://www.blogger.com/atom/ns#' term='five'/><title type='text'>My ADC Submission: Five, a media distribution technique</title><content type='html'>&lt;div id="inbdy"&gt;I have created a system by which your music can be accessed anytime on the go using your cell phone's wireless data connection.  Simply install the server software onto your home PC and configure the phone to connect to it.  Initially, the meta database will be downloaded and then from there only changes will be synced to the phone.  The media itself is retrieved on demand and cached to the storage card.  In my real-world tests with a remote server and simulating GPRS or EDGE data throughput has been very promising, requiring only 3 - 8 seconds of buffer time before most content can be played.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_hzaKggjtxDQ/SATPJsWxPtI/AAAAAAAAAIE/LsZPIhg3uHc/s1600-h/buffering.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp1.blogger.com/_hzaKggjtxDQ/SATPJsWxPtI/AAAAAAAAAIE/LsZPIhg3uHc/s320/buffering.png" alt="" id="BLOGGER_PHOTO_ID_5189500436070088402" border="0" /&gt;&lt;/a&gt;&lt;p&gt;For more screenshots and info, see &lt;a target="_blank" rel="nofollow" href="http://android-five.googlecode.com/"&gt;http://android-five.googlecode.com&lt;/a&gt;.  The system, though currently closed, will be opened under the terms of the GPL after the first round challenge winners are announced, regardless of outcome.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I will also be posting a video this week, showing my system in action.  Stay tuned.   &lt;/p&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-1852037059819969320?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/1852037059819969320/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=1852037059819969320' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/1852037059819969320'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/1852037059819969320'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2008/04/my-adc-submission-five-media.html' title='My ADC Submission: Five, a media distribution technique'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp1.blogger.com/_hzaKggjtxDQ/SATPJsWxPtI/AAAAAAAAAIE/LsZPIhg3uHc/s72-c/buffering.png' height='72' width='72'/><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-3714830712200204659</id><published>2008-04-10T10:00:00.000-07:00</published><updated>2008-04-10T10:06:59.607-07:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='io'/><category scheme='http://www.blogger.com/atom/ns#' term='google'/><title type='text'>Obligatory Google I/O Posting</title><content type='html'>Seems like &lt;a href="http://code.google.com/events/io"&gt;Google I/O&lt;/a&gt; is all the rage these days, so I decided I'd officially mention that I will be attending.  I live in Seattle so airfare was cheap, plus I have &lt;a href="http://www.loopt.com"&gt;friends&lt;/a&gt; in the area who want to go too.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-3714830712200204659?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/3714830712200204659/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=3714830712200204659' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3714830712200204659'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3714830712200204659'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2008/04/obligatory-google-io-posting.html' title='Obligatory Google I/O Posting'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-4891399342078601803</id><published>2008-03-23T21:29:00.000-07:00</published><updated>2008-03-24T16:29:11.410-07:00</updated><title type='text'>Advanced Tab Activity Demo</title><content type='html'>I was inspired by the simple TabHost/TabWidget demonstration by &lt;a href="http://www.jsharkey.org/blog/2008/02/14/android-tabhost-in-the-m5-sdk/"&gt;Jeffrey Sharkey&lt;/a&gt;, and decided to expand upon it significantly.  In my demo, I have replaced all the default drawables and layouts, created my own custom &lt;a href="http://code.google.com/android/reference/android/graphics/ColorStateList.html"&gt;ColorStateList&lt;/a&gt;, and even utilized TabActivity for greater isolation.&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_hzaKggjtxDQ/R-cvu_hWm7I/AAAAAAAAAGo/x_LZOsanPPw/s1600-h/TabActivityDemo.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_hzaKggjtxDQ/R-cvu_hWm7I/AAAAAAAAAGo/x_LZOsanPPw/s320/TabActivityDemo.png" alt="" id="BLOGGER_PHOTO_ID_5181162380684860338" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Download:&lt;/span&gt; &lt;a href="http://android-random.googlecode.com/files/TabActivityDemo.tar.gz"&gt;TabActivityDemo.tar.gz&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The code and images for this demo are in the public domain, so please feel free to use and modify as you wish.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;NOTE:&lt;/span&gt; TabActivity is currently marked as deprecated, but according to &lt;a href="http://groups.google.com/group/android-developers/browse_thread/thread/61976a6a2d86673d"&gt;this post&lt;/a&gt;, I believe that may be in error.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-4891399342078601803?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/4891399342078601803/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=4891399342078601803' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/4891399342078601803'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/4891399342078601803'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2008/03/advanced-tab-activity-demo.html' title='Advanced Tab Activity Demo'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_hzaKggjtxDQ/R-cvu_hWm7I/AAAAAAAAAGo/x_LZOsanPPw/s72-c/TabActivityDemo.png' height='72' width='72'/><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-3836536829423612486</id><published>2008-03-05T15:54:00.000-08:00</published><updated>2008-03-05T16:10:24.349-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='xml'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Tool to read Android binary XML files</title><content type='html'>I have successfully reverse engineered a good portion of the Android binary XML file format that is found inside of Android package files (.apk). With this tool, you can explore the XML layout, drawable, and animation files used in the applications distributed with the SDK (phone, browser, contacts, etc). My primary motivation for doing this was to simply observe some of the common practices and get a sense for what Google is doing internally that isn't necessarily available through their API demos and samples. Below you can find two links to download either the stand-alone convertor or the collected output as run over every APK file found in the phone's /system directory:&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Download:&lt;/strong&gt; &lt;a href="http://android-random.googlecode.com/files/axml2xml.pl"&gt;axml2xml.pl&lt;/a&gt;&lt;br /&gt;&lt;strong&gt;Download:&lt;/strong&gt; &lt;a href="http://android-random.googlecode.com/files/android-xmldump.tar.gz"&gt;android-xmldump.tar.gz&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Please note that this tool was a very quick hack and some of the XML files I found failed to parse. Not many, and the only ones I found were raw XML documents (not Android resources) so I didn't bother to explore any further incompatibilities. If you find any resources that fail to parse or have any insight into the format, feel free to leave a comment and I will investigate when I have time.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-3836536829423612486?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/3836536829423612486/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=3836536829423612486' title='24 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3836536829423612486'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3836536829423612486'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2008/03/tool-to-read-android-binary-xml-files.html' title='Tool to read Android binary XML files'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>24</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-4522102124941789161</id><published>2008-03-02T20:20:00.000-08:00</published><updated>2008-03-03T00:04:37.197-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Custom Android list widget to access large sorted lists on touch devices</title><content type='html'>I have developed a custom Android widget for &lt;code&gt;m5-rc14&lt;/code&gt; that automatically (and efficiently) sections a sorted list by alphabet letters and offers a side-bar widget for quickly jumping to each section.  This widget could be very useful for any project offering an extremely large list to the user, such as a music player showing artists or albums.&lt;br /&gt;&lt;br /&gt;Some things left out with this widget are a smooth scroll to the selected position as well as a finer control for sections that have large item counts themselves.  More to come later :)&lt;br /&gt;&lt;br /&gt;Here's a screenshot using dummy data:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_hzaKggjtxDQ/R8t-cW3GXVI/AAAAAAAAAGE/_tvEA8mr0Ks/s1600-h/alphabet-list-test.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp0.blogger.com/_hzaKggjtxDQ/R8t-cW3GXVI/AAAAAAAAAGE/_tvEA8mr0Ks/s320/alphabet-list-test.png" alt="" id="BLOGGER_PHOTO_ID_5173367622603267410" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Download:&lt;/span&gt; &lt;a href="http://android-random.googlecode.com/files/AlphabetListView.tar.gz"&gt;AlphabetListView.tar.gz&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Licensed under the GPLv2.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-4522102124941789161?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/4522102124941789161/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=4522102124941789161' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/4522102124941789161'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/4522102124941789161'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2008/03/custom-android-list-view-widget-to.html' title='Custom Android list widget to access large sorted lists on touch devices'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_hzaKggjtxDQ/R8t-cW3GXVI/AAAAAAAAAGE/_tvEA8mr0Ks/s72-c/alphabet-list-test.png' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-4226823734854109791</id><published>2008-02-10T21:41:00.000-08:00</published><updated>2008-02-21T02:09:26.474-08:00</updated><title type='text'>Android Eclipse Plugin / AIDL bugs</title><content type='html'>&lt;span style="font-weight: bold;"&gt;UPDATE: &lt;/span&gt;This work-around is no longer necessary since &lt;code&gt;m5-rc14&lt;/code&gt; fixed the aidl bugs.&lt;br /&gt;&lt;br /&gt;The current Android SDK (&lt;code&gt;m3-rc37a&lt;/code&gt;) has numerous bugs surrounding the aidl parser, the most annoying of which makes it very difficult to work with a project utilizing aidl imports and the Eclipse Android plugin.  In order to ease some frustrations, I have created a wrapper around the aidl tool which tries to guess certain usage parameters and automatically inject the necessary &lt;code&gt;-I&lt;/code&gt; switch.&lt;br /&gt;&lt;br /&gt;To use the script, enter your Android SDK tools directory and issue the following:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;mv aidl aidl.google&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;br /&gt;Then save the following script as &lt;code&gt;aidl&lt;/code&gt;:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;#!/usr/bin/perl&lt;br /&gt;&lt;br /&gt;my @aidl = split /[\/\\]/, [ grep { /\.aidl$/ } @ARGV ]-&gt;[-1];&lt;br /&gt;&lt;br /&gt;foreach (reverse @aidl)&lt;br /&gt;{&lt;br /&gt;last if $_ eq 'src';&lt;br /&gt;undef $_;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;my $I = join('/', map { $_ if $_ } @aidl);&lt;br /&gt;&lt;br /&gt;my @args;&lt;br /&gt;&lt;br /&gt;push @args, "-I$I" if $I;&lt;br /&gt;push @args, @ARGV;&lt;br /&gt;&lt;br /&gt;system("$0.google", @args);&lt;br /&gt;&lt;br /&gt;&lt;/code&gt;And finally, set the script executable:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;&lt;/code&gt;&lt;code&gt;chmod +x aidl&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-4226823734854109791?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/4226823734854109791/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=4226823734854109791' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/4226823734854109791'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/4226823734854109791'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2008/02/android-eclipse-plugin-aidl-bugs.html' title='Android Eclipse Plugin / AIDL bugs'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-3732678604824574377</id><published>2008-01-09T00:50:00.000-08:00</published><updated>2008-02-29T23:17:41.925-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Asynchronous Service Example</title><content type='html'>Many folks have been asking about asynchronous services (using the Binder) in Android and I decided to whip up a quick example showing how this is intended to work with the current SDK (m3-rc37a).  There are rumors from Google that they will be improving things soon and providing a better example, but in the mean time this example should clear up a lot of the confusion:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://android-random.googlecode.com/files/AsyncService.tar.gz"&gt;AsyncService.tar.gz&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;UPDATE:&lt;/span&gt; The project must be built using ant (not Eclipse) because of an SDK bug regarding the invocation of the aidl tool.  There are also reports that even ant won't work on Windows due to yet more bugs in aidl.  The code does work as Google intended, though, and in the next SDK release they are committed to having these issues resolved.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;UPDATE2:&lt;/span&gt; Google released m5-rc14 and, as promised, the bugs are fixed and their included RemoteService example has been updated to show similar functionality.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-3732678604824574377?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/3732678604824574377/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=3732678604824574377' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3732678604824574377'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3732678604824574377'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2008/01/asynchronous-service-example.html' title='Asynchronous Service Example'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-3896493711583168691</id><published>2007-12-28T20:37:00.000-08:00</published><updated>2007-12-28T21:43:32.165-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vnc'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Android VNC, Part Deux</title><content type='html'>I decided to create &lt;a href="http://android-vnc.googlecode.com"&gt;my own VNC implementation&lt;/a&gt; and have posted code and binaries over at Google Code.   There, you'll find instructions for installing and using the VNC server with a Windows Mobile device using &lt;a href="http://dotnetvnc.sourceforge.net/"&gt;.NET VNC Viewer&lt;/a&gt;.  Here's a low-quality photo I snapped to get you interested:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_hzaKggjtxDQ/R3XdX5GR0jI/AAAAAAAAAFY/47VvYo2XtTw/s1600-h/CIMG0359.JPG.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp3.blogger.com/_hzaKggjtxDQ/R3XdX5GR0jI/AAAAAAAAAFY/47VvYo2XtTw/s200/CIMG0359.JPG.jpg" alt="" id="BLOGGER_PHOTO_ID_5149265151501914674" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;The application running is my &lt;a href="http://android-rss.googlecode.com/"&gt;Android RSS reader&lt;/a&gt;, also hosted by Google Code.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-3896493711583168691?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/3896493711583168691/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=3896493711583168691' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3896493711583168691'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3896493711583168691'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2007/12/android-vnc-part-deux.html' title='Android VNC, Part Deux'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp3.blogger.com/_hzaKggjtxDQ/R3XdX5GR0jI/AAAAAAAAAFY/47VvYo2XtTw/s72-c/CIMG0359.JPG.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-3847788208463588233</id><published>2007-12-23T15:19:00.000-08:00</published><updated>2008-01-08T10:53:16.657-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='vnc'/><category scheme='http://www.blogger.com/atom/ns#' term='android'/><title type='text'>Android RFB / VNC implementation</title><content type='html'>Looks like the Android team has created a functional VNC server implementation natively in their surfaceflinger library (/system/lib/libsurfaceflinger.so).  After some further exploration, it is possible to actually connect to and use this VNC server, although there are very strict requirements of the client.&lt;br /&gt;&lt;br /&gt;First off, you will need to proxy the connection as it only permits connections on the local interface.  For this, I have simply &lt;a href="http://benno.id.au/blog/2007/11/13/android-native-apps"&gt;cross-compiled&lt;/a&gt; a &lt;a href="http://www.life-gone-hazy.com/src/simple-tcp-proxy/"&gt;simple TCP proxy&lt;/a&gt; and invoked it on the emulator:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;arm-none-linux-gnueabi-gcc -static -o proxy simple-tcp-proxy.c&lt;br /&gt;adb push proxy /data/proxy&lt;br /&gt;adb shell /data/proxy 0.0.0.0 5901 127.0.0.1 5900&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Then you must redirect port 5901 on the local machine using the Android telnet interface:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;$ telnet localhost 5554&lt;br /&gt;Trying 127.0.0.1...&lt;br /&gt;Connected to localhost.localdomain.&lt;br /&gt;Escape character is '^]'.&lt;br /&gt;Android Console: type 'help' for a list of commands&lt;br /&gt;OK&lt;br /&gt;redir add tcp:5900:5901&lt;br /&gt;OK&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;Now you can connect from your local workstation:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;xvncviewer -noauto localhost&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Note: &lt;/span&gt;the VNC connection will fail if the client suggests any unsupported pixel format (bit depth, endianness(?), etc).  So make sure you use -noauto to disable the initial 8bpp performance test and also use a 16bpp native display on your workstation.  If your client requests 24 or 32bpp, the server will reject and hang indefinitely.  See &lt;code&gt;adb logcat&lt;/code&gt; to determine if you have triggered this behaviour.&lt;br /&gt;&lt;br /&gt;A few comments on this implementation:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;You may only specify 16bpp pixel format, with the true colour flag on and a 565 bit pattern.  This creates problems trying to use it from mobile devices with tools like &lt;a href="http://dotnetvnc.sourceforge.net/"&gt;.NET VNC Viewer&lt;/a&gt; which default specifies a 655 bit pattern when you force a 16bpp encoding.  I wrote a very simple proxy that understands the RFB protocol and "fixes" some of this brokenness, but the experience is still less than desirable.&lt;/li&gt;&lt;/ul&gt;&lt;ul&gt;&lt;li&gt;Only the raw encoding is supported, with no incremental updates.  This causes atrocious performance problems on the client, making it impractical to use an existing mobile device to interact with the Android RFB server.  I tried, it's bad.  I think the only real option to proceed would be to extend my proxy to have a deeper understanding of the full RFB protocol, interpretting and re-encoding the data sent from the native Android RFB server.  This seems like excessive work, and ultimately is work that should go into the native server.  Perhaps I will still do it, though, just to prove it's possible.&lt;/li&gt;&lt;/ul&gt;For reference and further reading, see my &lt;a href="http://groups.google.com/group/android-developers/browse_thread/thread/b4fc2a71fa377baf/792d6afcee458b5a?lnk=gst&amp;amp;q=rfb#792d6afcee458b5a"&gt;android-developers post&lt;/a&gt; on the subject.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;UPDATE: &lt;/span&gt;I have created &lt;a href="http://devtcg.blogspot.com/2007/12/android-vnc-part-deux.html"&gt;my own VNC server&lt;/a&gt; implementation on Android to work around these problems.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-3847788208463588233?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/3847788208463588233/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=3847788208463588233' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3847788208463588233'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3847788208463588233'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2007/12/android-rfb-vnc-implementation.html' title='Android RFB / VNC implementation'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-7926704732529509373</id><published>2007-12-01T19:53:00.000-08:00</published><updated>2007-12-01T20:03:14.523-08:00</updated><title type='text'>Open to the public</title><content type='html'>&lt;span style="font-family:arial;"&gt;I've created a Google Code project at &lt;a href="http://android-rss.googlecode.com/"&gt;http://android-rss.googlecode.com&lt;/a&gt; to host the new Subversion repository for my RSS reader.  I will be "releasing" version 0.1 in the near future with a better build environment (ant supported with meaningful dist targets) and a few default feeds preconfigured for easier testing.  In the mean time, head on over to the &lt;a href="http://android-rss.googlecode.com/"&gt;android-rss&lt;/a&gt; project to access the code through SVN.  Again, for now you must use Eclipse w/ the Android plugin installed or you will not be able to build the source.&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-7926704732529509373?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/7926704732529509373/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=7926704732529509373' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/7926704732529509373'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/7926704732529509373'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2007/12/open-to-public.html' title='Open to the public'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-9106822915308030165.post-3206363823453129387</id><published>2007-11-20T15:48:00.000-08:00</published><updated>2007-12-01T19:52:10.710-08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='android'/><category scheme='http://www.blogger.com/atom/ns#' term='rss'/><title type='text'>Android RSS Reader</title><content type='html'>&lt;span style="font-family:arial;"&gt;I started an Android RSS reader project to help learn the new Google Android APIs in preparation for the Android Developer Challenge.  The irony as I tested overwhelmed me:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp2.blogger.com/_hzaKggjtxDQ/R1Ir2L0-pxI/AAAAAAAAAEU/aCk67jnKdzg/s1600-R/rss2.png"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://bp2.blogger.com/_hzaKggjtxDQ/R1Ir2L0-pxI/AAAAAAAAAEU/hUVee6zhq9o/s320/rss2.png" alt="" id="BLOGGER_PHOTO_ID_5139218334671087378" border="0" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_hzaKggjtxDQ/R0NyrN1Ux4I/AAAAAAAAAEE/_1diIR-AGJ0/s1600-h/android-rss.jpg"&gt;&lt;br /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/9106822915308030165-3206363823453129387?l=devtcg.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://devtcg.blogspot.com/feeds/3206363823453129387/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=9106822915308030165&amp;postID=3206363823453129387' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3206363823453129387'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/9106822915308030165/posts/default/3206363823453129387'/><link rel='alternate' type='text/html' href='http://devtcg.blogspot.com/2007/11/android-rss-reader.html' title='Android RSS Reader'/><author><name>Josh Guilfoyle</name><uri>http://www.blogger.com/profile/02055635184861046754</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp2.blogger.com/_hzaKggjtxDQ/R1Ir2L0-pxI/AAAAAAAAAEU/hUVee6zhq9o/s72-c/rss2.png' height='72' width='72'/><thr:total>1</thr:total></entry></feed>
