<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;C0ANRHYzcSp7ImA9WxJUFU8.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179</id><updated>2009-07-13T14:49:55.889-07:00</updated><title type="text">Android Developers Blog</title><subtitle type="html">An Open Handset Alliance Project.</subtitle><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://android-developers.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://android-developers.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>David McLaughlin, Developer Advocate</name><uri>http://www.blogger.com/profile/15001019201575108829</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>84</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><link rel="self" href="http://feeds.feedburner.com/blogspot/hsDu" type="application/atom+xml" /><entry gd:etag="W/&quot;C0ANRHc7fCp7ImA9WxJUFU8.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-1204734511466994858</id><published>2009-07-13T14:45:00.000-07:00</published><updated>2009-07-13T14:49:55.904-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-13T14:49:55.904-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android Developer Challenge" /><category scheme="http://www.blogger.com/atom/ns#" term="Announcements" /><title>ADC 2 Updates</title><content type="html">&lt;img src="http://2.bp.blogspot.com/_-e06f1q-QQE/SLcdjvXWN2I/AAAAAAAAAGc/kkSvcvrRWok/s320/android_adc.gif" align="right"&gt;&lt;p&gt;Since the &lt;a href="http://android-developers.blogspot.com/2009/05/calling-all-developers-for-android.html"&gt;announcement of Android Developer Challenge 2&lt;/a&gt; in May, Android phones continue to be deployed in countries worldwide. Android phones are currently available in over 20 countries, with more on the way. As I've mentioned earlier, we'll be including real-world users of these phones to help review and score your submissions.  It is important to remember that your apps will be reviewed by judges around the world on actual devices; thus,   be sure to make it extremely easy for users/judges to access your apps with minimum setup. &lt;/p&gt; &lt;p&gt; Some of you have been asking for clarifications on what we mean by "open only to applications that have not been published".  To be specific, applications that are available on Android Market before August 1, 2009 will not be eligible to participate in the contest. Users have already been providing comments for apps that are currently available on Android Market, so it wouldn't make sense for them to "judge" the same apps again in this contest.  In addition, apps that include or that are based on open source projects are fully welcomed, as long as the application itself is not on Android Market until August 1, 2009. &lt;/p&gt; &lt;p&gt; If you want to find out more details about ADC 2, you can find everything at the &lt;a href="http://code.google.com/android/adc/"&gt;ADC 2 page&lt;/a&gt; along with the &lt;a href="http://code.google.com/android/adc/adc2_terms.html"&gt;Terms and Conditions&lt;/a&gt;.  For the moment, the most important thing to know is that ADC 2 submissions will be due August 31.  I can't wait to see what you all come up with this time. &lt;/p&gt; &lt;p&gt; Happy coding -- and good luck! &lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-1204734511466994858?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=eYGbMUMXXY8:B8gcG7Stt5E:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=eYGbMUMXXY8:B8gcG7Stt5E:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=eYGbMUMXXY8:B8gcG7Stt5E:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/eYGbMUMXXY8" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/1204734511466994858?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/1204734511466994858?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/eYGbMUMXXY8/adc-2-updates.html" title="ADC 2 Updates" /><author><name>Eric Chu, Android Mobile Platform</name><uri>http://www.blogger.com/profile/11243666057159213807</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00850393112957401966" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_-e06f1q-QQE/SLcdjvXWN2I/AAAAAAAAAGc/kkSvcvrRWok/s72-c/android_adc.gif" height="72" width="72" /><feedburner:origLink>http://android-developers.blogspot.com/2009/07/adc-2-updates.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UCRXw6cSp7ImA9WxJWGUg.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-5375150057279538273</id><published>2009-06-25T10:30:00.000-07:00</published><updated>2009-06-25T10:34:24.219-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-25T10:34:24.219-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><category scheme="http://www.blogger.com/atom/ns#" term="NDK" /><category scheme="http://www.blogger.com/atom/ns#" term="Announcements" /><title>Introducing Android 1.5 NDK, Release 1</title><content type="html">&lt;p&gt;Many of you have been asking for the ability to call into native code from your Android applications. I'm glad to announce that developers can now download the &lt;a href="http://developer.android.com/sdk/ndk/1.5_r1/index.html"&gt;Android Native Development Kit&lt;/a&gt; from the Android developer site.&lt;/p&gt;&lt;p&gt;As you know, Android applications run in the Dalvik virtual machine.  The NDK allows developers to implement parts of these applications using native-code languages such as C and C++. This can provide benefits to certain kinds of applications.&lt;/p&gt;&lt;p&gt;The NDK provides:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;a set of tools and build files used to generate native code libraries from C and C++ sources&lt;/li&gt;&lt;li&gt;a way to embed the corresponding native libraries into application packages files (.apks) that can be deployed on Android devices&lt;/li&gt;&lt;li&gt;a set of native system headers and libraries that will be supported in all future releases of the Android platform, starting from Android 1.5 documentation, samples and tutorials&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;This release of the NDK supports the ARMv5TE machine instruction set and provides stable headers for:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;libc, the standard C library&lt;/li&gt;&lt;li&gt;libm, the standard math library&lt;/li&gt;&lt;li&gt;the JNI interface&lt;/li&gt;&lt;li&gt;libz, the common ZLib compression library&lt;/li&gt;&lt;li&gt;liblog, used to send logcat messages to the kernel&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Keep in mind that using the NDK will not be relevant for all Android applications. As a developer, you will need to balance its benefits against its drawbacks, which are numerous!  Your application will be more complicated, have reduced compatibility, have no access to framework APIs, and be harder to debug. That said, some applications that have self-contained, CPU-intensive operations that don't allocate much memory may still benefit from increased performance and the ability to reuse existing code.  Some examples are signal processing, intensive physics simulations, and some kinds of data processing.&lt;/p&gt;&lt;p&gt;For any questions on the NDK, please join the &lt;a href="http://groups.google.com/group/android-ndk"&gt;Android NDK forum&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Have fun.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-5375150057279538273?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=2foWz7hwFtE:bMjCa29nU10:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=2foWz7hwFtE:bMjCa29nU10:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=2foWz7hwFtE:bMjCa29nU10:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/2foWz7hwFtE" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/5375150057279538273?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/5375150057279538273?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/2foWz7hwFtE/introducing-android-15-ndk-release-1.html" title="Introducing Android 1.5 NDK, Release 1" /><author><name>David Turner</name><uri>http://www.blogger.com/profile/11184262845691377700</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11972009299897723328" /></author><feedburner:origLink>http://android-developers.blogspot.com/2009/06/introducing-android-15-ndk-release-1.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Dk8FQHkzcSp7ImA9WxJXEEs.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-6365226330003873799</id><published>2009-06-03T13:00:00.000-07:00</published><updated>2009-06-03T14:33:31.789-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-03T14:33:31.789-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Guidelines" /><category scheme="http://www.blogger.com/atom/ns#" term="User Interface" /><title>Activities and Tasks Design Guidelines</title><content type="html">&lt;p&gt;For our third post in the series of Android UI, we're releasing &lt;a href="http://developer.android.com/guide/practices/ui_guidelines/activity_task_design.html"&gt;Activity and Task Design Guidelines&lt;/a&gt;. This section of our guidelines aims to help you understand basic concepts of activities and tasks, how they work, and how to enrich the user experience you are creating.&lt;/p&gt;&lt;p&gt;We've packed a lot into this section, which is targeted at designers and developers. You'll see examples that will illustrate how to use our core principles and mechanisms, such as multitasking, activity reuse, intents, and the back stack.&lt;/p&gt;&lt;p&gt;Additionally, we are providing some best practices around our UI patterns such as notifications. For example, we'll show you how to design a notification so that it will take the user to the screen they expect.  This behavior needs to be thought out, and doesn't necessarily just happen by default.&lt;/p&gt;&lt;p&gt;With helpful pointers to the API's and this documentation, we look forward to building your understanding of what it means to design and develop an Android UI. &lt;/p&gt;&lt;p&gt;&lt;img src="http://1.bp.blogspot.com/_skDnkH-UhlQ/ShzTnAHyxmI/AAAAAAAAABQ/aBL5QqhcuaQ/s400/HomeTaskBasics1d-small.png" alt="" border="0" /&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-6365226330003873799?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=aXdmYVagwDs:7HVK8KTZrHc:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=aXdmYVagwDs:7HVK8KTZrHc:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=aXdmYVagwDs:7HVK8KTZrHc:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/aXdmYVagwDs" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/6365226330003873799?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/6365226330003873799?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/aXdmYVagwDs/activities-and-tasks-design-guidelines.html" title="Activities and Tasks Design Guidelines" /><author><name>Doug Kramer</name><uri>http://www.blogger.com/profile/03063975743681455376</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10482118479720122042" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_skDnkH-UhlQ/ShzTnAHyxmI/AAAAAAAAABQ/aBL5QqhcuaQ/s72-c/HomeTaskBasics1d-small.png" height="72" width="72" /><feedburner:origLink>http://android-developers.blogspot.com/2009/06/activities-and-tasks-design-guidelines.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0MEQ3g9cCp7ImA9WxJQFEU.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-7205415940234122978</id><published>2009-05-27T11:00:00.000-07:00</published><updated>2009-05-27T22:43:22.668-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-27T22:43:22.668-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android Developer Challenge" /><category scheme="http://www.blogger.com/atom/ns#" term="Announcements" /><title>Calling all developers for Android Developer Challenge 2!</title><content type="html">&lt;img src="http://2.bp.blogspot.com/_-e06f1q-QQE/SLcdjvXWN2I/AAAAAAAAAGc/kkSvcvrRWok/s320/android_adc.gif" align="right"&gt;&lt;p&gt;I'm excited to announce the second Android Developer Challenge (ADC)! The first challenge was a huge success with over 1,700 entries that resulted in &lt;a href="http://code.google.com/android/adc/adc_gallery/"&gt;50 excellent winners&lt;/a&gt;. With the recent release of Android 1.5, as well as the availability of devices in multiple markets around the world, I'm pleased to announce the second ADC.&lt;/p&gt;&lt;p&gt;We've expanded ADC 2 to involve a very important part of the Android community&amp;mdash;the users who will be running these applications.  Users of Android-powered devices with Android Market will be able to download a special Android judging application and use it to download and rank applications submitted to the Challenge. The results from this round will determine the top ranking applications in each of the 10 categories.  These top applications will then be ranked by a combination of users and a panel of Google selected judges through a similar process as the first round to determine the final winners.&lt;/p&gt;&lt;p&gt;I've already seen a lot of great apps on Android and I look forward to seeing even more innovative and unexpected cool apps that will come out of this Challenge! For more details on ADC 2, please see the &lt;a href="http://code.google.com/android/adc/"&gt;official site&lt;/a&gt;. Start your engines and good luck!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-7205415940234122978?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=M3e43BWGH_0:66k5Z-Qjxbo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=M3e43BWGH_0:66k5Z-Qjxbo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=M3e43BWGH_0:66k5Z-Qjxbo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/M3e43BWGH_0" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/7205415940234122978?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/7205415940234122978?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/M3e43BWGH_0/calling-all-developers-for-android.html" title="Calling all developers for Android Developer Challenge 2!" /><author><name>Eric Chu, Android Mobile Platform</name><uri>http://www.blogger.com/profile/11243666057159213807</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00850393112957401966" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_-e06f1q-QQE/SLcdjvXWN2I/AAAAAAAAAGc/kkSvcvrRWok/s72-c/android_adc.gif" height="72" width="72" /><feedburner:origLink>http://android-developers.blogspot.com/2009/05/calling-all-developers-for-android.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcEQHc-cSp7ImA9WxJQE0s.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-41231587637295475</id><published>2009-05-26T11:20:00.000-07:00</published><updated>2009-05-26T11:20:01.959-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-26T11:20:01.959-07:00</app:edited><title>Android Icon Guidelines</title><content type="html">&lt;p&gt;&lt;img src="http://docs.google.com/a/google.com/File?id=ad9xdxhtb4_21d5zv7fcb_b" style="width: 172px; height: 164px; float: left; margin-left: 0px; margin-right: 1em;" id="q8te"&gt;For our second post in our series on Android UI, we're releasing our &lt;a title="Icon Design Guidelines" href="http://developer.android.com/guide/practices/ui_guidelines/icon_design.html"&gt;Icon Design Guidelines&lt;/a&gt; and an &lt;a title="Android Icon Templates Pack" href="http://developer.android.com/shareables/icon_templates-v1.0.zip"&gt;Android Icon Templates Pack&lt;/a&gt;. These should make it a lot easier for you (or your designer) to develop all the icons your applications need, so they fit with the other icons in the Android environment.&lt;/p&gt;&lt;p&gt;The Icon Design Guidelines document describes how to design and export icons that fit within the Android framework. It includes a wealth of detail about icons in the &lt;a title="Home screen" href="http://developer.android.com/guide/practices/ui_guidelines/icon_design.html#launcherstructure"&gt;Home screen&lt;/a&gt;, &lt;a title="menus" href="http://developer.android.com/guide/practices/ui_guidelines/icon_design.html#menustructure"&gt;menus&lt;/a&gt;, the &lt;a title="status bar" href="http://developer.android.com/guide/practices/ui_guidelines/icon_design.html#statusbarstructure"&gt;status bar&lt;/a&gt;, &lt;a title="tabs" href="http://developer.android.com/guide/practices/ui_guidelines/icon_design.html#tabstructure"&gt;tabs&lt;/a&gt;, &lt;a title="dialogs" href="http://developer.android.com/guide/practices/ui_guidelines/icon_design.html#dialogstructure"&gt;dialogs&lt;/a&gt;, and &lt;a title="lists" href="http://developer.android.com/guide/practices/ui_guidelines/icon_design.html#listviewstructure"&gt;lists&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;The Android Icon Templates Pack is a collection of template designs, filters, and settings that make it easier for you to create icons that conform to the general specifications given in this Guidelines document. We recommend downloading the template pack archive before you get started with your icon design.&lt;/p&gt;&lt;p&gt;The Templates Pack provides templates in Adobe Photoshop and Adobe Illustrator file formats, which preserves the layers and design treatments we used when creating the standard icons for the Android platform. You can load the template files into any compatible image-editing program, although your ability to work directly with the layers and treatments may vary based on the program you are using.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-41231587637295475?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=4RYt2kBnEUk:cuot_hCQr9o:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=4RYt2kBnEUk:cuot_hCQr9o:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=4RYt2kBnEUk:cuot_hCQr9o:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/4RYt2kBnEUk" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/41231587637295475?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/41231587637295475?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/4RYt2kBnEUk/android-icon-guidelines.html" title="Android Icon Guidelines" /><author><name>Chris Nesladek</name><uri>http://www.blogger.com/profile/00650153306523605448</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="15005591833900444280" /></author><feedburner:origLink>http://android-developers.blogspot.com/2009/05/android-icon-guidelines.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE4EQ387cCp7ImA9WxJQEE8.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-7797948979126681822</id><published>2009-05-22T14:15:00.000-07:00</published><updated>2009-05-22T14:15:02.108-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-22T14:15:02.108-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Google I/O" /><title>Lightning talks at Google I/O</title><content type="html">&lt;p&gt;&lt;a href="http://code.google.com/events/io/"&gt;Google I/O&lt;/a&gt; is approaching, and with over ten &lt;a href="http://code.google.com/events/io/schedule.html"&gt;quality talks&lt;/a&gt; lined up, we should all strive to be attentive, avid learners. But for the last Android session of the conference, we thought it would be fun to unwind and open up the podium for &lt;a href="http://en.wikipedia.org/wiki/Lightning_Talk"&gt;lightning talks&lt;/a&gt;. This is where anyone can take the stage for six minutes and talk about anything. If you've done a cool hack involving Android, if you've devised a clever technique for a common problem, or even if you just want to get up on your soapbox for six minutes to appeal to your fellow developers, this is your time to be heard.&lt;/p&gt;&lt;p&gt;For those planning on attending Google I/O, we need you to submit and judge lightning talk proposals through a &lt;a href="http://moderator.appspot.com/#15/e=6de3b&amp;amp;t=6a7d9"&gt;Google Moderator series&lt;/a&gt; we've set up. Please go ahead and start submitting your proposals. You only have 250 characters to describe the talk, which may be 110 more characters than you've been used to these days.&lt;/p&gt;&lt;p&gt;Voting is open from now until the moment the session starts. We'll take the eight highest rated talks and will call upon each speaker to take the stage. Remember you only have six minutes. Exceed that, and our security force tackles you off the stage. Thanks and see you all at I/O!&lt;/p&gt;&lt;p&gt;&lt;a href="http://moderator.appspot.com/#15/e=6de3b&amp;amp;t=6a7d9"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 111px;" src="http://1.bp.blogspot.com/_Yv8sBwNnaiI/ShbrVCvEzTI/AAAAAAAAABI/-ETRMZrnfmw/s400/cd3jzrcb_24dmsdzmhj_b.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5338713155038399794" /&gt;&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-7797948979126681822?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=IAriuc6svpw:jwtF-ra43mg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=IAriuc6svpw:jwtF-ra43mg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=IAriuc6svpw:jwtF-ra43mg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/IAriuc6svpw" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/7797948979126681822?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/7797948979126681822?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/IAriuc6svpw/lightning-talks-at-google-io.html" title="Lightning talks at Google I/O" /><author><name>James Yum</name><uri>http://www.blogger.com/profile/08187363046295257307</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="09184109853385563376" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_Yv8sBwNnaiI/ShbrVCvEzTI/AAAAAAAAABI/-ETRMZrnfmw/s72-c/cd3jzrcb_24dmsdzmhj_b.png" height="72" width="72" /><feedburner:origLink>http://android-developers.blogspot.com/2009/05/lightning-talks-at-google-io.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08ASHc8cCp7ImA9WxJSFk4.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-2021514946948968931</id><published>2009-05-06T09:30:00.000-07:00</published><updated>2009-05-06T10:44:09.978-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-06T10:44:09.978-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="How-to" /><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><category scheme="http://www.blogger.com/atom/ns#" term="User Interface" /><title>Painless threading</title><content type="html">&lt;p&gt;Whenever you first start an Android application, a thread called "main" is automatically created. The main thread, also called the UI thread, is very important because it is in charge of dispatching the events to the appropriate widgets and this includes the drawing events. It is also the thread you interact with Android widgets on. For instance, if you touch the a button on screen, the UI thread dispatches the touch event to the widget which in turn sets its pressed state and posts an invalidate request to the event queue. The UI thread dequeues the request and notifies the widget to redraw itself.&lt;/p&gt;&lt;p&gt;This single thread model can yield poor performance in Android applications that do not consider the implications. Since everything happens on a single thread performing long operations, like network access or database queries, on this thread will block the whole user interface. No event can be dispatched, including drawing events, while the long operation is underway. From the user's perspective, the application appears hung. Even worse, if the UI thread is blocked for more than a few seconds (about 5 seconds currently) the user is presented with the infamous "&lt;a href="http://developer.android.com/guide/practices/design/responsiveness.html"&gt;application not responding&lt;/a&gt;" (ANR) dialog.&lt;/p&gt;&lt;p&gt;If you want to see how bad this can look, write a simple application with a button that invokes &lt;code&gt;Thread.sleep(2000)&lt;/code&gt; in its &lt;a href="http://developer.android.com/reference/android/view/View.OnClickListener.html"&gt;OnClickListener&lt;/a&gt;. The button will remain in its pressed state for about 2 seconds before going back to its normal state. When this happens, it is very easy for the user to &lt;em&gt;perceive&lt;/em&gt; the application as slow.&lt;/p&gt;&lt;p&gt;Now that you know you &lt;em&gt;must&lt;/em&gt; avoid lengthy operations on the UI thread, you will probably use extra threads (&lt;em&gt;background&lt;/em&gt; or &lt;em&gt;worker&lt;/em&gt; threads) to perform these operations, and rightly so. Let's take the example of a click listener downloading an image over the network and displaying it in an &lt;a href="http://developer.android.com/reference/android/widget/ImageView.html"&gt;ImageView&lt;/a&gt;:&lt;/p&gt;&lt;pre class="prettyprint"&gt;public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
      Bitmap b = loadImageFromNetwork();
      mImageView.setImageBitmap(b);
    }
  }).start();
}&lt;/pre&gt;&lt;p&gt;At first, this code seems to be a good solution to your problem, as it does not block the UI thread. Unfortunately, it violates the single thread model: the Android UI toolkit is not thread-safe and must always be manipulated on the UI thread. In this piece of code, the &lt;code&gt;ImageView&lt;/code&gt; is manipulated on a worker thread, which can cause really weird problems. Tracking down and fixing such bugs can be difficult and time-consuming.&lt;/p&gt;&lt;p&gt;Android offers several ways to access the UI thread from other threads. You may already be familiar with some of them but here is a comprehensive list:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="http://developer.android.com/reference/android/app/Activity.html#runOnUiThread(java.lang.Runnable)"&gt;Activity.runOnUiThread(Runnable)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://developer.android.com/reference/android/view/View.html#post(java.lang.Runnable)"&gt;View.post(Runnable)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://developer.android.com/reference/android/view/View.html#postDelayed(java.lang.Runnable,%20long)"&gt;View.postDelayed(Runnable, long)&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="http://developer.android.com/reference/android/os/Handler.html"&gt;Handler&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;Any of these classes and methods could be used to correct our previous code example:&lt;/p&gt;&lt;pre class="prettyprint"&gt;public void onClick(View v) {
  new Thread(new Runnable() {
    public void run() {
      final Bitmap b = loadImageFromNetwork();
      mImageView.post(new Runnable() {
        public void run() {
          mImageView.setImageBitmap(b);
        }
      });
    }
  }).start();
}&lt;/pre&gt;&lt;p&gt;Unfortunately, these classes and methods also tend to make your code more complicated and more difficult to read. It becomes even worse when your implement complex operations that require frequent UI updates. To remedy this problem, Android 1.5 offers a new utility class, called &lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html"&gt;AsyncTask&lt;/a&gt;, that simplifies the creation of long-running tasks that need to communicate with the user interface.&lt;/p&gt;&lt;p&gt;&lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html"&gt;AsyncTask&lt;/a&gt; is also available for Android 1.0 and 1.1 under the name &lt;a href="http://code.google.com/p/shelves/source/browse/trunk/Shelves/src/org/curiouscreature/android/shelves/util/UserTask.java"&gt;UserTask&lt;/a&gt;. It offers the exact same API and all you have to do is copy its source code in your application.&lt;/p&gt;&lt;p&gt;The goal of &lt;code&gt;AsyncTask&lt;/code&gt; is to take care of thread management for you. Our previous example can easily be rewritten with &lt;code&gt;AsyncTask&lt;/code&gt;:&lt;/p&gt;&lt;pre class="prettyprint"&gt;public void onClick(View v) {
  new DownloadImageTask().execute("http://example.com/image.png");
}

private class DownloadImageTask extends AsyncTask&lt;String, Void, Bitmap&gt; {
     protected Bitmap doInBackground(String... urls) {
         return loadImageFromNetwork(urls[0]);
     }

     protected void onPostExecute(Bitmap result) {
         mImageView.setImageBitmap(result);
     }
 }&lt;/pre&gt;&lt;p&gt;As you can see, &lt;code&gt;AsyncTask&lt;/code&gt; &lt;em&gt;must&lt;/em&gt; be used by subclassing it. It is also very important to remember that an &lt;code&gt;AsyncTask&lt;/code&gt; instance has to be created on the UI thread and can be executed only once. You can read the &lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html"&gt;AsyncTask documentation&lt;/a&gt; for a full understanding on how to use this class, but here is a quick overview of how it works:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;You can specify the type, using generics, of the parameters, the progress values and the final value of the task&lt;/li&gt;&lt;li&gt;The method &lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html#doInBackground(Params...)"&gt;doInBackground()&lt;/a&gt; executes automatically on a worker thread&lt;/li&gt;&lt;li&gt;&lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html#onPreExecute()"&gt;onPreExecute()&lt;/a&gt;, &lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html#onPostExecute(Result)"&gt;onPostExecute()&lt;/a&gt; and &lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html#onProgressUpdate(Progress...)"&gt;onProgressUpdate()&lt;/a&gt; are all invoked on the UI thread&lt;/li&gt;&lt;li&gt;The value returned by &lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html#doInBackground(Params...)"&gt;doInBackground()&lt;/a&gt; is sent to &lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html#onPostExecute(Result)"&gt;onPostExecute()&lt;/a&gt;&lt;/li&gt;&lt;li&gt;You can call &lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html#publishProgress(Progress...)"&gt;publishProgress()&lt;/a&gt; at anytime in &lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html#doInBackground(Params...)"&gt;doInBackground()&lt;/a&gt; to execute &lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html#onProgressUpdate(Progress...)"&gt;onProgressUpdate()&lt;/a&gt; on the UI thread&lt;/li&gt;&lt;li&gt;You can cancel the task at any time, from any thread&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In addition to the official documentation, you can read several complex examples in the source code of Shelves (&lt;a href="http://code.google.com/p/shelves/source/browse/trunk/Shelves/src/org/curiouscreature/android/shelves/activity/ShelvesActivity.java"&gt;ShelvesActivity.java&lt;/a&gt; and &lt;a href="http://code.google.com/p/shelves/source/browse/trunk/Shelves/src/org/curiouscreature/android/shelves/activity/AddBookActivity.java"&gt;AddBookActivity.java&lt;/a&gt;) and Photostream (&lt;a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/src/com/google/android/photostream/LoginActivity.java"&gt;LoginActivity.java&lt;/a&gt;, &lt;a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/src/com/google/android/photostream/PhotostreamActivity.java"&gt;PhotostreamActivity.java&lt;/a&gt; and &lt;a href="http://code.google.com/p/apps-for-android/source/browse/trunk/Photostream/src/com/google/android/photostream/ViewPhotoActivity.java"&gt;ViewPhotoActivity.java&lt;/a&gt;). I highly recommend reading the source code of &lt;a href="http://code.google.com/p/shelves/"&gt;Shelves&lt;/a&gt; to see how to persist tasks across configuration changes and how to cancel them properly when the activity is destroyed.&lt;/p&gt;&lt;p&gt;Regardless of whether or not you use &lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html"&gt;AsyncTask&lt;/a&gt;, always remember these two rules about the single thread model: do not block the UI thread and make sure the Android UI toolkit is only accessed on the UI thread. &lt;a href="http://developer.android.com/reference/android/os/AsyncTask.html"&gt;AsyncTask&lt;/a&gt; just makes it easier to do both of these things.&lt;/p&gt;&lt;p&gt;If you want to learn more cool techniques, come join us at &lt;a href="http://code.google.com/events/io/"&gt;Google I/O&lt;/a&gt;. Members of the Android team will be there to give a &lt;a href="http://code.google.com/events/io/sessions.html#android"&gt;series of in-depth technical sessions&lt;/a&gt; and answer all your questions.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-2021514946948968931?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=rV3jg9vInwQ:K5VTaqzVCBE:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=rV3jg9vInwQ:K5VTaqzVCBE:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=rV3jg9vInwQ:K5VTaqzVCBE:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/rV3jg9vInwQ" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/2021514946948968931?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/2021514946948968931?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/rV3jg9vInwQ/painless-threading.html" title="Painless threading" /><author><name>Romain Guy</name><uri>http://www.blogger.com/profile/14359137835485363401</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11053364165382206530" /></author><feedburner:origLink>http://android-developers.blogspot.com/2009/05/painless-threading.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcER3s-eSp7ImA9WxJSFEo.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-2432088149258057512</id><published>2009-05-04T16:00:00.000-07:00</published><updated>2009-05-04T16:00:06.551-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-04T16:00:06.551-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="How-to" /><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><category scheme="http://www.blogger.com/atom/ns#" term="User Interface" /><title>Drawable mutations</title><content type="html">&lt;p&gt;Android's drawables are extremely useful to easily build applications. A &lt;a href="http://developer.android.com/reference/android/graphics/drawable/Drawable.html"&gt;Drawable&lt;/a&gt; is a pluggable drawing container that is usually associated with a View. For instance, a &lt;a href="http://developer.android.com/reference/android/graphics/drawable/BitmapDrawable.html"&gt;BitmapDrawable&lt;/a&gt; is used to display images, a &lt;a href="http://developer.android.com/reference/android/graphics/drawable/ShapeDrawable.html"&gt;ShapeDrawable&lt;/a&gt; to draw shapes and gradients, etc. You can even combine them to create complex renderings.&lt;/p&gt;&lt;p&gt;Drawables allow you to easily customize the rendering of the widgets without subclassing them. As a matter of fact, they are so convenient that most of the default Android apps and widgets are built using drawables; there are about 700 drawables used in the core Android framework. Because drawables are used so extensively throughout the system, Android optimizes them when they are loaded from resources. For instance, every time you create a &lt;a href="http://developer.android.com/reference/android/widget/Button.html"&gt;Button&lt;/a&gt;, a new drawable is loaded from the framework resources (&lt;code&gt;android.R.drawable.btn_default&lt;/code&gt;). This means all buttons across all the apps use a different drawable instance as their background. However, all these drawables share a common state, called the "constant state." The content of this state varies according to the type of drawable you are using, but it usually contains all the properties that can be defined by a resource. In the case of a button, the constant state contains a bitmap image. This way, all buttons across all applications share the same bitmap, which saves a lot of memory.&lt;/p&gt;&lt;p&gt;The following diagram shows what entities are created when you assign the same image resource as the background of two different views. As you can see, two drawables are created but they both share the same constant state, hence the same bitmap:&lt;/p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 307px; height: 400px;" src="http://1.bp.blogspot.com/_9l0GmPwgCzk/Sf0SgfbQcVI/AAAAAAAAAD8/xKcxTQCAxn0/s400/shared_states.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5331437883277472082" /&gt;&lt;p&gt;This state sharing feature is great to avoid wasting memory but it can cause problems when you try to modify the properties of a drawable. Imagine an application with a list of books. Each book has a star next to its name, totally opaque when the user marks the book as a favorite, and translucent when the book is not a favorite. To achieve this effect, you would probably write the following code in your list adapter's &lt;code&gt;getView()&lt;/code&gt; method:&lt;/p&gt;&lt;pre&gt;Book book = ...;
TextView listItem = ...;

listItem.setText(book.getTitle());

Drawable star = context.getResources().getDrawable(R.drawable.star);
if (book.isFavorite()) {
  star.setAlpha(255); // opaque
} else {
  star.setAlpha(70); // translucent
}&lt;/pre&gt;&lt;p&gt;Unfortunately, this piece of code yields a rather strange result, all the drawables have the same opacity:&lt;/p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://4.bp.blogspot.com/_9l0GmPwgCzk/Sf0TgPCgubI/AAAAAAAAAEE/xP3FxmTfOgg/s400/all_drawables_changed.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5331438978390342066" /&gt;&lt;p&gt;This result is explained by the constant state. Even though we are getting a new drawable instance for each list item, the constant state remains the same and, in the case of BitmapDrawable, the opacity is part of the constant state. Thus, changing the opacity of one drawable instance changes the opacity of all the other instances. Even worse, working around this issue was not easy with Android 1.0 and 1.1.&lt;/p&gt;&lt;p&gt;Android 1.5 offers a very way to solve this issue with a the new &lt;a href="http://developer.android.com/reference/android/graphics/drawable/Drawable.html#mutate()"&gt;mutate() method&lt;/a&gt;. When you invoke this method on a drawable, the constant state of the drawable is duplicated to allow you to change any property without affecting other drawables. Note that bitmaps are still shared, even after mutating a drawable. The diagram below shows what happens when you invoke &lt;code&gt;mutate()&lt;/code&gt; on a drawable:&lt;/p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 307px; height: 400px;" src="http://3.bp.blogspot.com/_9l0GmPwgCzk/Sf0UkFtP6PI/AAAAAAAAAEM/2ywQ5XZlpP4/s400/mutated_states.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5331440144116345074" /&gt;&lt;p&gt;Let's update our previous piece of code to make use of &lt;code&gt;mutate()&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;Drawable star = context.getResources().getDrawable(R.drawable.star);
if (book.isFavorite()) {
  star.mutate().setAlpha(255); // opaque
} else {
  star. mutate().setAlpha(70); // translucent
}&lt;/pre&gt;&lt;p&gt;For convenience, &lt;code&gt;mutate()&lt;/code&gt; returns the drawable itself, which allows to chain method calls. It does not however create a new drawable instance. With this new piece of code, our application now behaves correctly:&lt;/p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://4.bp.blogspot.com/_9l0GmPwgCzk/Sf0VHyzBWlI/AAAAAAAAAEU/9wdeSyWHo4M/s400/correct_drawables.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5331440757515573842" /&gt;&lt;p&gt;If you want to learn more cool techniques, come join us at &lt;a href="http://code.google.com/events/io/"&gt;Google I/O&lt;/a&gt;. Members of the Android team will be there to give a &lt;a href="http://code.google.com/events/io/sessions.html#android"&gt;series of in-depth technical sessions&lt;/a&gt; and answer all your questions.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-2432088149258057512?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=zwURoE8P_p0:w_4CqK96T7w:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=zwURoE8P_p0:w_4CqK96T7w:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=zwURoE8P_p0:w_4CqK96T7w:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/zwURoE8P_p0" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/2432088149258057512?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/2432088149258057512?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/zwURoE8P_p0/drawable-mutations.html" title="Drawable mutations" /><author><name>Romain Guy</name><uri>http://www.blogger.com/profile/14359137835485363401</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11053364165382206530" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_9l0GmPwgCzk/Sf0SgfbQcVI/AAAAAAAAAD8/xKcxTQCAxn0/s72-c/shared_states.png" height="72" width="72" /><feedburner:origLink>http://android-developers.blogspot.com/2009/05/drawable-mutations.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEcGRXg9eCp7ImA9WxJSEUk.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-1320639687853600653</id><published>2009-04-30T18:30:00.000-07:00</published><updated>2009-04-30T18:40:24.660-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-30T18:40:24.660-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Guidelines" /><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><category scheme="http://www.blogger.com/atom/ns#" term="Widgets" /><title>Widget Design Guidelines</title><content type="html">&lt;p&gt;Since the beginning of the year, the Android UI team has been hard at work on the Android 1.5 release. Starting today with widgets, we would like to share some of our evolving Android design principles with you.&lt;img src="http://docs.google.com/a/google.com/File?id=ad9xdxhtb4_2d25jqdcx_b" style="width: 406px; height: 383px; float: left; margin-left: 0px; margin-right: 1em"&gt;&lt;/p&gt;&lt;p&gt;Widgets are a new feature that application developers can use to promote a small sample of the most relevant dynamic data from their applications on the Home screen. We've designed widgets to fit within our Home screen grid framework, which means you and your designer can create a widget within a 4x1, 3x3, or 2x2 grid cell, depending on the space you need for an at-a-glance summary of information from your application. To illustrate the preferred ways to design widgets for the home screen, we've assembled &lt;a href="http://developer.android.com/guide/practices/ui_guidelines/widget_design.html"&gt;Widget Design Guidelines&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;We're also providing the original artwork assets and source files that we used to create the widgets bundled with Android 1.5. If you want your widgets to match the platform in terms of appearance, use the templates that are available throughout the Widget Design Guidelines.&lt;/p&gt;&lt;p&gt;For more technical information around widgets, take a look at Jeff Sharkey's &lt;a href="http://android-developers.blogspot.com/2009/04/introducing-home-screen-widgets-and.html"&gt;blog post&lt;/a&gt; as well as the &lt;a href="http://developer.android.com/guide/topics/appwidgets/index.html"&gt;AppWidgets&lt;/a&gt; documentation.&lt;/p&gt;&lt;p&gt;We've only just begun to scratch the surface of what's possible using widgets. We're looking forward to seeing how far you can extend our work!&lt;/p&gt;&lt;p&gt;One last thing: in the coming weeks, we'll be rolling out more articles and presentations that demonstrate design best practices for Android. For example, if you've ever wanted to learn how to create and be consistent with iconography on Android, stay tuned: we'll be posting sample guides and templates.&lt;/p&gt;&lt;hr style="align: center; width: 66%; border: none 0; border-top: 1px dashed #000;" /&gt;&lt;p&gt;&lt;em&gt;Learn about Android 1.5 and more at &lt;a href="http://code.google.com/events/io/"&gt;Google I/O&lt;/a&gt;. Members of the Android team will be there to give a series of &lt;a href="http://code.google.com/events/io/sessions.html#android"&gt;in-depth technical sessions&lt;/a&gt; and to field your toughest questions.&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-1320639687853600653?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=tHBkABlluNo:L_G4zm2umiY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=tHBkABlluNo:L_G4zm2umiY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=tHBkABlluNo:L_G4zm2umiY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/tHBkABlluNo" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/1320639687853600653?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/1320639687853600653?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/tHBkABlluNo/widget-design-guidelines.html" title="Widget Design Guidelines" /><author><name>Chris Nesladek</name><uri>http://www.blogger.com/profile/00650153306523605448</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="15005591833900444280" /></author><feedburner:origLink>http://android-developers.blogspot.com/2009/04/widget-design-guidelines.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEUMSHw8fSp7ImA9WxJTGUs.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-2882740941826082333</id><published>2009-04-28T07:00:00.000-07:00</published><updated>2009-04-28T16:44:49.275-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-28T16:44:49.275-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="How-to" /><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><title>Backward compatibility for Android applications</title><content type="html">&lt;p&gt;Android 1.5 introduced a number of new features that application developers can take advantage of, like virtual input devices and speech recognition.  As a developer, you need to be aware of backward compatibility issues on older devices—do you want to allow your application to run on all devices, or just those running newer software?  In some cases it will be useful to employ the newer APIs on devices that support them, while continuing to support older devices.&lt;/p&gt;&lt;p&gt;If the use of a new API is integral to the program—perhaps you need to record video—you should add a manifest entry to ensure your app won't be installed on older devices.  For example, if you require APIs added in 1.5, you would &lt;a href="http://developer.android.com/guide/publishing/versioning.html#minsdkversion"&gt;specify 3 as the minimum SDK version&lt;/a&gt;:&lt;/p&gt;&lt;pre&gt;  &amp;lt;manifest&amp;gt;
   ...
   &amp;lt;uses-sdk android:minSdkVersion="3" /&amp;gt;
   ...
  &amp;lt;/manifest&amp;gt;&lt;/pre&gt;&lt;p&gt;If you want to add a useful but non-essential feature, such as popping up an on-screen keyboard even when a hardware keyboard is available, you can write your program in a way that allows it to use the newer features without failing on older devices.&lt;/p&gt;&lt;h3&gt;Using reflection&lt;/h3&gt;&lt;p&gt;Suppose there's a simple new call you want to use, like &lt;code&gt;&lt;a href="http://developer.android.com/reference/android/os/Debug.html#dumpHprofData%28java.lang.String%29"&gt;android.os.Debug.dumpHprofData(String filename)&lt;/a&gt;&lt;/code&gt;.  The &lt;code&gt;&lt;a href="http://developer.android.com/reference/android/os/Debug.html"&gt;android.os.Debug&lt;/a&gt;&lt;/code&gt; class has existed since the first SDK, but the method is new in 1.5.  If you try to call it directly, your app will fail to run on older devices.&lt;/p&gt;&lt;p&gt;The simplest way to call the method is through reflection.  This requires doing a one-time lookup and caching the result in a &lt;code&gt;Method&lt;/code&gt; object.  Using the method is a matter of calling &lt;code&gt;Method.invoke&lt;/code&gt; and un-boxing the result.  Consider the following:&lt;/p&gt;&lt;pre&gt;public class Reflect {
   private static Method mDebug_dumpHprofData;

   static {
       initCompatibility();
   };

   private static void initCompatibility() {
       try {
           mDebug_dumpHprofData = Debug.class.getMethod(
                   "dumpHprofData", new Class[] { String.class } );
           /* success, this is a newer device */
       } catch (NoSuchMethodException nsme) {
           /* failure, must be older device */
       }
   }

   private static void dumpHprofData(String fileName) throws IOException {
       try {
           mDebug_dumpHprofData.invoke(null, fileName);
       } catch (InvocationTargetException ite) {
           /* unpack original exception when possible */
           Throwable cause = ite.getCause();
           if (cause instanceof IOException) {
               throw (IOException) cause;
           } else if (cause instanceof RuntimeException) {
               throw (RuntimeException) cause;
           } else if (cause instanceof Error) {
               throw (Error) cause;
           } else {
               /* unexpected checked exception; wrap and re-throw */
               throw new RuntimeException(ite);
           }
       } catch (IllegalAccessException ie) {
           System.err.println("unexpected " + ie);
       }
   }

   public void fiddle() {
       if (mDebug_dumpHprofData != null) {
           /* feature is supported */
           try {
               dumpHprofData("/sdcard/dump.hprof");
           } catch (IOException ie) {
               System.err.println("dump failed!");
           }
       } else {
           /* feature not supported, do something else */
           System.out.println("dump not supported");
       }
   }
}&lt;/pre&gt;&lt;p&gt;This uses a static initializer to call &lt;code&gt;initCompatibility&lt;/code&gt;, which does the method lookup.  If that succeeds, it uses a private method with the same semantics as the original (arguments, return value, checked exceptions) to do the call.  The return value (if it had one) and exception are unpacked and returned in a way that mimics the original.  The &lt;code&gt;fiddle&lt;/code&gt; method demonstrates how the application logic would choose to call the new API or do something different based on the presence of the new method.&lt;/p&gt;&lt;p&gt;For each additional method you want to call, you would add an additional private &lt;code&gt;Method&lt;/code&gt; field, field initializer, and call wrapper to the class.&lt;/p&gt;&lt;p&gt;This approach becomes a bit more complex when the method is declared in a previously undefined class.  It's also much slower to call &lt;code&gt;Method.invoke()&lt;/code&gt; than it is to call the method directly.  These issues can be mitigated by using a wrapper class.&lt;/p&gt;&lt;h3&gt;Using a wrapper class&lt;/h3&gt;&lt;p&gt;The idea is to create a class that wraps all of the new APIs exposed by a new or existing class. Each method in the wrapper class just calls through to the corresponding real method and returns the same result.&lt;/p&gt;&lt;p&gt;If the target class and method exist, you get the same behavior you would get by calling the class directly, with a small amount of overhead from the additional method call.  If the target class or method doesn't exist, the initialization of the wrapper class fails, and your application knows that it should avoid using the newer calls.&lt;/p&gt;&lt;p&gt;Suppose this new class were added:&lt;/p&gt;&lt;pre&gt;public class NewClass {
   private static int mDiv = 1;

   private int mMult;

   public static void setGlobalDiv(int div) {
       mDiv = div;
   }

   public NewClass(int mult) {
       mMult = mult;
   }

   public int doStuff(int val) {
       return (val * mMult) / mDiv;
   }
}&lt;/pre&gt;&lt;p&gt;We would create a wrapper class for it:&lt;/p&gt;&lt;pre&gt;class WrapNewClass {
   private NewClass mInstance;

   /* class initialization fails when this throws an exception */
   static {
       try {
           Class.forName("NewClass");
       } catch (Exception ex) {
           throw new RuntimeException(ex);
       }
   }

   /* calling here forces class initialization */
   public static void checkAvailable() {}

   public static void setGlobalDiv(int div) {
       NewClass.setGlobalDiv(div);
   }

   public WrapNewClass(int mult) {
       mInstance = new NewClass(mult);
   }

   public int doStuff(int val) {
       return mInstance.doStuff(val);
   }
}&lt;/pre&gt;&lt;p&gt;This has one method for each constructor and method in the original, plus a static initializer that tests for the presence of the new class.  If the new class isn't available, initialization of &lt;code&gt;WrapNewClass&lt;/code&gt; fails, ensuring that the wrapper class can't be used inadvertently.  The &lt;code&gt;checkAvailable&lt;/code&gt; method is used as a simple way to force class initialization.  We use it like this:&lt;/p&gt;&lt;pre&gt;public class MyApp {
   private static boolean mNewClassAvailable;

   /* establish whether the "new" class is available to us */
   static {
       try {
           WrapNewClass.checkAvailable();
           mNewClassAvailable = true;
       } catch (Throwable t) {
           mNewClassAvailable = false;
       }
   }

   public void diddle() {
       if (mNewClassAvailable) {
           WrapNewClass.setGlobalDiv(4);
           WrapNewClass wnc = new WrapNewClass(40);
           System.out.println("newer API is available - " + wnc.doStuff(10));
       } else {
           System.out.println("newer API not available");
       }
   }
}&lt;/pre&gt;&lt;p&gt;If the call to &lt;code&gt;checkAvailable&lt;/code&gt; succeeds, we know the new class is part of the system.  If it fails, we know the class isn't there, and adjust our expectations accordingly.  It should be noted that the call to &lt;code&gt;checkAvailable&lt;/code&gt; will fail before it even starts if the bytecode verifier decides that it doesn't want to accept a class that has references to a nonexistent class.  The way this code is structured, the end result is the same whether the exception comes from the verifier or from the call to &lt;code&gt;Class.forName&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;When wrapping an existing class that now has new methods, you only need to put the new methods in the wrapper class.  Invoke the old methods directly.  The static initializer in &lt;code&gt;WrapNewClass&lt;/code&gt; would be augmented to do a one-time check with reflection.&lt;/p&gt;&lt;h3&gt;Testing is key&lt;/h3&gt;&lt;p&gt;You must test your application on every version of the Android framework that is expected to support it.  By definition, the behavior of your application will be different on each.  Remember the mantra: if you haven't tried it, it doesn't work.&lt;/p&gt;&lt;p&gt;You can test for backward compatibility by running your application in an emulator from an older SDK, but as of the 1.5 release there's a better way.  The SDK allows you to specify "Android Virtual Devices" with different API levels.  Once you create the AVDs, you can test your application with old and new versions of the system, perhaps running them side-by-side to see the differences.  More information about emulator AVDs can be found &lt;a href="http://developer.android.com/guide/developing/tools/avd.html"&gt;in the SDK documentation&lt;/a&gt; and from &lt;code&gt;emulator -help-virtual-device&lt;/code&gt;.&lt;/p&gt;&lt;hr style="align: center; width: 66%; border: none 0; border-top: 1px dashed #000;" /&gt;&lt;p&gt;&lt;em&gt;Learn about Android 1.5 and more at &lt;a href="http://code.google.com/events/io/"&gt;Google I/O&lt;/a&gt;. Members of the Android team will be there to give a series of &lt;a href="http://code.google.com/events/io/sessions.html#android"&gt;in-depth technical sessions&lt;/a&gt; and to field your toughest questions.&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-2882740941826082333?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=7cGBsPVzWWM:q2Rk4ekKBZg:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=7cGBsPVzWWM:q2Rk4ekKBZg:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=7cGBsPVzWWM:q2Rk4ekKBZg:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/7cGBsPVzWWM" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/2882740941826082333?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/2882740941826082333?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/7cGBsPVzWWM/backward-compatibility-for-android.html" title="Backward compatibility for Android applications" /><author><name>Andy McFadden</name><uri>http://www.blogger.com/profile/00364072745010016951</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10493149835825858873" /></author><feedburner:origLink>http://android-developers.blogspot.com/2009/04/backward-compatibility-for-android.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcER3s-fCp7ImA9WxJTGEs.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-403910035873942175</id><published>2009-04-27T14:00:00.000-07:00</published><updated>2009-04-27T14:00:06.554-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-27T14:00:06.554-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><category scheme="http://www.blogger.com/atom/ns#" term="Google I/O" /><title>Android 1.5 at Google I/O</title><content type="html">&lt;img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 200px; height: 200px;" src="http://1.bp.blogspot.com/_DJiuxagkTVU/SfXLKfdYqpI/AAAAAAAAADE/ACW6FfnZfP0/s320/IO_blogpost-R2-blue.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5329389115166730898" /&gt;&lt;p&gt;I admit, I've been talking big about &lt;a href="http://code.google.com/events/io"&gt;Google I/O&lt;/a&gt; in my last few posts. But I'm entirely serious: Google I/O is going to be the Android developer event of the year, no doubt about it. I want to take a few minutes to explain why.&lt;/p&gt;&lt;p&gt;The most exciting aspect, to my mind, is the technical content. We have 9 sessions listed now on the &lt;a href="http://code.google.com/events/io/sessions.html"&gt;Google I/O sessions site&lt;/a&gt;, and we're working on still more. (And that's not even including the fireside chat with the Android Core Technical Team.) I recently sat down with some of the speakers to discuss their topics, and found that this is very solid material. Here are some of the sessions I'm excited about.&lt;/p&gt;&lt;p&gt;My background is strictly in engineering, and I never had the chance in college to take any design courses. So one session I'll definitely be at is Chris Nesladek's "Pixel Perfect Code". He's going to start with the basics, and give us an overview of the theory of UI design, and then explain the principles that we use when designing the core Android UI. If you like the UI updates that you've seen in the &lt;a href="http://android-developers.blogspot.com/2009/04/android-15-final-is-here.html"&gt;Android 1.5&lt;/a&gt; "Cupcake" user interface, then be at this session.&lt;/p&gt;&lt;p&gt;My particular team works intensively with developers to help them build and launch applications. Justin Mattson is going to share some of the hard-earned debugging and performance techniques that we've picked up in our work with partners. He's going to walk you through some actual, real-world apps on the &lt;a href="http://market.android.com/"&gt;Android Market&lt;/a&gt; and show you how we squeezed the bugs out of them.&lt;/p&gt;&lt;p&gt;Now, they told me to focus on only one or two sessions in this post, but forget that. I can't resist! I have to tell you about a couple more, like David Sparks' session on the media framework. One of the most common questions we get asked goes something like "dude, what is up with all these codecs? AAC? MP3? OGG? MPEG? H264?" David's going to answer that question—among many others -- and explain how the media framework is designed and operates. Armed with this new understanding, you'll be able to make smarter choices as you design the media components of your own apps.&lt;/p&gt;&lt;p&gt;And last (for today), I want to mention Jeff Sharkey's "Coding for Life—Battery Life" session. A statement like "it's important to code efficiently on mobile devices" is deceptively simple. It turns out that what constitutes efficient code on, say, the desktop is sometimes woefully hard on battery life, on mobiles. What I've learned to tell developers is "everything you know is wrong." That's why I'm looking forward to Jeff's session. He's going to go through a whole basket of tips and tricks, backed up by some nice crunchy numbers.&lt;/p&gt;&lt;p&gt;And of course, these are just the technical sessions (and not even half of those.) We're also going to have quite a few folks representing some of our app developer and &lt;a href="http://www.openhandsetalliance.com/oha_members.html"&gt;Open Handset Alliance partners&lt;/a&gt; at Google I/O, but I'll save those details for another post.  I'm also looking forward to turning the tables, and giving some of you the floor. Besides the fireside chat where you can ask the &lt;a href="http://source.android.com/project/core-technical-team"&gt;Core Technical Team&lt;/a&gt; all the thorny technical questions you've been saving up, there's also a Lightning Talks session just for Android developers, and an Android Corner mixer area in the After-Hours Playground.&lt;/p&gt;&lt;p&gt;I'm also excited about a few surprises we've lined up... but I can't say anything about those, or they wouldn't be surprises, would they?&lt;/p&gt;&lt;p&gt;So, there you have it. Excitement! Drama! Surprises! It's like a movie trailer, but without the awesome voiceover. I hope it worked, and that you all are looking forward to Google I/O as much as I am. (By the way, I'm instructed to inform you that you can save a bit of coin by &lt;a href="https://io2009.event-projects.com/"&gt;registering early&lt;/a&gt;. You might want to hurry though, since early registration ends May 1.)&lt;/p&gt;&lt;p&gt;Happy Coding!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-403910035873942175?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=W66WrwpyR1A:86jfyUazCsM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=W66WrwpyR1A:86jfyUazCsM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=W66WrwpyR1A:86jfyUazCsM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/W66WrwpyR1A" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/403910035873942175?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/403910035873942175?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/W66WrwpyR1A/android-15-at-google-io.html" title="Android 1.5 at Google I/O" /><author><name>Dan Morrill</name><uri>http://www.blogger.com/profile/12526265248010766454</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="17206489683788395259" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_DJiuxagkTVU/SfXLKfdYqpI/AAAAAAAAADE/ACW6FfnZfP0/s72-c/IO_blogpost-R2-blue.png" height="72" width="72" /><feedburner:origLink>http://android-developers.blogspot.com/2009/04/android-15-at-google-io.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0AGQHw7eCp7ImA9WxJTGEg.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-3207818865799105949</id><published>2009-04-27T10:02:00.000-07:00</published><updated>2009-04-27T10:02:01.200-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-27T10:02:01.200-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android Developer Phone" /><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><category scheme="http://www.blogger.com/atom/ns#" term="SDK updates" /><category scheme="http://www.blogger.com/atom/ns#" term="Announcements" /><title>Android 1.5 is here!</title><content type="html">&lt;p&gt;I've got some good news today: the Android 1.5 SDK, release 1 is ready! Grab it from the &lt;a href="http://developer.android.com/sdk/1.5_r1/index.html"&gt;download page&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;For an overview of the new Android 1.5 features, see the &lt;a href="http://developer.android.com/sdk/RELEASENOTES.html"&gt;1.5 release notes page&lt;/a&gt; in our developer site.&lt;/p&gt;&lt;p&gt;I am also happy to let you know that our partners at HTC have made available &lt;a title="new system images" href="http://www.htc.com/www/support/android/adp.html" id="wa__"&gt;new system images&lt;/a&gt; to upgrade your Android Dev Phone 1 (ADP1) to Android 1.5. This new version (which is only available for the ADP1) is based on the Cupcake branch from the &lt;a href="http://source.android.com/"&gt;Android Open Source Project&lt;/a&gt; and corresponds to the system image of the Android 1.5 SDK, release 1. If you have questions about the process of updating your device, you can &lt;a href="http://groups.google.com/group/android-devphone-updating" id="qs4f" title="ask the mailing list"&gt;ask the mailing list&lt;/a&gt; that we've set up.&lt;/p&gt;&lt;p&gt;I'd also like to note that Android developer phones like the ADP1 are intended for application development, rather than daily use. Additionally, they are operator-neutral and country-neutral, so they may not include certain features found on end-user devices.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-3207818865799105949?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=iVODJL9H09M:QEGkMfYvrP8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=iVODJL9H09M:QEGkMfYvrP8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=iVODJL9H09M:QEGkMfYvrP8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/iVODJL9H09M" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/3207818865799105949?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/3207818865799105949?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/iVODJL9H09M/android-15-is-here.html" title="Android 1.5 is here!" /><author><name>Xavier Ducrohet</name><uri>http://www.blogger.com/profile/00361998914767345309</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="14283194986884703640" /></author><feedburner:origLink>http://android-developers.blogspot.com/2009/04/android-15-is-here.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0EER3k6cSp7ImA9WxJTFUQ.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-6435758355210914663</id><published>2009-04-24T12:00:00.000-07:00</published><updated>2009-04-24T12:00:06.719-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-24T12:00:06.719-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><category scheme="http://www.blogger.com/atom/ns#" term="OpenGL ES" /><title>Introducing GLSurfaceView</title><content type="html">&lt;p&gt;GLSurfaceView is a new API class in Android 1.5. GLSurfaceView makes OpenGL ES applications easier to write by:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Providing the glue code to connect OpenGL ES to the &lt;a href="http://developer.android.com/reference/android/view/View.html" title="View"&gt;View&lt;/a&gt; system.&lt;/li&gt;&lt;li&gt;Providing the glue code to make OpenGL ES work with the &lt;a href="http://developer.android.com/reference/android/app/Activity.html" title="Activity"&gt;Activity&lt;/a&gt; life-cycle.&lt;/li&gt;&lt;li&gt;Making it easy to choose an appropriate frame buffer pixel format.&lt;/li&gt;&lt;li&gt;Creating and managing a separate rendering thread to enable smooth animation.&lt;/li&gt;&lt;li&gt;Providing easy-to-use debugging tools for tracing OpenGL ES API calls and checking for errors.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;GLSurfaceView is a good base for building an application that uses OpenGL ES for part or all of its rendering. A 2D or 3D action game would be a good candidate, as would a 2D or 3D data visualization application such as &lt;a href="http://www.youtube.com/watch?v=4PRfVKzuUJ4&amp;amp;fmt=18" title="Google Maps StreetView"&gt;Google Maps StreetView&lt;/a&gt;.&lt;/p&gt;&lt;h3&gt;The Simplest GLSurfaceView Application&lt;/h3&gt;&lt;p&gt;Here's the source code to the simplest possible OpenGL ES application:&lt;/p&gt;&lt;pre&gt;package com.example.android.apis.graphics;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.app.Activity;
import android.opengl.GLSurfaceView;
import android.os.Bundle;

public class ClearActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mGLView = new GLSurfaceView(this);
        mGLView.setRenderer(new ClearRenderer());
        setContentView(mGLView);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mGLView.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mGLView.onResume();
    }

    private GLSurfaceView mGLView;
}

class ClearRenderer implements GLSurfaceView.Renderer {
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // Do nothing special.
    }

    public void onSurfaceChanged(GL10 gl, int w, int h) {
        gl.glViewport(0, 0, w, h);
    }

    public void onDrawFrame(GL10 gl) {
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    }
}&lt;/pre&gt;&lt;p&gt;This program doesn't do much: it clears the screen to black on every frame. But it is a complete OpenGL application, that correctly implements the Android activity life-cycle. It pauses rendering when the activity is paused, and resumes it when the activity is resumed. You could use this application as the basis for non-interactive demonstration programs. Just add more OpenGL calls to the ClearRenderer.onDrawFrame method. Notice that you don't even need to subclass the GLSurfaceView view.&lt;/p&gt;&lt;p&gt;Note that the GLSurfaceView.Renderer interface has three methods:&lt;/p&gt;&lt;p&gt;The onSurfaceCreated() method is called at the start of rendering, and whenever the OpenGL ES drawing context has to be recreated. (The drawing context is typically lost and recreated when the activity is paused and resumed.) OnSurfaceCreated() is a good place to create long-lived OpenGL resources like textures.&lt;/p&gt;&lt;p&gt;The onSurfaceChanged() method is called when the surface changes size. It's a good place to set your OpenGL viewport. You may also want to set your camera here, if it's a fixed camera that doesn't move around the scene.&lt;/p&gt;&lt;p&gt;The onDrawFrame() method is called every frame, and is responsible for drawing the scene. You would typically start by calling glClear to clear the framebuffer, followed by other OpenGL ES calls to draw the current scene.&lt;/p&gt;&lt;h3&gt;How about User Input?&lt;/h3&gt;&lt;p&gt;If you want an interactive application (like a game), you will typically subclass GLSurfaceView, because that's an easy way of obtaining input events. Here's a slightly longer example showing how to do that:&lt;/p&gt;&lt;pre&gt;package com.google.android.ClearTest;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.app.Activity;
import android.content.Context;
import android.opengl.GLSurfaceView;
import android.os.Bundle;
import android.view.MotionEvent;

public class ClearActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mGLView = new ClearGLSurfaceView(this);
        setContentView(mGLView);
    }

    @Override
    protected void onPause() {
        super.onPause();
        mGLView.onPause();
    }

    @Override
    protected void onResume() {
        super.onResume();
        mGLView.onResume();
    }

    private GLSurfaceView mGLView;
}

class ClearGLSurfaceView extends GLSurfaceView {
    public ClearGLSurfaceView(Context context) {
        super(context);
        mRenderer = new ClearRenderer();
        setRenderer(mRenderer);
    }

    public boolean onTouchEvent(final MotionEvent event) {
        queueEvent(new Runnable(){
            public void run() {
                mRenderer.setColor(event.getX() / getWidth(),
                        event.getY() / getHeight(), 1.0f);
            }});
            return true;
        }

        ClearRenderer mRenderer;
}

class ClearRenderer implements GLSurfaceView.Renderer {
    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
        // Do nothing special.
    }

    public void onSurfaceChanged(GL10 gl, int w, int h) {
        gl.glViewport(0, 0, w, h);
    }

    public void onDrawFrame(GL10 gl) {
        gl.glClearColor(mRed, mGreen, mBlue, 1.0f);
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
    }

    public void setColor(float r, float g, float b) {
        mRed = r;
        mGreen = g;
        mBlue = b;
    }

    private float mRed;
    private float mGreen;
    private float mBlue;
}&lt;/pre&gt;&lt;p&gt;This application clears the screen every frame. When you tap on the screen, it sets the clear color based on the (x,y) coordinates of your touch event. Note the use of &lt;code&gt;queueEvent()&lt;/code&gt; in &lt;code&gt;ClearGLSurfaceView.onTouchEvent()&lt;/code&gt;. The &lt;code&gt;queueEvent()&lt;/code&gt; method is used to safely communicate between the UI thread and the rendering thread. If you prefer you can use some other Java cross-thread communication technique, such as synchronized methods on the Renderer class itself. But queueing events is often the simplest way of dealing with cross-thread communication.&lt;/p&gt;&lt;h3&gt;Other GLSurfaceView Samples&lt;/h3&gt;&lt;p&gt;Tired of just clearing the screen? You can find more interesting samples in the API Demos sample in the SDK. All the OpenGL ES samples have been converted to use the GLSurfaceView view:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;GLSurfaceView - a spinning triangle&lt;/li&gt;&lt;li&gt;Kube - a cube puzzle demo&lt;/li&gt;&lt;li&gt;Translucent GLSurfaceView - shows how to display 3D graphics on a translucent background&lt;/li&gt;&lt;li&gt;Textured Triangle - shows how to draw a textured 3D triangle&lt;/li&gt;&lt;li&gt;Sprite Text - shows how to draw text into a texture and then composite it into a 3D scene&lt;/li&gt;&lt;li&gt;Touch Rotate - shows how to rotate a 3D object in response to user input.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Choosing a Surface&lt;/h3&gt;&lt;p&gt;GLSurfaceView helps you choose the type of surface to render to. Different Android devices support different types of surfaces, with no common subset. This makes it tricky problem to choose the best available surface on each device. By default GLSurfaceView tries to find a surface that's as close as possible to a 16-bit RGB frame buffer with a 16-bit depth buffer. Depending upon your application's needs you may want to change this behavior. For example, the Translucent GLSurfaceView sample needs an Alpha channel in order to render translucent data. GLSurfaceView provides an overloaded &lt;code&gt;setEGLSurfaceChooser()&lt;/code&gt; method to give the developer control over which surface type is chosen:&lt;/p&gt;&lt;dl&gt;&lt;dt&gt;&lt;code&gt;setEGLConfigChooser(boolean needDepth)&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;Choose a config that's closest to R5G6B5 with or without a 16-bit framebuffer&lt;/dd&gt;&lt;dt&gt;&lt;code&gt;setEGLConfigChooser(int redSize, int greenSize,int blueSize, int alphaSize,int depthSize, int stencilSize)&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;Choose the config with the fewest number of bits per pixel that has at least as many bits-per-channel as specified in the constructor.&lt;/dd&gt;&lt;dt&gt;&lt;code&gt;setEGLConfigChooser(EGLConfigChooser configChooser)&lt;/code&gt;&lt;/dt&gt;&lt;dd&gt;Allow total control over choosing a configuration. You pass in your own implementation of &lt;code&gt;EGLConfigChooser&lt;/code&gt;, which gets to inspect the device's capabilities and choose a configuration.&lt;/dd&gt;&lt;/dl&gt;&lt;h3&gt;Continuous Rendering vs. Render When Dirty&lt;/h3&gt;&lt;p&gt;Most 3D applications, such as games or simulations, are continuously animated. But some 3D applications are more reactive: they wait passively until the user does something, and then react to it. For those types of applications, the default GLSurfaceView behavior of continuously redrawing the screen is a waste of time. If you are developing a reactive application, you can call &lt;code&gt;GLSurfaceView.setRenderMode(RENDERMODE_WHEN_DIRTY)&lt;/code&gt;, which turns off the continuous animation. Then you call &lt;code&gt;GLSurfaceView.requestRender()&lt;/code&gt; whenever you want to re-render.&lt;/p&gt;&lt;h3&gt;Help With Debugging&lt;/h3&gt;&lt;p&gt;GLSurfaceView has a handy built-in feature for debugging OpenGL ES applications: the &lt;code&gt;GLSurfaceView.setDebugFlags()&lt;/code&gt; method can be used to enable logging and/or error checking your OpenGL ES calls. Call this method in your GLSurfaceView's constructor, before calling &lt;code&gt;setRenderer()&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;public ClearGLSurfaceView(Context context) {
    super(context);
    // Turn on error-checking and logging
    setDebugFlags(DEBUG_CHECK_GL_ERROR | DEBUG_LOG_GL_CALLS);
    mRenderer = new ClearRenderer();
    setRenderer(mRenderer);
}&lt;/pre&gt;&lt;hr style="align: center; width: 66%; border: none 0; border-top: 1px dashed #000;" /&gt;&lt;p&gt;&lt;em&gt;Learn about Android 1.5 and more at &lt;a href="http://code.google.com/events/io/"&gt;Google I/O&lt;/a&gt;. Members of the Android team will be there to give a series of &lt;a href="http://code.google.com/events/io/sessions.html#android"&gt;in-depth technical sessions&lt;/a&gt; and to field your toughest questions.&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-6435758355210914663?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=H26VlPh0Moo:hi1PvZ2-2bA:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=H26VlPh0Moo:hi1PvZ2-2bA:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=H26VlPh0Moo:hi1PvZ2-2bA:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/H26VlPh0Moo" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/6435758355210914663?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/6435758355210914663?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/H26VlPh0Moo/introducing-glsurfaceview.html" title="Introducing GLSurfaceView" /><author><name>Jack Palevich</name><uri>http://www.blogger.com/profile/03007259254321602946</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="06743467225177010350" /></author><feedburner:origLink>http://android-developers.blogspot.com/2009/04/introducing-glsurfaceview.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkEEQ3k5cSp7ImA9WxJTFUQ.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-8270401365504867796</id><published>2009-04-24T09:30:00.000-07:00</published><updated>2009-04-24T09:30:02.729-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-24T09:30:02.729-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="How-to" /><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><category scheme="http://www.blogger.com/atom/ns#" term="User Interface" /><title>Live folders</title><content type="html">&lt;p&gt;Live folders have been introduced in Android 1.5 and let you display any source of data on the Home screen without forcing the user to launch an application. A live folder is simply a real-time view of a &lt;a href="http://developer.android.com/reference/android/content/ContentProvider.html"&gt;ContentProvider&lt;/a&gt;. As such, a live folder can be used to display all your contacts, your bookmarks, your email, your playlists, an RSS feed, etc. The possibilities are endless! Android 1.5 ships with a few stock live folders to display your contacts. For instance, the screenshot below shows the content of the live folders that displays all my contacts with a phone number:&lt;/p&gt;&lt;p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://1.bp.blogspot.com/_9l0GmPwgCzk/SeAeChYUuII/AAAAAAAAADk/ZrYbwiYT1II/s400/contacts.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5323287788220889218" /&gt;&lt;/p&gt;&lt;p&gt;If a contacts sync happens in the background while I'm browsing this live folder, I will see the change happen in real-time. Live folders are not only useful but it's also very easy to modify your application to make it provider a live folder. In this article, I will show you how to add a live folder to the &lt;a href="http://code.google.com/p/shelves"&gt;Shelves&lt;/a&gt; application. You can download its source code and modify it by following my instructions to better understand how live folders work.&lt;/p&gt;&lt;p&gt;To give the user the option to create a new live folder, you first need to create a new activity with an intent filter who action is &lt;code&gt;android.intent.action.CREATE_LIVE_FOLDER&lt;/code&gt;. To do so, simply open &lt;code&gt;AndroidManifest.xml&lt;/code&gt; and add something similar to this:&lt;/p&gt;&lt;pre&gt;&amp;lt;activity
    android:name=".activity.BookShelfLiveFolder"
    android:label="BookShelf"&amp;gt;
    &amp;lt;intent-filter&amp;gt;
        &amp;lt;action android:name="android.intent.action.CREATE_LIVE_FOLDER" /&amp;gt;
        &amp;lt;category android:name="android.intent.category.DEFAULT" /&amp;gt;
    &amp;lt;/intent-filter&amp;gt;
&amp;lt;/activity&amp;gt;&lt;/pre&gt;&lt;p&gt;The label and icon of this activity are what the user will see on the Home screen when choosing a live folder to create:&lt;/p&gt;&lt;p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://1.bp.blogspot.com/_9l0GmPwgCzk/SeAfVu4IazI/AAAAAAAAADs/ZZYmkwOOYTk/s400/device.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5323289217773103922" /&gt;&lt;/p&gt;&lt;p&gt;Since you just need an intent filter, it is possible, and sometimes advised, to reuse an existing activity. In the case of Shelves, we will create a new activity, &lt;code&gt;org.curiouscreature.android.shelves.activity.BookShelfLiveFolder&lt;/code&gt;. The role of this activity is to send an &lt;code&gt;Intent&lt;/code&gt; result to Home containing the description of the live folder: its name, icon, display mode and content URI. The content URI is very important as it describes what &lt;code&gt;ContentProvider&lt;/code&gt; will be used to populate the live folder. The code of the activity is very simple as you can see here:&lt;/p&gt;&lt;pre&gt;public class BookShelfLiveFolder extends Activity {
    public static final Uri CONTENT_URI = Uri.parse("content://shelves/live_folders/books");

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        final Intent intent = getIntent();
        final String action = intent.getAction();

        if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) {
            setResult(RESULT_OK, createLiveFolder(this, CONTENT_URI,
                    "Books", R.drawable.ic_live_folder));
        } else {
            setResult(RESULT_CANCELED);
        }

        finish();
    }

    private static Intent createLiveFolder(Context context, Uri uri, String name, int icon) {
        final Intent intent = new Intent();

        intent.setData(uri);
        intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, name);
        intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON,
                Intent.ShortcutIconResource.fromContext(context, icon));
        intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE, LiveFolders.DISPLAY_MODE_LIST);

        return intent;
    }
}&lt;/pre&gt;&lt;p&gt;This activity, when invoked with the&lt;code&gt;ACTION_CREATE_LIVE_FOLDER&lt;/code&gt; intent, returns an intent with a URI, &lt;code&gt;content://shelves/live_folders/books&lt;/code&gt;, and three extras to describe the live folder. There are other extras and constants you can use and you should refer to the documentation of &lt;code&gt;android.provider.LiveFolders&lt;/code&gt; for more details. When Home receives this intent, a new live folder is created on the user's desktop, with the name and icon you provided. Then, when the user clicks on the live folder to open it, Home queries the content provider referenced by the provided URI.&lt;/p&gt;&lt;p&gt;Live folders' content providers must obey specific naming rules. The &lt;code&gt;Cursor&lt;/code&gt; returned by the &lt;code&gt;query()&lt;/code&gt; method must have at least two columns named &lt;code&gt;LiveFolders._ID&lt;/code&gt; and &lt;code&gt;LiveFolders.NAME&lt;/code&gt;. The first one is the unique identifier of each item in the live folder and the second one is the name of the item. There are other column names you can use to specify an icon, a description, the intent to associate with the item (fired when the user clicks that item), etc. Again, refer to the documentation of &lt;code&gt;android.provider.LiveFolders&lt;/code&gt; for more details.&lt;/p&gt;&lt;p&gt;In our example, all we need to do is modify the existing provider in Shelves called &lt;code&gt;org.curiouscreature.android.shelves.provider.BooksProvider&lt;/code&gt;. First, we need to modify the &lt;code&gt;URI_MATCHER&lt;/code&gt; to recognize our &lt;code&gt;content://shelves/live_folders/books&lt;/code&gt; content URI:&lt;/p&gt;&lt;pre&gt;private static final int LIVE_FOLDER_BOOKS = 4;
// ...
URI_MATCHER.addURI(AUTHORITY, "live_folders/books", LIVE_FOLDER_BOOKS);&lt;/pre&gt;&lt;p&gt;Then we need to create a new projection map for the cursor. A projection map can be used to "rename" columns. In our case, we will replace &lt;code&gt;BooksStore.Book._ID&lt;/code&gt;, &lt;code&gt;BooksStore.Book.TITLE&lt;/code&gt; and &lt;code&gt;BooksStore.Book.AUTHORS&lt;/code&gt; with &lt;code&gt;LiveFolders._ID&lt;/code&gt;, &lt;code&gt;LiveFolders.TITLE&lt;/code&gt; and &lt;code&gt;LiveFolders.DESCRIPTION&lt;/code&gt;:&lt;/p&gt;&lt;pre&gt;private static final HashMap&lt;String, String&gt; LIVE_FOLDER_PROJECTION_MAP;
static {
    LIVE_FOLDER_PROJECTION_MAP = new HashMap&lt;String, String&gt;();
    LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders._ID, BooksStore.Book._ID +
            " AS " + LiveFolders._ID);
    LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.NAME, BooksStore.Book.TITLE +
            " AS " + LiveFolders.NAME);
    LIVE_FOLDER_PROJECTION_MAP.put(LiveFolders.DESCRIPTION, BooksStore.Book.AUTHORS +
            " AS " + LiveFolders.DESCRIPTION);
}&lt;/pre&gt;&lt;p&gt;Because we are providing a title and a description for each row, Home will automatically display each item of the live folder with two lines of text. Finally, we implement the &lt;code&gt;query()&lt;/code&gt; method by supplying our projection map to the SQL query builder:&lt;/p&gt;&lt;pre&gt;public Cursor query(Uri uri, String[] projection, String selection,
        String[] selectionArgs, String sortOrder) {

    SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

    switch (URI_MATCHER.match(uri)) {
        // ...
        case LIVE_FOLDER_BOOKS:
            qb.setTables("books");
            qb.setProjectionMap(LIVE_FOLDER_PROJECTION_MAP);
            break;
        default:
            throw new IllegalArgumentException("Unknown URI " + uri);
    }

    SQLiteDatabase db = mOpenHelper.getReadableDatabase();
    Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, BooksStore.Book.DEFAULT_SORT_ORDER);
    c.setNotificationUri(getContext().getContentResolver(), uri);

    return c;
}&lt;/pre&gt;&lt;p&gt;You can now compile and deploy the application, go to the Home screen and try to add a live folder. I added a books live folder to my Home screen and when I open it, I can see the list of all of my books, with their titles and authors, and all it took was a few lines of code:&lt;/p&gt;&lt;p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 267px; height: 400px;" src="http://2.bp.blogspot.com/_9l0GmPwgCzk/SeAjRo5pECI/AAAAAAAAAD0/zfgdXMfQ2LE/s400/device.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5323293545495859234" /&gt;&lt;/p&gt;&lt;p&gt;The live folders API is extremely simple and relies only on intents and content URI. If you want to see more examples of live folders implementation, you can read the source code of the &lt;a href="http://android.git.kernel.org/?p=platform/packages/apps/Contacts.git;a=tree;h=refs/heads/cupcake;hb=cupcake"&gt;Contacts application&lt;/a&gt; and of the &lt;a href="http://android.git.kernel.org/?p=platform/packages/providers/ContactsProvider.git;a=tree;h=refs/heads/cupcake;hb=cupcake"&gt;Contacts provider&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;You can also download the result of our exercise, the &lt;a href="http://jext.free.fr/CupcakeShelves.zip"&gt;modified version of Shelves with live folders support&lt;/a&gt;.&lt;/p&gt;&lt;hr style="align: center; width: 66%; border: none 0; border-top: 1px dashed #000;" /&gt;&lt;p&gt;&lt;em&gt;Learn about Android 1.5 and more at &lt;a href="http://code.google.com/events/io/"&gt;Google I/O&lt;/a&gt;. Members of the Android team will be there to give a series of &lt;a href="http://code.google.com/events/io/sessions.html#android"&gt;in-depth technical sessions&lt;/a&gt; and to field your toughest questions.&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-8270401365504867796?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=hUy4VFeBBak:uCfeAM-x7Gk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=hUy4VFeBBak:uCfeAM-x7Gk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=hUy4VFeBBak:uCfeAM-x7Gk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/hUy4VFeBBak" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/8270401365504867796?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/8270401365504867796?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/hUy4VFeBBak/live-folders.html" title="Live folders" /><author><name>Romain Guy</name><uri>http://www.blogger.com/profile/14359137835485363401</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11053364165382206530" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_9l0GmPwgCzk/SeAeChYUuII/AAAAAAAAADk/ZrYbwiYT1II/s72-c/contacts.png" height="72" width="72" /><feedburner:origLink>http://android-developers.blogspot.com/2009/04/live-folders.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkEBSH46fip7ImA9WxJTGEk.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-6443372341951283483</id><published>2009-04-23T09:15:00.000-07:00</published><updated>2009-04-27T09:10:59.016-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-27T09:10:59.016-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="How-to" /><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><title>Future-Proofing Your Apps</title><content type="html">&lt;p&gt;Hi, developers!  I hope you've heard about the &lt;a href="http://android-developers.blogspot.com/2009/04/getting-ready-for-android-15.html"&gt;early-look version of the Android 1.5 SDK&lt;/a&gt; that we recently released.  There are some great new features in there, but don't get too excited yet -- some of you will need to fix some problems in your apps before you can start taking advantage of Android 1.5.&lt;/p&gt;&lt;p&gt;We've done some fairly extensive testing of the popular apps on the Android Market, and it turns out that a few of those apps use some bad techniques that cause them to crash or behave strangely on Android 1.5. The list below is based on our observations of five ways that we've seen bad apps fail on 1.5. You can think of these as "anti-patterns" (that is, techniques to avoid) for Android development. If you've written an app with the Android 1.0 or 1.1 SDKs, you'll need to pay close attention.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Technique to Avoid, #1: Using Internal APIs&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Even though we've always strongly advised against doing so, some developers have chosen to use unsupported or internal APIs. For instance, many developers are using the internal brightness control and bluetooth toggle APIs that were present in 1.0 and 1.1. A bug -- which is now fixed in Android 1.5 -- allowed apps to use those APIs without requesting permission. As a result, apps that use those APIs will break on 1.5. There are other changes to unsupported APIs in 1.5 besides these, so if you've used internal APIs in your apps, you need to update your apps to stop doing so. Even if they don't break on Android 1.5, there's a good chance they will on some later version. (There's some good news, though: because "flashlight" apps are so popular, we've added the "screenBrightness" field on the WindowManager.LayoutParams class just for that use case.)&lt;/p&gt;&lt;p&gt;&lt;b&gt;Technique to Avoid, #2: Directly Manipulating Settings&lt;/b&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Okay, strictly speaking this one isn't evil, since this is a change in behavior that we made to Android itself. But we made it because some developers were doing naughty things: a number of apps were changing system settings silently without even notifying the user. For instance, some apps turn on GPS without asking the user, and others might turn on data roaming.&lt;/p&gt;&lt;p&gt;As a result, applications can no longer directly manipulate the values of certain system Settings, even if they previously had permission to do so. For instance, apps can no longer directly turn on or off GPS. These apps won't crash, but the APIs in question now have no effect, and do nothing. Instead, apps will need to issue an Intent to launch the appropriate Settings configuration screen, so that the user can change these settings manually. For details, see the android.provider.Settings.Secure class, which you can find in the 1.5_pre SDK documentation (and later). Note that only Settings that were moved to the Settings.Secure class are affected. Other, less sensitive, settings will continue to have the same behavior as in Android 1.1.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Technique to Avoid, #3: Going Overboard with Layouts&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Due to changes in the View rendering infrastructure, unreasonably deep (more than 10 or so) or broad (more than 30 total) View hierarchies in layouts are now likely to cause crashes.  This was always a risk for excessively complex layouts, but you can think of Android 1.5 as being better than 1.1 at exposing this problem. Most developers won't need to worry about this, but if your app has very complicated layouts, you'll need to put it on a diet. You can simplify your layouts using the more advanced layout classes like FrameLayout and TableLayout.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Technique to Avoid, #4: Bad Hardware Assumptions&lt;/b&gt;&lt;/p&gt;&lt;p&gt;Android 1.5 includes support for soft keyboards, and there will soon be many devices that run Android but do not have physical keyboards. If your application assumes the presence of a physical keyboard (such as if you have created a custom View that sinks keypress events) you should make sure it degrades gracefully on devices that only have soft keyboards. For more information on this, keep on eye on this blog as we'll be posting more detailed information about handling the new soft keyboards.&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;b&gt;Technique to Avoid, #5: Incautious Rotations &lt;/b&gt;&lt;/p&gt;&lt;p&gt;Devices running Android 1.5 and later can automatically rotate the screen, depending on how the user orients the device. Some 1.5 devices will do this by default, and on all others it can be turned on by the user. This can sometimes result in unpredictable behavior from applications that do their own reorientations (whether using the accelerometer, or something else.) This often happens when applications assume that the screen can only rotate if the physical keyboard is exposed; if the device lacks a physical keyboard, these apps do not expect to be reoriented, which is a coding error. Developers should be sure that their applications can gracefully handle being reoriented at any time.&lt;/p&gt;&lt;p&gt;Also, apps that use the accelerometer directly to reorient themselves sometimes compete with the system doing the same thing, with odd results. And finally, some apps that use the accelerometer to detect things like shaking motions and that don't lock their orientation to portrait or landscape, often end up flipping back and forth between orientations. This can be irritating to the user. (You can lock your app's orientation to portrait or landscape using the 'android:screenOrientation' attribute in your AndroidManifest.xml.)&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;Have any of &lt;i&gt;your&lt;/i&gt; apps used one of these dubious techniques? If so, break out your IDE, duct tape, and spackle, and patch 'em up. I'm pretty excited by the new features in the Android 1.5 SDK, and I look forward to seeing your apps on my own 1.5-equipped phone -- but I can't, if they won't run! Fortunately, the fixes for these are pretty simple, and you can start fixing all of the above even with the 1.1_r1 SDK release.&lt;/p&gt;&lt;p&gt;By the way, if you'd like to fully immerse yourself in Android 1.5, join us at &lt;a title="Google I/O" href="http://code.google.com/io" id="vmp1"&gt;Google I/O&lt;/a&gt;! It's my pleasure to shamelessly plug an event that's shaping up to be the Android developer event of the year. We've added two more &lt;a id="krvc" href="http://code.google.com/events/io/sessions.html#android" title="sessions"&gt;sessions&lt;/a&gt;—one on multimedia jujitsu, and a particularly interesting session on the Eyes-Free Android project—with even more yet to come. I thought Google I/O was a pretty killer event last year, and this year's looking even better, especially in terms of Android content.&lt;/p&gt;&lt;p&gt;I hope to meet many of you there, but either way, Happy Coding!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-6443372341951283483?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=n4_FXGmodnk:V28bkLcdICo:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=n4_FXGmodnk:V28bkLcdICo:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=n4_FXGmodnk:V28bkLcdICo:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/n4_FXGmodnk" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/6443372341951283483?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/6443372341951283483?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/n4_FXGmodnk/future-proofing-your-apps.html" title="Future-Proofing Your Apps" /><author><name>Dan Morrill</name><uri>http://www.blogger.com/profile/12526265248010766454</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="17206489683788395259" /></author><feedburner:origLink>http://android-developers.blogspot.com/2009/04/future-proofing-your-apps.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0AAQnk6fSp7ImA9WxJTFUU.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-131748225826176146</id><published>2009-04-22T17:00:00.000-07:00</published><updated>2009-04-24T09:15:43.715-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-24T09:15:43.715-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="How-to" /><category scheme="http://www.blogger.com/atom/ns#" term="Input methods" /><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><title>Creating an Input Method</title><content type="html">&lt;p&gt;To create an input method (IME) for entering text into text fields and other Views, you need to extend &lt;code&gt;android.inputmethodservice.InputMethodService&lt;/code&gt;. This API provides much of the basic implementation for an input method, in terms of managing the state and visibility of the input method and communicating with the currently visible activity.&lt;/p&gt;&lt;p&gt;A good starting point would be the SoftKeyboard sample code provided as part of the SDK. Modify this code to start building your own input method.&lt;/p&gt;&lt;p&gt;An input method is packaged like any other application or service. In the &lt;code&gt;AndroidManifest.xml&lt;/code&gt; file, you declare the input method as a service, with the appropriate intent filter and any associated meta data:&lt;/p&gt;&lt;pre&gt;&amp;lt;manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.fastinput"&amp;gt;

    &amp;lt;application android:label="@string/app_label"&amp;gt;&lt;br&gt;
        &amp;lt;!-- Declares the input method service --&amp;gt;
        &amp;lt;service android:name="FastInputIME"
            android:label="@string/fast_input_label"
            android:permission="android.permission.BIND_INPUT_METHOD"&amp;gt;
            &amp;lt;intent-filter&amp;gt;
                &amp;lt;action android:name="android.view.InputMethod" /&amp;gt;
            &amp;lt;/intent-filter&amp;gt;
            &amp;lt;meta-data android:name="android.view.im" android:resource="@xml/method" /&amp;gt;
        &amp;lt;/service&amp;gt;

        &amp;lt;!-- Optional activities. A good idea to have some user settings. --&amp;gt;
        &amp;lt;activity android:name="FastInputIMESettings" android:label="@string/fast_input_settings"&amp;gt;
            &amp;lt;intent-filter&amp;gt;
                &amp;lt;action android:name="android.intent.action.MAIN"/&amp;gt;
            &amp;lt;/intent-filter&amp;gt;
        &amp;lt;/activity&amp;gt; 
    &amp;lt;/application&amp;gt;
&amp;lt;/manifest&amp;gt;&lt;/pre&gt;&lt;p&gt;If your input method allows the user to tweak some settings, you should provide a settings activity that can be launched from the Settings application. This is optional and you may choose to provide all user settings directly in your IME's UI.&lt;/p&gt;&lt;p&gt;The typical life-cycle of an &lt;code&gt;InputMethodService&lt;/code&gt; looks like this:&lt;/p&gt;&lt;p&gt;&lt;img src="https://docs.google.com/a/google.com/File?id=ad9xdxhtb4_043qn7phd_b" style="width: 374px; height: 871px; border: none;"&gt;&lt;/p&gt;&lt;h3&gt;Visual Elements&lt;/h3&gt;&lt;p&gt;There are 2 main visual elements for an input method—the input view and the candidates view. You don't have to follow this style though, if one of them is not relevant to your input method experience.&lt;/p&gt;&lt;h4&gt;Input View&lt;/h4&gt;&lt;p&gt;This is where the user can input text either in the form of keypresses, handwriting or other gestures. When the input method is displayed for the first time, &lt;code&gt;InputMethodService.onCreateInputView()&lt;/code&gt; will be called. Create and return the view hierarchy that you would like to display in the input method window.&lt;/p&gt;&lt;h4&gt;Candidates View&lt;/h4&gt;&lt;p&gt;This is where potential word corrections or completions are presented to the user for selection. Again, this may or may not be relevant to your input method and you can return &lt;code&gt;null&lt;/code&gt; from calls to &lt;code&gt;InputMethodService.onCreateCandidatesView()&lt;/code&gt;, which is the default behavior.&lt;/p&gt;&lt;h3&gt;Designing for the different Input Types&lt;/h3&gt;&lt;p&gt;An application's text fields can have different input types specified on them, such as free form text, numeric, URL, email address and search. When you implement a new input method, you need to be aware of the different input types. Input methods are not automatically switched for different input types and so you need to support all types in your IME. However, the IME is not responsible for validating the input sent to the application. That's the responsibility of the application.&lt;/p&gt;&lt;p&gt;For example, the LatinIME provided with the Android platform provides different layouts for text and phone number entry:&lt;/p&gt;&lt;p&gt;&lt;img style="width: 319px; height: 198px; margin: 0 10px 0 0;" src="https://docs.google.com/a/google.com/File?id=ddvqp2ns_18g2nm5jhb_b"&gt;&lt;img style="width: 320px; height: 199px" src="https://docs.google.com/a/google.com/File?id=ddvqp2ns_17crk39fd9_b"&gt;&lt;/p&gt;&lt;p&gt;&lt;code&gt;InputMethodService.onStartInputView()&lt;/code&gt; is called with an&lt;code&gt; EditorInfo&lt;/code&gt; object that contains details about the input type and other attributes of the application's text field.&lt;/p&gt;&lt;p&gt;(&lt;code&gt;EditorInfo.inputType &amp;amp; EditorInfo.TYPE_CLASS_MASK&lt;/code&gt;) can be one of many different values, including:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;TYPE_CLASS_NUMBER&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;TYPE_CLASS_DATETIME&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;TYPE_CLASS_PHONE&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;TYPE_CLASS_TEXT&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;See &lt;code&gt;android.text.InputType&lt;/code&gt; for more details.&lt;/p&gt;&lt;p&gt;&lt;code&gt;EditorInfo.inputType&lt;/code&gt; can contain other masked bits that indicate the class variation and other flags. For example, &lt;code&gt;TYPE_TEXT_VARIATION_PASSWORD&lt;/code&gt; or &lt;code&gt;TYPE_TEXT_VARIATION_URI&lt;/code&gt; or &lt;code&gt;TYPE_TEXT_FLAG_AUTO_COMPLETE&lt;/code&gt;.&lt;/p&gt;&lt;h4&gt;Password fields&lt;/h4&gt;&lt;p&gt;Pay specific attention when sending text to password fields. Make sure that the password is not visible within your UI - in neither the input view nor the candidates view. And do not save the password anywhere without explicitly informing the user.&lt;/p&gt;&lt;h3&gt;Landscape vs. portrait&lt;/h3&gt;&lt;p&gt;The UI needs to be able to scale between landscape and portrait orientations. In non-fullscreen IME mode, leave sufficient space for the application to show the text field and any associated context. Preferably, no more than half the screen should be occupied by the IME. In fullscreen IME mode this is not an issue.&lt;/p&gt;&lt;h3&gt;Sending text to the application&lt;/h3&gt;&lt;p&gt;There are two ways to send text to the application. You can either send individual key events or you can edit the text around the cursor in the application's text field.&lt;/p&gt;&lt;p&gt;To send a key event, you can simply construct KeyEvent objects and call InputConnection.sendKeyEvent(). Here are some examples:&lt;/p&gt;&lt;pre&gt;InputConnection ic = getCurrentInputConnection();
long eventTime = SystemClock.uptimeMillis();
ic.sendKeyEvent(new KeyEvent(eventTime, eventTime,
    KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, 0, 0,
    KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));
ic.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime,
    KeyEvent.ACTION_UP, keyEventCode, 0, 0, 0, 0,
    KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE));&lt;/pre&gt;&lt;p&gt;Or use the convenience method:&lt;/p&gt;&lt;pre&gt;InputMethodService.sendDownUpKeyEvents(keyEventCode);&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: It is recommended to use the above method for certain fields such as phone number fields because of filters that may be applied to the text after each key press. Return key and delete key should also be sent as raw key events for certain input types, as applications may be watching for specific key events in order to perform an action.&lt;/p&gt;&lt;p&gt;When editing text in a text field, some of the more useful methods on &lt;code&gt;android.view.inputmethod.InputConnection&lt;/code&gt; are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;getTextBeforeCursor()&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;getTextAfterCursor()&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;deleteSurroundingText()&lt;/code&gt;&lt;/li&gt;&lt;li&gt;&lt;code&gt;commitText()&lt;/code&gt;&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;For example, let's say the text "Fell" is to the left of the cursor. And you want to replace it with "Hello!":&lt;/p&gt;&lt;pre&gt;InputConnection ic = getCurrentInputConnection();
ic.deleteSurroundingText(4, 0);
ic.commitText("Hello", 1);
ic.commitText("!", 1);&lt;/pre&gt;&lt;h4&gt;Composing text before committing&lt;/h4&gt;&lt;p&gt;If your input method does some kind of text prediction or requires multiple steps to compose a word or glyph, you can show the progress in the text field until the user commits the word and then you can replace the partial composition with the completed text. The text that is being composed will be highlighted in the text field in some fashion, such as an underline.&lt;/p&gt;&lt;pre&gt;InputConnection ic = getCurrentInputConnection();
ic.setComposingText("Composi", 1);
...
ic.setComposingText("Composin", 1);
...
ic.commitText("Composing ", 1);&lt;/pre&gt;&lt;p&gt;&lt;img style="width: 320px; height: 98px; margin-bottom: 10px" src="https://docs.google.com/a/google.com/File?id=ddvqp2ns_0g2z84dg2_b"&gt;&lt;img style="width: 320px; height: 97px; margin-bottom: 10px" src="https://docs.google.com/a/google.com/File?id=ddvqp2ns_1jnw696d3_b"&gt;&lt;img style="width: 320px; height: 97px;" src="https://docs.google.com/a/google.com/File?id=ddvqp2ns_2crrwtbf7_b"&gt;&lt;/p&gt;&lt;h3&gt;Intercepting hard key events&lt;/h3&gt;&lt;p&gt;Even though the input method window doesn't have explicit focus, it receives hard key events first and can choose to consume them or forward them along to the application. For instance, you may want to consume the directional keys to navigate within your UI for candidate selection during composition. Or you may want to trap the back key to dismiss any popups originating from the input method window. To intercept hard keys, override &lt;code&gt;InputMethodService.onKeyDown()&lt;/code&gt; and &lt;code&gt;InputMethodService.onKeyUp().&lt;/code&gt; Remember to call &lt;code&gt;super.onKey&lt;/code&gt;* if you don't want to consume a certain key yourself.&lt;/p&gt;&lt;h3&gt;Other considerations&lt;/h3&gt;&lt;ul&gt;&lt;li&gt;Provide a way for the user to easily bring up any associated settings directly from the input method UI&lt;/li&gt;&lt;li&gt;Provide a way for the user to switch to a different input method (multiple input methods may be installed) directly from the input method UI.&lt;/li&gt;&lt;li&gt;Bring up the UI quickly - preload or lazy-load any large resources so that the user sees the input method quickly on tapping on a text field. And cache any resources and views for subsequent invocations of the input method.&lt;/li&gt;&lt;li&gt;On the flip side, any large memory allocations should be released soon after the input method window is hidden so that applications can have sufficient memory to run. Consider using a delayed message to release resources if the input method is in a hidden state for a few seconds.&lt;/li&gt;&lt;li&gt;Make sure that most common characters can be entered using the input method, as users may use punctuation in passwords or user names and they shouldn't be stuck in a situation where they can't enter a certain character in order to gain access into a password-locked device.&lt;/li&gt;&lt;/ul&gt;&lt;h3&gt;Samples&lt;/h3&gt;&lt;p&gt;For a real world example, with support for multiple input types and text prediction, see the &lt;a id="ccpb" href="http://android.git.kernel.org/?p=platform/packages/inputmethods/LatinIME.git;a=tree" title="LatinIME source code online"&gt;LatinIME source code&lt;/a&gt;. The Android 1.5 SDK also includes a SoftKeyboard sample as well.&lt;/p&gt;&lt;hr style="align: center; width: 66%; border: none 0; border-top: 1px dashed #000;" /&gt;&lt;p&gt;&lt;em&gt;Learn about Android 1.5 and more at &lt;a href="http://code.google.com/events/io/"&gt;Google I/O&lt;/a&gt;. Members of the Android team will be there to give a series of &lt;a href="http://code.google.com/events/io/sessions.html#android"&gt;in-depth technical sessions&lt;/a&gt; and to field your toughest questions.&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-131748225826176146?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=mxJ5gA619Ls:Gecjq4j1LnQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=mxJ5gA619Ls:Gecjq4j1LnQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=mxJ5gA619Ls:Gecjq4j1LnQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/mxJ5gA619Ls" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/131748225826176146?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/131748225826176146?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/mxJ5gA619Ls/creating-input-method.html" title="Creating an Input Method" /><author><name>Amith Yamasani</name><uri>http://www.blogger.com/profile/17365517215904306398</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="10858805196650211411" /></author><feedburner:origLink>http://android-developers.blogspot.com/2009/04/creating-input-method.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ck4EQn04eCp7ImA9WxJTFEk.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-6719288588971680640</id><published>2009-04-21T21:10:00.000-07:00</published><updated>2009-04-22T15:55:03.330-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-22T15:55:03.330-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="How-to" /><category scheme="http://www.blogger.com/atom/ns#" term="Input methods" /><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><category scheme="http://www.blogger.com/atom/ns#" term="User Interface" /><title>Updating Applications for On-screen Input Methods</title><content type="html">&lt;p&gt;One of the major new features we are introducing in Android 1.5 is our Input Method Framework (IMF), which allows developers on-screen input methods such as software keyboards.  This article will provide an overview of what Android input method editors (IMEs) are, and what an application developer needs to do to work well with them.  The IMF allows for a new class of Android devices, such as those without a hardware keyboard, so it is important that your application work well with it to provide the users of such devices a great experience.&lt;/p&gt;&lt;h3&gt;What is an input method?&lt;/h3&gt;&lt;p&gt;The Android IMF is designed to support a variety of IMEs, including soft keyboard, hand-writing recognizers, and hard keyboard translators.  Our focus, however, will be on soft keyboards, since this is the kind of input method that is currently part of the platform.&lt;/p&gt;&lt;p&gt;A user will usually access the current IME by tapping on a text view to edit, as shown here in the home screen:&lt;/p&gt;&lt;p&gt;&lt;img style="width: 320px; height: 480px; margin-right:10px;" src="https://docs.google.com/a/google.com/File?id=afzfgn3h3x_5cmzpb6n2_b"&gt;&lt;img style="width: 320px; height: 480px;" src="https://docs.google.com/a/google.com/File?id=afzfgn3h3x_6d8h4c2cb_b"&gt;&lt;/p&gt;&lt;p&gt;The soft keyboard is positioned at the bottom of the screen over the application's window.  To organize the available space between the application and IME, we use a few approaches; the one shown here is called &lt;em&gt;pan and scan&lt;/em&gt;, and simply involves scrolling the application window around so that the currently focused view is visible.  This is the default mode, since it is the safest for existing applications.&lt;/p&gt;&lt;p&gt;Most often the preferred screen layout is a &lt;em&gt;resize&lt;/em&gt;, where the application's window is resized to be entirely visible.  An example is shown here, when composing an e-mail message:&lt;/p&gt;&lt;p&gt;&lt;img style="width: 320px; height: 480px; margin-right: 10px;" src="https://docs.google.com/a/google.com/File?id=afzfgn3h3x_3zgvm8kcw_b"&gt;&lt;img style="width: 320px; height: 480px;" src="https://docs.google.com/a/google.com/File?id=afzfgn3h3x_4d9d4ktc9_b"&gt;&lt;/p&gt;&lt;p&gt;The size of the application window is changed so that none of it is hidden by the IME, allowing full access to both the application and IME.  This of course only works for applications that have a resizeable area that can be reduced to make enough space, but the vertical space in this mode is actually no less than what is available in landscape orientation, so very often an application can already accommodate it.&lt;/p&gt;&lt;p&gt;The final major mode is &lt;em&gt;fullscreen&lt;/em&gt; or &lt;em&gt;extract&lt;/em&gt; mode.  This is used when the IME is too large to reasonably share space with the underlying application.  With the standard IMEs, you will only encounter this situation when the screen is in a landscape orientation, although other IMEs are free to use it whenever they desire.  In this case the application window is left as-is, and the IME simply displays fullscreen on top of it, as shown here:&lt;/p&gt;&lt;p&gt;&lt;img style="width: 480px; height: 320px; margin-right:10px; margin-bottom:10px" src="https://docs.google.com/a/google.com/File?id=afzfgn3h3x_9cbwkp5gb_b"&gt;&lt;img style="width: 480px; height: 320px;" src="https://docs.google.com/a/google.com/File?id=afzfgn3h3x_10dwd35pv4_b"&gt;&lt;/p&gt;&lt;p&gt;Because the IME is covering the application, it has its own editing area, which shows the text actually contained in the application.  There are also some limited opportunities the application has to customize parts of the IME (the "done" button at the top and enter key label at the bottom) to improve the user experience.&lt;/p&gt;&lt;h3&gt;Basic XML attributes for controlling IMEs&lt;/h3&gt;&lt;p&gt;There are a number of things the system does to try to help existing applications work with IMEs as well as possible, such as:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Use pan and scan mode by default, unless it can reasonably guess that resize mode will work by the existence of lists, scroll views, etc.&lt;/li&gt;&lt;li&gt;Analyze the various existing TextView attributes to guess at the kind of content (numbers, plain text, etc) to help the soft keyboard display an appropriate key layout.&lt;/li&gt;&lt;li&gt;Assign a few default actions to the fullscreen IME, such as "next field" and "done".&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;There are also some simple things you can do in your application that will often greatly improve its user experience.  Note that, except where explicitly mentioned, all of the things suggested here will not tie your application to Android 1.5 -- it will still work on older releases, which will simply ignore these new options.&lt;/p&gt;&lt;h4&gt;Specifying each EditText control's input type&lt;/h4&gt;&lt;p&gt;The most important thing for an application to do is use the new &lt;code&gt;android:inputType&lt;/code&gt; attribute on each EditText, which provides much richer information about the text content.  This attribute actually replaces many existing attributes (&lt;code&gt;android:&lt;/code&gt;&lt;code&gt;password&lt;/code&gt;, &lt;code&gt;android:&lt;/code&gt;&lt;code&gt;singleLine&lt;/code&gt;, &lt;code&gt;android:&lt;/code&gt;&lt;code&gt;numeric&lt;/code&gt;, &lt;code&gt;android:&lt;/code&gt;&lt;code&gt;phoneNumber&lt;/code&gt;, &lt;code&gt;android:&lt;/code&gt;&lt;code&gt;capitalize&lt;/code&gt;, &lt;code&gt;android:&lt;/code&gt;&lt;code&gt;autoText&lt;/code&gt;, &lt;code&gt;android:&lt;/code&gt;&lt;code&gt;editable&lt;/code&gt;); if you specify both, Cupcake devices will use the new &lt;code&gt;android:&lt;/code&gt;&lt;code&gt;inputType&lt;/code&gt; attribute and ignore the others.&lt;/p&gt;&lt;p&gt;The input type attribute has three pieces:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The &lt;em&gt;class&lt;/em&gt; is the overall interpretation of characters.  The currently supported classes are &lt;code&gt;text&lt;/code&gt; (plain text), &lt;code&gt;number&lt;/code&gt; (decimal number), &lt;code&gt;phone&lt;/code&gt; (phone number), and &lt;code&gt;datetime&lt;/code&gt; (a date or time).&lt;/li&gt;&lt;li&gt;The &lt;em&gt;variation&lt;/em&gt; is a further refinement on the class.  In the attribute you will normally specify the class and variant together, with the class as a prefix.  For example, &lt;code&gt;textEmailAddress&lt;/code&gt; is a text field where the user will enter something that is an e-mail address (foo@bar.com) so the key layout will have an '@' character in easy access, and &lt;code&gt;numberSigned&lt;/code&gt; is a numeric field with a sign.  If only the class is specified, then you get the default/generic variant.&lt;/li&gt;&lt;li&gt;Additional &lt;em&gt;flags&lt;/em&gt; can be specified that supply further refinement.  These flags are specific to a class.  For example, some flags for the &lt;code&gt;text&lt;/code&gt; class are &lt;code&gt;textCapSentences&lt;/code&gt;, &lt;code&gt;textAutoCorrect&lt;/code&gt;, and &lt;code&gt;textMultiline&lt;/code&gt;.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;As an example, here is the new EditText for the IM application's message text view:&lt;/p&gt;&lt;pre&gt;    &amp;lt;EditText android:id="@+id/edtInput"
        android:layout_width="0dip"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:inputType="textShortMessage|textAutoCorrect|textCapSentences|textMultiLine"
        android:imeOptions="actionSend|flagNoEnterAction"
        android:maxLines="4"
        android:maxLength="2000"
        android:hint="@string/compose_hint"/&amp;gt;&lt;/pre&gt;&lt;p&gt;A full description of all of the input types can be found in the documentation.  It is important to make use of the correct input types that are available, so that the soft keyboard can use the optimal keyboard layout for the text the user will be entering.&lt;/p&gt;&lt;h4&gt;Enabling resize mode and other window features&lt;/h4&gt;&lt;p&gt;The next most important thing for you to do is specify the overall behavior of your window in relation to the input method.  The most visible aspect of this is controlling resize vs. pan and scan mode, but there are other things you can do as well to improve your user experience.&lt;/p&gt;&lt;p&gt;You will usually control this behavior through the &lt;code&gt;android:windowSoftInputMode&lt;/code&gt; attribute on each &lt;code&gt;&amp;lt;activity&amp;gt;&lt;/code&gt; definition in your &lt;code&gt;AndroidManifest.xml&lt;/code&gt;.  Like the input type, there are a couple different pieces of data that can be specified here by combining them together:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The window adjustment mode is specified with either &lt;code&gt;adjustResize&lt;/code&gt; or &lt;code&gt;adjustPan&lt;/code&gt;.  It is highly recommended that you always specify one or the other.&lt;/li&gt;&lt;li&gt;You can further control whether the IME will be shown automatically when your activity is displayed and other situations where the user moves to it.  The system won't automatically show an IME by default, but in some cases it can be convenient for the user if an application enables this behavior.  You can request this with &lt;code&gt;stateVisible&lt;/code&gt;.  There are also a number of other state options for finer-grained control that you can find in the documentation.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;A typical example of this field can be see in the edit contact activity, which ensures it is resized and automatically displays the IME for the user:&lt;/p&gt;&lt;pre&gt;    &amp;lt;activity name="EditContactActivity"
        android:windowSoftInputMode="stateVisible|adjustResize"&amp;gt;
        ...
    &amp;lt;/activity&amp;gt;&lt;/pre&gt;&lt;p&gt;For non-activity windows, there is a new Window.setSoftInputMode() method that can be used to control their behavior.  Note that calling this API will make your application incompatible with previous Android platforms.&lt;/p&gt;&lt;h4&gt;Controlling the action buttons&lt;/h4&gt;&lt;p&gt;The final customization we will look at is the "action" buttons in the IME.  There are currently two types of actions:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The enter key on a soft keyboard is typically bound to an action when not operating on a mult-line edit text.  For example, on the G1 pressing the hard enter key will typically move to the next field or the application will intercept it to execute an action; with a soft keyboard, this overloading of the enter key remains, since the enter button just sends an enter key event.&lt;/li&gt;&lt;li&gt;When in fullscreen mode, an IME may also put an additional action button to the right of the text being edited, giving the user quick access to a common application operation.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;These options are controlled with the &lt;code&gt;android:imeOptions&lt;/code&gt; attribute on TextView.  The value you supply here can be any combination of:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;One of the pre-defined action constants (&lt;code&gt;actionGo&lt;/code&gt;, &lt;code&gt;actionSearch&lt;/code&gt;, &lt;code&gt;actionSend&lt;/code&gt;, &lt;code&gt;actionNext&lt;/code&gt;, &lt;code&gt;actionDone&lt;/code&gt;).  If none of these are specified, the system will infer either &lt;code&gt;actionNext&lt;/code&gt; or &lt;code&gt;actionDone&lt;/code&gt; depending on whether there is a focusable field after this one; you can explicitly force no action with &lt;code&gt;actionNone&lt;/code&gt;.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;flagNoEnterAction&lt;/code&gt; option tells the IME that the action should &lt;em&gt;not&lt;/em&gt; be available on the enter key, even if the text itself is not multi-line.  This avoids having unrecoverable actions like (send) that can be accidentally touched by the user while typing.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;flagNoAccessoryAction&lt;/code&gt; removes the action button from the text area, leaving more room for text.&lt;/li&gt;&lt;li&gt;The &lt;code&gt;flagNoExtractUi&lt;/code&gt; completely removes the text area, allowing the application to be seen behind it.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;The previous IM application message view also provides an example of an interesting use of imeOptions, to specify the send action but not let it be shown on the enter key:&lt;/p&gt;&lt;pre&gt; android:imeOptions="actionSend|flagNoEnterAction"&lt;/pre&gt;&lt;h3&gt;APIs for controlling IMEs&lt;/h3&gt;&lt;p&gt;For more advanced control over the IME, there are a variety of new APIs you can use.  Unless special care is taken (such as by using reflection), using these APIs will cause your application to be incompatible with previous versions of Android, and you should make sure you specify &lt;code&gt;android:minSdkVersion="3"&lt;/code&gt; in your manifest.&lt;/p&gt;&lt;p&gt;The primary API is the new &lt;code&gt;android.view.inputmethod.InputMethodManager&lt;/code&gt; class, which you can retrieve with &lt;code&gt;Context.getSystemService()&lt;/code&gt;.  It allows you to interact with the global input method state, such as explicitly hiding or showing the current IME's input area.&lt;/p&gt;&lt;p&gt;There are also new window flags controlling input method interaction, which you can control through the existing &lt;code&gt;Window.addFlags()&lt;/code&gt; method and new &lt;code&gt;Window.setSoftInputMode()&lt;/code&gt; method.  The &lt;code&gt;PopupWindow&lt;/code&gt; class has grown corresponding methods to control these options on its window.  One thing in particular to be aware of is the new &lt;code&gt;WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM&lt;/code&gt; constant, which is used to control whether a window is on top of or behind the current IME.&lt;/p&gt;&lt;p&gt;Most of the interaction between an active IME and application is done through the &lt;code&gt;android.view.inputmethod.InputConnection&lt;/code&gt; class.  This is the API an application implement, which an IME calls to perform the appropriate edit operations on the application.  You won't normally need to worry about this, since &lt;code&gt;TextView&lt;/code&gt; provides its own implementation for itself.&lt;/p&gt;&lt;p&gt;There are also a handful of new &lt;code&gt;View&lt;/code&gt; APIs, the most important of these being&lt;code&gt; onCreateInputConnection()&lt;/code&gt; which creates a new &lt;code&gt;InputConnection&lt;/code&gt; for an IME (and fills in an &lt;code&gt;android.view.inputmethod.EditorInfo&lt;/code&gt; structure with your input type, IME options, and other data); again, most developers won't need to worry about this, since TextView takes care of it for you.&lt;/p&gt;&lt;hr style="align: center; width: 66%; border: none 0; border-top: 1px dashed #000;" /&gt;&lt;p&gt;&lt;em&gt;Learn about Android 1.5 and more at &lt;a href="http://code.google.com/events/io/"&gt;Google I/O&lt;/a&gt;. Members of the Android team will be there to give a series of &lt;a href="http://code.google.com/events/io/sessions.html#android"&gt;in-depth technical sessions&lt;/a&gt; and to field your toughest questions.&lt;/em&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-6719288588971680640?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=pIV-jfhKlMg:JroYQo0Ok3s:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=pIV-jfhKlMg:JroYQo0Ok3s:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=pIV-jfhKlMg:JroYQo0Ok3s:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/pIV-jfhKlMg" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/6719288588971680640?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/6719288588971680640?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/pIV-jfhKlMg/updating-applications-for-on-screen.html" title="Updating Applications for On-screen Input Methods" /><author><name>Dianne Hackborn</name><uri>http://www.blogger.com/profile/05718281896174499332</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="05293452969024352076" /></author><feedburner:origLink>http://android-developers.blogspot.com/2009/04/updating-applications-for-on-screen.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0cAR38zeCp7ImA9WxJTEkU.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-7546043629102318539</id><published>2009-04-20T18:43:00.000-07:00</published><updated>2009-04-20T19:30:46.180-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-20T19:30:46.180-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="How-to" /><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><category scheme="http://www.blogger.com/atom/ns#" term="Widgets" /><title>Introducing home screen widgets and the AppWidget framework</title><content type="html">&lt;p&gt;One exciting new feature in the Android 1.5 SDK is the AppWidget framework which allows developers to write "widgets" that people can drop onto their home screen and interact with.  Widgets can provide a quick glimpse into full-featured apps, such as showing upcoming calendar events, or viewing details about a song playing in the background.&lt;/p&gt;&lt;p&gt;When widgets are dropped onto the home screen, they are given a reserved space to display custom content provided by your app.  Users can also interact with your app through the widget, for example pausing or switching music tracks.  If you have a background service, you can push widget updates on your own schedule, or the AppWidget framework provides an automatic update mechanism.&lt;/p&gt;&lt;p&gt;At a high level, each widget is a BroadcastReceiver paired with XML metadata describing the widget details.  The AppWidget framework communicates with your widget through broadcast intents, such as when it requests an update.  Widget updates are built and sent using RemoteViews which package up a layout and content to be shown on the home screen.&lt;/p&gt;&lt;p&gt;&lt;img style="margin: 0pt 0pt 10px 10px; float: right; width: 214px; height: 320px;" src="http://2.bp.blogspot.com/_y1mY6f9T7rU/Sej_RgrVQUI/AAAAAAAAAAM/fr5SdKeUViU/s320/wiktionary-widget.png" alt="Widget screenshot" id="BLOGGER_PHOTO_ID_5325787235660153154" border="0" /&gt;You can easily add widgets into your existing app, and in this article I'll walk through a quick example: writing a widget to show the Wiktionary "Word of the day."  The &lt;a href="http://code.google.com/p/wiktionary-android/source/browse/#svn/trunk/SimpleWiktionary"&gt;full source code is available&lt;/a&gt;, but I'll point out the AppWidget-specific code in detail here.&lt;/p&gt;&lt;p&gt;First, you'll need some &lt;a href="http://code.google.com/p/wiktionary-android/source/browse/trunk/SimpleWiktionary/res/xml/widget_word.xml"&gt;XML metadata to describe the widget&lt;/a&gt;, including the home screen area you'd like to reserve, an initial layout to show, and how often you'd like to be updated.  The default Android home screen uses a cell-based layout, so it rounds your requested size up to the next-nearest cell size.  This can be a little confusing, so here's a quick equation to help:&lt;/p&gt;&lt;pre class="prettyprint"&gt;Minimum size in dip = (Number of cells * 74dip) - 2dip&lt;/pre&gt;&lt;p&gt;In this example, we want our widget to be 2 cells wide and 1 cell tall, which means we should request a minimum size 146dip x 72dip.  We're also going to request updates once per day, which is roughly every 86,400,000 milliseconds.  Here's what our widget XML metadata looks like:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&amp;lt;appwidget-provider
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="146dip"
    android:minHeight="72dip"
    android:initialLayout="@layout/widget_message"
    android:updatePeriodMillis="86400000"
    /&amp;gt;&lt;/pre&gt;&lt;p&gt;Next, let's pair this XML metadata with a &lt;a href="http://code.google.com/p/wiktionary-android/source/browse/trunk/SimpleWiktionary/AndroidManifest.xml#29"&gt;BroadcastReceiver in the AndroidManifest&lt;/a&gt;:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&amp;lt;!-- Broadcast Receiver that will process AppWidget updates --&amp;gt;
&amp;lt;receiver android:name=".WordWidget" android:label="@string/widget_name"&amp;gt;
    &amp;lt;intent-filter&amp;gt;
        &amp;lt;action android:name="android.appwidget.action.APPWIDGET_UPDATE" /&amp;gt;
    &amp;lt;/intent-filter&amp;gt;
    &amp;lt;meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_word" /&amp;gt;
&amp;lt;/receiver&amp;gt;

&amp;lt;!-- Service to perform web API queries --&amp;gt;
&amp;lt;service android:name=".WordWidget$UpdateService" /&amp;gt;&lt;/pre&gt;&lt;p&gt;Finally, let's write the BroadcastReceiver code to actually handle AppWidget requests.  To help widgets manage all of the various broadcast events, there is a helper class called AppWidgetProvider, which we'll use here. One very important thing to notice is that we're launching a background service to perform the actual update.  This is because BroadcastReceivers are subject to the &lt;a href="http://developer.android.com/guide/practices/design/responsiveness.html"&gt;Application Not Responding&lt;/a&gt; (ANR) timer, which may prompt users to force close our app if it's taking too long.  Making a web request might take several seconds, so we use the service to avoid any ANR timeouts.&lt;/p&gt;&lt;pre class="prettyprint"&gt;/**
 * Define a simple widget that shows the Wiktionary "Word of the day." To build
 * an update we spawn a background {@link Service} to perform the API queries.
 */
public class WordWidget extends AppWidgetProvider {
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager,
        int[] appWidgetIds) {
        // To prevent any ANR timeouts, we perform the update in a service
        context.startService(new Intent(context, UpdateService.class));
    }

    public static class UpdateService extends Service {
        @Override
        public void onStart(Intent intent, int startId) {
            // Build the widget update for today
            RemoteViews updateViews = buildUpdate(this);

            // Push update for this widget to the home screen
            ComponentName thisWidget = new ComponentName(this, WordWidget.class);
            AppWidgetManager manager = AppWidgetManager.getInstance(this);
            manager.updateAppWidget(thisWidget, updateViews);
        }

        /**
         * Build a widget update to show the current Wiktionary
         * "Word of the day." Will block until the online API returns.
         */
        public RemoteViews buildUpdate(Context context) {
            // Pick out month names from resources
            Resources res = context.getResources();
            String[] monthNames = res.getStringArray(R.array.month_names);

            // Find current month and day
            Time today = new Time();
            today.setToNow();

            // Build today's page title, like "Wiktionary:Word of the day/March 21"
            String pageName = res.getString(R.string.template_wotd_title,
                monthNames[today.month], today.monthDay);
            RemoteViews updateViews = null;
            String pageContent = "";

            try {
                // Try querying the Wiktionary API for today's word
                SimpleWikiHelper.prepareUserAgent(context);
                pageContent = SimpleWikiHelper.getPageContent(pageName, false);
            } catch (ApiException e) {
                Log.e("WordWidget", "Couldn't contact API", e);
            } catch (ParseException e) {
                Log.e("WordWidget", "Couldn't parse API response", e);
            }

            // Use a regular expression to parse out the word and its definition
            Pattern pattern = Pattern.compile(SimpleWikiHelper.WORD_OF_DAY_REGEX);
            Matcher matcher = pattern.matcher(pageContent);
            if (matcher.find()) {
                // Build an update that holds the updated widget contents
                updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_word);
    
                String wordTitle = matcher.group(1);
                updateViews.setTextViewText(R.id.word_title, wordTitle);
                updateViews.setTextViewText(R.id.word_type, matcher.group(2));
                updateViews.setTextViewText(R.id.definition, matcher.group(3).trim());
    
                // When user clicks on widget, launch to Wiktionary definition page
                String definePage = res.getString(R.string.template_define_url,
                        Uri.encode(wordTitle));
                Intent defineIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(definePage));
                PendingIntent pendingIntent = PendingIntent.getActivity(context,
                        0 /* no requestCode */, defineIntent, 0 /* no flags */);
                updateViews.setOnClickPendingIntent(R.id.widget, pendingIntent);
    
            } else {
                // Didn't find word of day, so show error message
                updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_message);
                CharSequence errorMessage = context.getText(R.string.widget_error);
                updateViews.setTextViewText(R.id.message, errorMessage);
            }
            return updateViews;
        }

        @Override
        public IBinder onBind(Intent intent) {
            // We don't need to bind to this service
            return null;
        }
    }
}&lt;/pre&gt;&lt;p&gt;And there you have it, a simple widget that will show the Wiktionary "Word of the day."  When an update is requested, we read the online API and push the newest data to the surface.  The AppWidget framework automatically requests updates from us as needed, such as when a new widget is inserted, and again each day to load the new "Word of the day."&lt;/p&gt;&lt;p&gt;Finally, some words of wisdom.  Widgets are designed for longer-term content that doesn't update very often, and updating more frequently than every hour can quickly eat up battery and bandwidth.  Consider updating as infrequently as possible, or letting your users pick a custom update frequency.  For example, some people might want a stock ticker to update every 15 minutes, or maybe only four times a day. I'll be talking about additional strategies for saving battery life as part of a session I'm &lt;a href="http://code.google.com/events/io/"&gt;giving at Google I/O&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;One last cool thing to mention is that the AppWidget framework is abstracted in both directions, meaning alternative home screens can also contain widgets.  Your widgets can be inserted into any home screen that supports the AppWidget framework.&lt;/p&gt;&lt;p&gt;We've already written several widgets ourselves, such as the Calendar and Music widgets, but we're even more excited to see the widgets you'll write!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-7546043629102318539?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=szIxn5N9QKI:k3svqt-AaIk:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=szIxn5N9QKI:k3svqt-AaIk:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=szIxn5N9QKI:k3svqt-AaIk:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/szIxn5N9QKI" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/7546043629102318539?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/7546043629102318539?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/szIxn5N9QKI/introducing-home-screen-widgets-and.html" title="Introducing home screen widgets and the AppWidget framework" /><author><name>Jeff Sharkey</name><uri>http://www.blogger.com/profile/15560859325638213656</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="13933879408157097807" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_y1mY6f9T7rU/Sej_RgrVQUI/AAAAAAAAAAM/fr5SdKeUViU/s72-c/wiktionary-widget.png" height="72" width="72" /><feedburner:origLink>http://android-developers.blogspot.com/2009/04/introducing-home-screen-widgets-and.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0UFQHg8fCp7ImA9WxVaF0o.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-7891860032686230519</id><published>2009-04-14T23:00:00.000-07:00</published><updated>2009-04-14T23:00:11.674-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-14T23:00:11.674-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="How-to" /><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><category scheme="http://www.blogger.com/atom/ns#" term="User Interface" /><title>UI framework changes in Android 1.5</title><content type="html">&lt;p&gt;On Monday, we released an &lt;a href="http://developer.android.com/sdk/preview/"&gt;early look at the Android 1.5 SDK&lt;/a&gt;. Not only does this platform update contain &lt;a href="http://developer.android.com/sdk/preview/features.html"&gt;numerous new features&lt;/a&gt;, APIs, and bug fixes, but Android 1.5 also brings a new default look for the Android UI framework. After Android 1.0 and 1.1, our designers worked hard to refine and polish the appearance of the system. The screenshots below show the same activity (creating a new contact) on Android 1.1 and Android 1.5:&lt;/p&gt;&lt;p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 277px;" src="http://1.bp.blogspot.com/_9l0GmPwgCzk/Sd-YpjNpaEI/AAAAAAAAADM/8G0-yahXrSo/s400/android.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5323141124169754690" /&gt;&lt;/p&gt;&lt;p&gt;You can see in this example that the buttons and checkboxes have a new appearance. Even though these changes do not affect binary nor source compatibility, they might still break the UI of your apps. As part of the UI refresh, the minimum size of some of the widgets has changed. For instance, Android 1.1 buttons have a minimum size of 44x48 pixels whereas Android 1.5 buttons now have a minimum size of 24x48 pixels. The image below compares the sizes of Android 1.1 buttons with Android 1.5 buttons:&lt;/p&gt;&lt;p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 100px; height: 130px;" src="http://4.bp.blogspot.com/_9l0GmPwgCzk/Sd-c0Wvd8eI/AAAAAAAAADU/2X2YwR6Rxvc/s400/buttons.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5323145707847021026" /&gt;&lt;/p&gt;&lt;p&gt;If you rely on the button's minimum size, then the layout of your application may not be the same in Android 1.5 as it was in Android 1.1 because of this change. This would happen for instance if you created a grid of buttons using &lt;code&gt;LinearLayout&lt;/code&gt; and relying on the minimum size yielded by &lt;code&gt;wrap_content&lt;/code&gt; to align the buttons properly:&lt;/p&gt;&lt;p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 277px;" src="http://2.bp.blogspot.com/_9l0GmPwgCzk/Sd-e2fnrTlI/AAAAAAAAADc/bgt_QYsnxCs/s400/grid.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5323147943613255250" /&gt;&lt;/p&gt;&lt;p&gt;This layout could easily be fixed by using the &lt;code&gt;android:layout_weight&lt;/code&gt; attribute or by replacing the &lt;code&gt;LinearLayout&lt;/code&gt; containers with a &lt;code&gt;TableLayout&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;This example is probably the worst-case UI issue you may encounter when running your application on Android 1.5.  Other changes introduced in Android 1.5, especially bug fixes in the layout views, may also impact your application&amp;mdash;especially if it is relying on faulty/buggy behavior of the UI framework.&lt;/p&gt;&lt;p&gt;If you encounter issues when running your application on Android 1.5, please &lt;a href="http://developer.android.com/community/index.html"&gt;join us on the Google groups or IRC&lt;/a&gt; so that we and the Android community can help you fix your application.&lt;/p&gt;&lt;p&gt;Happy coding!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-7891860032686230519?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=5IcsmHY3bWw:QdjcShuqwoQ:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=5IcsmHY3bWw:QdjcShuqwoQ:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=5IcsmHY3bWw:QdjcShuqwoQ:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/5IcsmHY3bWw" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/7891860032686230519?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/7891860032686230519?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/5IcsmHY3bWw/ui-framework-changes-in-android-15.html" title="UI framework changes in Android 1.5" /><author><name>Romain Guy</name><uri>http://www.blogger.com/profile/14359137835485363401</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11053364165382206530" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_9l0GmPwgCzk/Sd-YpjNpaEI/AAAAAAAAADM/8G0-yahXrSo/s72-c/android.png" height="72" width="72" /><feedburner:origLink>http://android-developers.blogspot.com/2009/04/ui-framework-changes-in-android-15.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C08AR3k4eSp7ImA9WxVaF0g.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-5373556931259387594</id><published>2009-04-13T16:10:00.000-07:00</published><updated>2009-04-14T16:30:46.731-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-14T16:30:46.731-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android 1.5" /><category scheme="http://www.blogger.com/atom/ns#" term="SDK updates" /><category scheme="http://www.blogger.com/atom/ns#" term="Announcements" /><title>Getting ready for Android 1.5</title><content type="html">&lt;p&gt;&lt;img style="float:left; margin:0 10px 10px 0; width: 200px; height: 200px;" src="http://3.bp.blogspot.com/_vOWVJj4LO0w/Sd7Bn6RnQJI/AAAAAAAAAC4/L6AcJuqk6Yg/s400/cupcake.png" border="0" alt="Android 1.5 SDK release!" id="BLOGGER_PHOTO_ID_5322904701000695954" /&gt;I'm excited to announce that starting today, developers can get an early look at the SDK for the next version of the Android platform. This new version (which will be 1.5) is based on the cupcake branch from the &lt;a href="http://source.android.com"&gt;Android Open Source Project&lt;/a&gt;. Version 1.5 introduces APIs for features such as soft keyboards, home screen widgets, live folders, and speech recognition. At the developer site, you can &lt;a href="http://developer.android.com/sdk/preview/"&gt;download the early-look Android 1.5 SDK&lt;/a&gt;, read important information about upgrading your Eclipse plugin and existing projects, and learn about &lt;a href="http://developer.android.com/sdk/preview/features.html"&gt;what's new and improved&lt;/a&gt; in Android 1.5.&lt;/p&gt;&lt;p&gt;We've also made changes to the developer tools and the structure of the SDK itself. Future Android SDK releases will include multiple versions of the Android platform. For example, this early-look includes Android platform versions 1.1 and 1.5. One benefit of this change is that developers can target different Android platform versions from within a single SDK installation.  Another is that it enables developers to install Android SDK add-ons to access extended functionality that might be provided by OEMs, carriers, or other providers. We at Google are using this feature ourselves: this early-look SDK includes an add-on for the Google APIs.  This add-on provides support for the Google Maps API, which was previously embedded in the "core" SDK.&lt;/p&gt;&lt;p&gt;To help you prepare your applications for the release of Android 1.5 on phones, over the next few weeks we'll be publishing a series of articles on this blog to highlight new APIs and other changes. In addition to the new APIs that I've mentioned, we'll cover topics such as OpenGL, asynchronous tasks, system settings, and new Activity callbacks.&lt;/p&gt;&lt;p&gt;I encourage you to start working with this early-look SDK, but please know that the APIs for Android 1.5 have not been finalized. The majority of the APIs are settled, but there may be some changes before the final release. As a result, it's very important that you don't release applications based on this early-look SDK, since they may not work on real devices. The applications you release should be built on the final Android 1.5 SDK release, which will be available around the end of this month.&lt;/p&gt;&lt;p&gt;I look forward to seeing all the great apps that use the new capabilities in Android 1.5. Happy coding!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-5373556931259387594?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=X8LAc30HiyE:SCSRV7_l28I:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=X8LAc30HiyE:SCSRV7_l28I:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=X8LAc30HiyE:SCSRV7_l28I:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/X8LAc30HiyE" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/5373556931259387594?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/5373556931259387594?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/X8LAc30HiyE/getting-ready-for-android-15.html" title="Getting ready for Android 1.5" /><author><name>Xavier Ducrohet</name><uri>http://www.blogger.com/profile/00361998914767345309</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="14283194986884703640" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://3.bp.blogspot.com/_vOWVJj4LO0w/Sd7Bn6RnQJI/AAAAAAAAAC4/L6AcJuqk6Yg/s72-c/cupcake.png" height="72" width="72" /><feedburner:origLink>http://android-developers.blogspot.com/2009/04/getting-ready-for-android-15.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkENRHc7fSp7ImA9WxVbFEg.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-9089603372394846532</id><published>2009-03-30T16:00:00.000-07:00</published><updated>2009-03-30T16:11:35.905-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-30T16:11:35.905-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="Android Developer Phone" /><category scheme="http://www.blogger.com/atom/ns#" term="Google I/O" /><title>Developer News</title><content type="html">&lt;p&gt;For no particular reason other than to celebrate this particular Monday, I wanted to update developers on two Android-related news items.&lt;/p&gt;&lt;p&gt;If you're a developer who will be in the San Francisco Bay Area at the end of May, I hope you'll join us at the &lt;a href="http://code.google.com/events/io"&gt;2009 Google I/O developer conference&lt;/a&gt;. You might have already seen the sessions we had listed for Android, but today I'm quite pleased to let you know that we've added a few more Android-related sessions.  You can find the &lt;a href="http://code.google.com/events/io/sessions.html"&gt;full list plus abstracts&lt;/a&gt; on the Google I/O site, but here are the titles:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;Turbo-Charge Your UI: How to Make Your Android UI Fast and Efficient&lt;/li&gt;&lt;li&gt;Pixel-Perfect Code: How to Marry Interaction and Visual Design the Android Way&lt;/li&gt;&lt;li&gt;Supporting Multiple Devices with One Binary&lt;/li&gt;&lt;li&gt;Debugging Arts of the Ninja Masters&lt;/li&gt;&lt;li&gt;Coding for Life&amp;mdash;Battery Life, That Is&lt;/li&gt;&lt;li&gt;Writing Real-Time Games for Android&lt;/li&gt;&lt;li&gt;Android Lightning Talks&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;These sessions don't even include the "fireside chat" with the Core Technical Team that we have planned. We're working on still more sessions too; keep an ear to the ground on this blog and the Google I/O site for the latest info. I'm pretty excited about how the Android sessions for Google I/O are coming together. I think it's going to be a great event, and I hope to meet many of you there.&lt;/p&gt;&lt;p&gt;The other topic I want to mention is that our partners at HTC have uploaded &lt;a href="http://www.htc.com/www/support/android/adp.html"&gt;a new system image for Android Dev Phone 1&lt;/a&gt; owners. This new image is mostly the same as the one we mentioned earlier this month, but adds voice dialing. Note that not all features will work correctly in all countries, such as voice dialing and Google Voice Search which currently only work well for US English. Additionally, there are some features that we aren't able to make available at all in some countries. For instance, this build can't currently include Google Latitude due to privacy standards in some regions. We'll always keep the ADP1 builds as full-featured as we can, but it's important to remember that these devices are primarily intended for development, and won't necessarily have all the features included on mainstream builds.&lt;/p&gt;&lt;p&gt;I hope this news is useful to you. As always, happy coding!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-9089603372394846532?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=fuUTTV2CjU4:Y14Ir8ChXYw:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=fuUTTV2CjU4:Y14Ir8ChXYw:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=fuUTTV2CjU4:Y14Ir8ChXYw:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/fuUTTV2CjU4" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/9089603372394846532?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/9089603372394846532?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/fuUTTV2CjU4/developer-news.html" title="Developer News" /><author><name>Dan Morrill</name><uri>http://www.blogger.com/profile/12526265248010766454</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="17206489683788395259" /></author><feedburner:origLink>http://android-developers.blogspot.com/2009/03/developer-news.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DE4FRHoycCp7ImA9WxVbFEk.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-8792365559562607541</id><published>2009-03-30T14:00:00.000-07:00</published><updated>2009-03-30T14:01:55.498-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-30T14:01:55.498-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="How-to" /><category scheme="http://www.blogger.com/atom/ns#" term="User Interface" /><category scheme="http://www.blogger.com/atom/ns#" term="Optimization" /><title>Android Layout Tricks #3: Optimize with stubs</title><content type="html">&lt;p&gt;Sharing and reusing layouts is very easy with Android thanks to the &lt;a href="http://www.curious-creature.org/2009/02/25/android-layout-trick-2-include-to-reuse/"&gt;&amp;lt;include /&amp;gt;&lt;/a&gt; tag, sometimes even too easy and you might end up with user interfaces that contain a large number of views, some of which are rarely used. Thankfully, Android offers a very special widget called &lt;a href="http://d.android.com/reference/android/view/ViewStub.html"&gt;ViewStub&lt;/a&gt;, which brings you all the benefits of the &lt;code&gt;&amp;lt;include /&amp;gt;&lt;/code&gt; without polluting your user interface with rarely used views.&lt;/p&gt;&lt;p&gt;A &lt;code&gt;ViewStub&lt;/code&gt; is a dumb and lightweight view. It has no dimension, it does not draw anything and does not participate in the layout in any way. This means a &lt;code&gt;ViewStub&lt;/code&gt; is very cheap to inflate and very cheap to keep in a view hierarchy. A &lt;code&gt;ViewStub&lt;/code&gt; can be best described as a &lt;em&gt;lazy include&lt;/em&gt;. The layout referenced by a &lt;code&gt;ViewStub&lt;/code&gt; is inflated and added to the user interface only when you decide so.&lt;/p&gt;&lt;p&gt;The following screenshot comes from the &lt;a href="http://code.google/p/shelves"&gt;Shelves&lt;/a&gt; application. The main purpose of the activity shown in the screenshot is to present the user with a browsable list of books:&lt;/p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://2.bp.blogspot.com/_9l0GmPwgCzk/Sb9CqClYIjI/AAAAAAAAACc/1ijy-Ab7oOE/s1600/viewstub1.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5314039375336055346" /&gt;&lt;p&gt;The same activity is also used when the user adds or imports new books. During such an operation, Shelves shows extra bits of user interface. The screenshot below shows the progress bar and cancel button that appear at the bottom of the screen during an import:&lt;/p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://1.bp.blogspot.com/_9l0GmPwgCzk/Sb9DCwlwvZI/AAAAAAAAACk/ETR67WJ5XTw/s1600/viewstub2.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5314039800002559378" /&gt;&lt;p&gt;Because importing books is not a common operation, at least when compared to browsing the list of books, the import panel is originally represented by a &lt;code&gt;ViewStub&lt;/code&gt;:&lt;/p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;" src="http://4.bp.blogspot.com/_9l0GmPwgCzk/Sb9Dh16nq9I/AAAAAAAAACs/5cAKaaUCq84/s1600/viewstub3.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5314040334008167378" /&gt;&lt;p&gt;When the user initiates the import process, the &lt;code&gt;ViewStub&lt;/code&gt; is inflated and replaced by the content of the layout file it references:&lt;/p&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;;" src="http://1.bp.blogspot.com/_9l0GmPwgCzk/Sb9DzlKN-FI/AAAAAAAAAC0/BH9Nv-Z1eqI/s1600/viewstub4.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5314040638747834450" /&gt;&lt;p&gt;To use a &lt;code&gt;ViewStub&lt;/code&gt; all you need is to specify an &lt;code&gt;android:id&lt;/code&gt; attribute, to later inflate the stub, and an &lt;code&gt;android:layout&lt;/code&gt; attribute, to reference what layout file to include and inflate. A stub lets you use a third attribute, &lt;code&gt;android:inflatedId&lt;/code&gt;, which can be used to override the id of the root of the included file. Finally, the layout parameters specified on the stub will be applied to the roof of the included layout. Here is an example:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&amp;lt;ViewStub
  android:id="@+id/stub_import"
  android:inflatedId="@+id/panel_import"

  android:layout="@layout/progress_overlay"

  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:layout_gravity="bottom" /&amp;gt;&lt;/pre&gt;&lt;p&gt;When you are ready to inflate the stub, simply invoke the &lt;a href="http://d.android.com/reference/android/view/ViewStub.html#inflate()"&gt;inflate()&lt;/a&gt; method. You can also simply change the visibility of the stub to &lt;a href="http://d.android.com/reference/android/view/View.html#VISIBLE"&gt;VISIBLE&lt;/a&gt; or &lt;a href="http://d.android.com/reference/android/view/View.html#INVISIBLE"&gt;INVISIBLE&lt;/a&gt; and the stub will inflate. Note however that the &lt;code&gt;inflate()&lt;/code&gt; method has the benefit of returning the root &lt;code&gt;View&lt;/code&gt; of the inflate layout:&lt;/p&gt;&lt;pre class="prettyprint"&gt;((ViewStub) findViewById(R.id.stub_import)).setVisibility(View.VISIBLE);
// or
View importPanel = ((ViewStub) findViewById(R.id.stub_import)).inflate();&lt;/pre&gt;&lt;p&gt;It is very important to remember that after the stub is inflated, the stub is &lt;em&gt;removed&lt;/em&gt; from the view hierarchy. As such, it is unnecessary to keep a long-lived reference, for instance in an class instance field, to a &lt;code&gt;ViewStub&lt;/code&gt;.&lt;/p&gt;&lt;p&gt;A &lt;code&gt;ViewStub&lt;/code&gt; is a great compromise between ease of programming and efficiency. Instead of inflating views manually and adding them at runtime to your view hierarchy, simply use a &lt;code&gt;ViewStub&lt;/code&gt;. It's cheap and easy. The only drawback of &lt;code&gt;ViewStub&lt;/code&gt; is that it currently does &lt;em&gt;not&lt;/em&gt; support the &lt;a href="http://www.curious-creature.org/2009/03/01/android-layout-tricks-3-optimize-part-1/"&gt;&amp;lt;merge /&amp;gt; tag&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;Happy coding!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-8792365559562607541?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=aRvnbzcsXtE:jG9JjA4FcO8:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=aRvnbzcsXtE:jG9JjA4FcO8:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=aRvnbzcsXtE:jG9JjA4FcO8:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/aRvnbzcsXtE" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/8792365559562607541?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/8792365559562607541?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/aRvnbzcsXtE/android-layout-tricks-3-optimize-with.html" title="Android Layout Tricks #3: Optimize with stubs" /><author><name>Romain Guy</name><uri>http://www.blogger.com/profile/14359137835485363401</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11053364165382206530" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://2.bp.blogspot.com/_9l0GmPwgCzk/Sb9CqClYIjI/AAAAAAAAACc/1ijy-Ab7oOE/s72-c/viewstub1.png" height="72" width="72" /><feedburner:origLink>http://android-developers.blogspot.com/2009/03/android-layout-tricks-3-optimize-with.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CEMAQ388fyp7ImA9WxVVFk4.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-7278744263990542203</id><published>2009-03-09T13:44:00.000-07:00</published><updated>2009-03-09T14:00:42.177-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-09T14:00:42.177-07:00</app:edited><title>Software Update Available for the Android Developer Phone</title><content type="html">&lt;p&gt;&lt;a href="http://android-developers.blogspot.com/2008/12/new-resources-for-developers.html" id="izyx" title="Back in December"&gt;Back in December&lt;/a&gt;, the Android Dev Phone 1 (ADP1) went on sale, giving developers access to unlocked hardware for their work. A few weeks ago, consumers with retail devices received an over the air update with the 1.1 release of Android. I know that many developers will be pleased to hear that today, our colleagues at HTC have released a &lt;a href="http://www.htc.com/www/support/android/adp.html"&gt;1.1 version of Android for the Android Dev Phone&lt;/a&gt; which you can install on your device. If you have questions about the process of updating your device, you can &lt;a href="http://groups.google.com/group/android-devphone-updating" id="qs4f" title="ask the mailing list"&gt;ask the mailing list&lt;/a&gt; we've set up for such questions.&lt;/p&gt;&lt;p&gt;This new system image is fully compatible with Android 1.1. To see a list of everything that's new, you can review the &lt;a href="http://developer.android.com/sdk/android-1.1.html" id="xxk6" title="notes from the 1.1_r1 SDK"&gt;notes from the 1.1_r1 SDK&lt;/a&gt;. This update also includes support for searching by voice, and priced apps in the Android Market.&lt;/p&gt;&lt;p&gt;Some developers have asked about the support for copy-protected apps on developer devices, and indeed there is a limitation you should be aware of. Many developers are concerned about the unauthorized redistribution of their applications, so they make use of the copy-protection feature (known as "forward locking") which prevents applications from being copied off devices. However, developer phones like the ADP1 allow for unrestricted access to the device's contents, making it impossible to enforce copy protection. As a result, the Market application on such devices is not able to access copy protected apps, whether they are free or paid. If you choose to add copy protection when you upload your application to the Android Market, then you won't be able to test it on the ADP1's Android Market client. Your application will always be accessible to users who have standard configurations though, and if your application (whether it is free or paid) is not copy-protected it will appear on all devices, including developer configurations.&lt;/p&gt;&lt;p&gt;If you own an Android Developer Phone, I definitely suggest you take advantage of this update. There's lots of good stuff in there, and the new software is backward compatible with Android 1.0, too.  The original 1.0 system image is also now available, you need to downgrade for any reason.  Happy coding!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-7278744263990542203?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=HG1O6qPSJ64:H9YznYZqwcM:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=HG1O6qPSJ64:H9YznYZqwcM:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=HG1O6qPSJ64:H9YznYZqwcM:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/HG1O6qPSJ64" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/7278744263990542203?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/7278744263990542203?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/HG1O6qPSJ64/software-update-available-for-android.html" title="Software Update Available for the Android Developer Phone" /><author><name>Dan Morrill</name><uri>http://www.blogger.com/profile/12526265248010766454</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="17206489683788395259" /></author><feedburner:origLink>http://android-developers.blogspot.com/2009/03/software-update-available-for-android.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CkEEQXw_cCp7ImA9WxVVEko.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-3542064214007631934</id><published>2009-03-05T08:30:00.000-08:00</published><updated>2009-03-05T08:30:00.248-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-05T08:30:00.248-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="User Interface" /><category scheme="http://www.blogger.com/atom/ns#" term="Optimization" /><title>Window Backgrounds &amp; UI Speed</title><content type="html">&lt;p&gt;Some Android applications require to squeeze every bit of performance out of the UI toolkit and there are many ways to do so. In this article, you will discover how to speed up the drawing and the &lt;em&gt;perceived&lt;/em&gt; startup time of your activities. Both these techniques rely on a single feature, the window's background drawable.&lt;/p&gt;&lt;p&gt;The term &lt;em&gt;window background&lt;/em&gt; is a bit misleading however. When you setup your user interface by calling &lt;code&gt;setContentView()&lt;/code&gt; on an &lt;a href="http://d.android.com/reference/android/app/Activity.html"&gt;Activity&lt;/a&gt;, Android adds your views to the &lt;code&gt;Activity&lt;/code&gt;'s window. The window however does not contain only your views, but a few others created for you. The most important one is, in the current implementation used on the T-Mobile G1, the &lt;code&gt;DecorView&lt;/code&gt;, highlighted in the view hierarchy below:&lt;/p&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://progx.org/users/Gfx/android/window_background_root.png" alt="A typical Android view hierarchy" /&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;DecorView&lt;/code&gt; is the view that actually holds the window's background drawable. Calling &lt;a href="http://d.android.com/reference/android/view/Window.html#setBackgroundDrawable(android.graphics.drawable.Drawable)"&gt;getWindow().setBackgroundDrawable()&lt;/a&gt; from your &lt;code&gt;Activity&lt;/code&gt; changes the background of the window by changing the &lt;code&gt;DecorView&lt;/code&gt;'s background drawable. As mentioned before, this setup is very specific to the current implementation of Android and can change in a future version or even on another device.&lt;/p&gt;&lt;p&gt;If you are using the standard Android themes, a default background drawable is set on your activities. The standard theme currently used on the T-Mobile G1 uses for instance a &lt;a href="http://d.android.com/reference/android/graphics/drawable/ColorDrawable.html"&gt;ColorDrawable&lt;/a&gt;. For most applications, this background drawable works just fine and can be left alone. It can however impacts your application's drawing performance. Let's take the example of an application that always draws a full screen opaque picture:&lt;/p&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://progx.org/users/Gfx/android/window_background.png" alt="An opaque user interface doesn't need a window background" /&gt;&lt;/div&gt;&lt;p&gt;You can see on this screenshot that the window's background is invisible, entirely covered by an &lt;code&gt;ImageView&lt;/code&gt;. This application is setup to redraw as fast as it can and draws at about 44 frames per second, or 22 milliseconds per frame (&lt;strong&gt;note:&lt;/strong&gt; the number of frames per second used in this article were obtained on a T-Mobile G1 with my finger on the screen so as to reduce the drawing speed which would otherwise be capped at 60 fps.) An easy way to make such an application draw faster is to &lt;em&gt;remove&lt;/em&gt; the background drawable. Since the user interface is entirely opaque, drawing the background is simply wasteful. Removing the background improves the performance quite nicely:&lt;/p&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://progx.org/users/Gfx/android/window_background_null.png" alt="Remove the background for faster drawing" /&gt;&lt;/div&gt;&lt;p&gt;In this new version of the application, the drawing speed went up to 51 frames per second, or 19 milliseconds per frame. The difference of 3 milliseconds per is easily explained by the speed of the memory bus on the T-Mobile G1: it is exactly the time it takes to move the equivalent of a screenful of pixels on the bus. The difference could be even greater if the default background was using a more expensive drawable.&lt;/p&gt;&lt;p&gt;Removing the window's background can be achieved very easily by using a custom theme. To do so, first create a file called &lt;code&gt;res/values/theme.xml&lt;/code&gt; containing the following:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&amp;lt;resources&amp;gt;
    &amp;lt;style name="Theme.NoBackground" parent="android:Theme"&amp;gt;
        &amp;lt;item name="android:windowBackground"&amp;gt;@null&amp;lt;/item&amp;gt;
    &amp;lt;/style&amp;gt;
&amp;lt;/resources&amp;gt;&lt;/pre&gt;&lt;p&gt;You then need to apply the theme to your activity by adding the attribute &lt;code&gt;android:theme="@style/Theme.NoBackground"&lt;/code&gt; to your &lt;code&gt;&amp;lt;activity /&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;application /&amp;gt;&lt;/code&gt; tag. This trick comes in very handy for any app that uses a &lt;code&gt;MapView&lt;/code&gt;, a &lt;code&gt;WebView&lt;/code&gt; or any other full screen opaque view.&lt;/p&gt;&lt;p&gt;&lt;strong&gt;Opaque views and Android&lt;/strong&gt;: this optimization is currently necessary because the Android UI toolkit is not smart enough to prevent the drawing of views hidden by opaque children. The main reason why this optimization was not implemented is simply because there are usually very few opaque views in Android applications. This is however something that I definitely plan on implementing as soon as possible and I can only apologize for not having been able to do this earlier.&lt;/p&gt;&lt;p&gt;Using a theme to change the window's background is also a fantastic way to improve the &lt;em&gt;perceived&lt;/em&gt; startup performance of some of your activities. This particular trick can only be applied to activities that use a custom background, like a texture or a logo. The &lt;a href="http://code.google.com/p/shelves"&gt;Shelves&lt;/a&gt; application is a good example:&lt;/p&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://progx.org/users/Gfx/shelves2.png" alt="Textured backgrounds are good candidates for window's background" /&gt;&lt;/div&gt;&lt;p&gt;If this application simply set the wooden background in the XML layout or in &lt;code&gt;onCreate()&lt;/code&gt; the user would see the application startup with the default theme and its dark background. The wooden texture would only appear after the inflation of the content view and the first layout/drawing pass. This causes a jarring effect and gives the user the impression that the application takes time to load (which can actually be the case.) Instead, the application defines the wooden background in a theme, picked up by the system as soon as the application starts. The user never sees the default theme and gets the impression that the application is up and running right away. To limit the memory and disk usage, the background is a tiled texture defined in &lt;code&gt;res/drawable/background_shelf.xml&lt;/code&gt;:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&amp;lt;bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/shelf_panel"
    android:tileMode="repeat" /&amp;gt;&lt;/pre&gt;&lt;p&gt;This drawable is simply referenced by the theme:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&amp;lt;resources&amp;gt;
    &amp;lt;style name="Theme.Shelves" parent="android:Theme"&amp;gt;
        &amp;lt;item name="android:windowBackground"&amp;gt;@drawable/background_shelf&amp;lt;/item&amp;gt;
        &amp;lt;item name="android:windowNoTitle"&amp;gt;true&amp;lt;/item&amp;gt;
    &amp;lt;/style&amp;gt;
&amp;lt;/resources&amp;gt;&lt;/pre&gt;&lt;p&gt;The same exact trick is used in the &lt;em&gt;Google Maps application that ships with the T-Mobile G1. When the application is launched, the user immediately sees the loading tiles of &lt;code&gt;MapView&lt;/code&gt;. This is only a trick, the theme is simply using a tiled background that looks exactly like the loading tiles of &lt;code&gt;MapView&lt;/code&gt;.&lt;/em&gt;&lt;/p&gt;&lt;p&gt;Sometimes the best tricks are also the simplest so the next time you create an activity with an opaque UI or a custom background, remember to change the window's background.&lt;/p&gt;&lt;p&gt;&lt;a href="http://progx.org/users/Gfx/android/WindowBackground"&gt;Download the source code of the first example&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;&lt;a href="http://code.google.com/p/shelves/"&gt;Download the source code of Shelves&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-3542064214007631934?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=6G7fXjrpo3U:UREq19TBeRI:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=6G7fXjrpo3U:UREq19TBeRI:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=6G7fXjrpo3U:UREq19TBeRI:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/6G7fXjrpo3U" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/3542064214007631934?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/3542064214007631934?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/6G7fXjrpo3U/window-backgrounds-ui-speed.html" title="Window Backgrounds &amp; UI Speed" /><author><name>Romain Guy</name><uri>http://www.blogger.com/profile/14359137835485363401</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11053364165382206530" /></author><feedburner:origLink>http://android-developers.blogspot.com/2009/03/window-backgrounds-ui-speed.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DEcEQHo8eip7ImA9WxVVEEQ.&quot;"><id>tag:blogger.com,1999:blog-6755709643044947179.post-5845204995564817095</id><published>2009-03-03T08:00:00.000-08:00</published><updated>2009-03-03T08:00:01.472-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-03T08:00:01.472-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="How-to" /><category scheme="http://www.blogger.com/atom/ns#" term="User Interface" /><category scheme="http://www.blogger.com/atom/ns#" term="Optimization" /><title>Android Layout Tricks #3: Optimize by merging</title><content type="html">&lt;p&gt;In the previous installment of &lt;em&gt;Android Layout Tricks&lt;/em&gt;, I showed you &lt;a href="http://www.curious-creature.org/2009/02/25/android-layout-trick-2-include-to-reuse/"&gt;how to use the &lt;code&gt;&amp;lt;include /&amp;gt;&lt;/code&gt; tag&lt;/a&gt; in XML layout to reuse and share your layout code. I  also mentioned the &lt;code&gt;&amp;lt;merge /&amp;gt;&lt;/code&gt; and it's now time to learn how to use it.&lt;/p&gt;&lt;p&gt;The &lt;code&gt;&amp;lt;merge /&amp;gt;&lt;/code&gt; was created for the purpose of optimizing Android layouts by reducing the number of levels in view trees. It's easier to understand the problem this tag solves by looking at an example. The following XML layout declares a layout that shows an image with its title on top of it. The structure is fairly simple; a &lt;a href="http://developer.android.com/reference/android/widget/FrameLayout.html"&gt;FrameLayout&lt;/a&gt; is used to stack a &lt;a href="http://developer.android.com/reference/android/widget/TextView.html"&gt;TextView&lt;/a&gt; on top of an &lt;a href="http://developer.android.com/reference/android/widget/ImageView.html"&gt;ImageView&lt;/a&gt;:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&amp;lt;FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"&amp;gt;

    &amp;lt;ImageView  
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" 
    
        android:scaleType="center"
        android:src="@drawable/golden_gate" /&amp;gt;
    
    &amp;lt;TextView
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_marginBottom="20dip"
        android:layout_gravity="center_horizontal|bottom"

        android:padding="12dip"
        
        android:background="#AA000000"
        android:textColor="#ffffffff"
        
        android:text="Golden Gate" /&amp;gt;

&amp;lt;/FrameLayout&amp;gt;&lt;/pre&gt;&lt;p&gt;This layout renders nicely as we expected and nothing seems wrong with this layout:&lt;/p&gt;

&lt;div style="text-align: center;"&gt;&lt;img src="http://progx.org/users/Gfx/android/merge1.jpg" alt="A FrameLayout is used to overlay a title on top of an image" /&gt;&lt;/div&gt;

&lt;p&gt;Things get more interesting when you inspect the result with &lt;a href="http://developer.android.com/guide/developing/tools/hierarchy-viewer.html"&gt;HierarchyViewer&lt;/a&gt;. If you look closely at the resulting tree you will notice that the &lt;code&gt;FrameLayout&lt;/code&gt; defined in our XML file (highlighted in blue below) is the sole child of another &lt;code&gt;FrameLayout&lt;/code&gt;:&lt;/p&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://progx.org/users/Gfx/android/merge2.png" alt="A layout with only one child of same dimensions can be removed" /&gt;&lt;/div&gt;&lt;p&gt;Since our &lt;code&gt;FrameLayout&lt;/code&gt; has the same dimension as its parent, by the virtue of using the &lt;code&gt;fill_parent&lt;/code&gt; constraints, and does not define any background, extra padding or a gravity, it is &lt;em&gt;totally useless&lt;/em&gt;. We only made the UI more complex for no good reason. But how could we get rid of this &lt;code&gt;FrameLayout&lt;/code&gt;? After all, XML documents require a root tag and tags in XML layouts always represent view instances.&lt;/p&gt;&lt;p&gt;That's where the &lt;code&gt;&amp;lt;merge /&amp;gt;&lt;/code&gt; tag comes in handy. When the  &lt;a href="http://developer.android.com/reference/android/view/LayoutInflater.html"&gt;LayoutInflater&lt;/a&gt; encounters this tag, it skips it and adds the &lt;code&gt;&amp;lt;merge /&amp;gt;&lt;/code&gt; children to the &lt;code&gt;&amp;lt;merge /&amp;gt;&lt;/code&gt; parent. Confused? Let's rewrite our previous XML layout by replacing the &lt;code&gt;FrameLayout&lt;/code&gt; with &lt;code&gt;&amp;lt;merge /&amp;gt;&lt;/code&gt;:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&amp;lt;merge xmlns:android="http://schemas.android.com/apk/res/android"&amp;gt;

    &amp;lt;ImageView  
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" 
    
        android:scaleType="center"
        android:src="@drawable/golden_gate" /&amp;gt;
    
    &amp;lt;TextView
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        android:layout_marginBottom="20dip"
        android:layout_gravity="center_horizontal|bottom"

        android:padding="12dip"
        
        android:background="#AA000000"
        android:textColor="#ffffffff"
        
        android:text="Golden Gate" /&amp;gt;

&amp;lt;/merge&amp;gt;&lt;/pre&gt;&lt;p&gt;With this new version, both the &lt;code&gt;TextView&lt;/code&gt; and the &lt;code&gt;ImageView&lt;/code&gt; will be added directly to the top-level &lt;code&gt;FrameLayout&lt;/code&gt;. The result will be visually the same but the view hierarchy is simpler:&lt;/p&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://progx.org/users/Gfx/android/merge3.png" alt="Optimized view hierarchy using the merge tag" /&gt;&lt;/div&gt;&lt;p&gt;Obviously, using &lt;code&gt;&amp;lt;merge /&amp;gt;&lt;/code&gt; works in this case because the parent of an activity's content view is always a &lt;code&gt;FrameLayout&lt;/code&gt;. You could not apply this trick if your layout was using a &lt;code&gt;LinearLayout&lt;/code&gt; as its root tag for instance. The &lt;code&gt;&amp;lt;merge /&amp;gt;&lt;/code&gt; can be useful in other situations though. For instance, it works perfectly when combined with the &lt;code&gt;&amp;lt;include /&amp;gt;&lt;/code&gt; tag. You can also use &lt;code&gt;&amp;lt;merge /&amp;gt;&lt;/code&gt; when you create a custom composite view. Let's see how we can use this tag to create a new view called &lt;code&gt;OkCancelBar&lt;/code&gt; which simply shows two buttons with customizable labels. You can also &lt;a href="http://progx.org/users/Gfx/android/MergeLayout.zip"&gt;download the complete source code of this example&lt;/a&gt;. Here is the XML used to display this custom view on top of an image:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&amp;lt;merge
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:okCancelBar="http://schemas.android.com/apk/res/com.example.android.merge"&amp;gt;

    &amp;lt;ImageView  
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent" 
    
        android:scaleType="center"
        android:src="@drawable/golden_gate" /&amp;gt;
    
    &amp;lt;com.example.android.merge.OkCancelBar
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:layout_gravity="bottom"

        android:paddingTop="8dip"
        android:gravity="center_horizontal"
        
        android:background="#AA000000"
        
        okCancelBar:okLabel="Save"
        okCancelBar:cancelLabel="Don't save" /&amp;gt;

&amp;lt;/merge&amp;gt;&lt;/pre&gt;&lt;p&gt;This new layout produces the following result on a device:&lt;/p&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://progx.org/users/Gfx/android/merge4.jpg" alt="Creating a custom view with the merge tag" /&gt;&lt;/div&gt;&lt;p&gt;The source code of &lt;code&gt;OkCancelBar&lt;/code&gt; is very simple because the two buttons are defined in an external XML file, loaded using a &lt;code&gt;LayoutInflate&lt;/code&gt;. As you can see in the following snippet, the XML layout &lt;code&gt;R.layout.okcancelbar&lt;/code&gt; is inflated with the &lt;code&gt;OkCancelBar&lt;/code&gt; as the parent:&lt;/p&gt;&lt;pre class="prettyprint"&gt;public class OkCancelBar extends LinearLayout {
    public OkCancelBar(Context context, AttributeSet attrs) {
        super(context, attrs);
        setOrientation(HORIZONTAL);
        setGravity(Gravity.CENTER);
        setWeightSum(1.0f);
        
        LayoutInflater.from(context).inflate(R.layout.okcancelbar, this, true);
        
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.OkCancelBar, 0, 0);
        
        String text = array.getString(R.styleable.OkCancelBar_okLabel);
        if (text == null) text = "Ok";
        ((Button) findViewById(R.id.okcancelbar_ok)).setText(text);
        
        text = array.getString(R.styleable.OkCancelBar_cancelLabel);
        if (text == null) text = "Cancel";
        ((Button) findViewById(R.id.okcancelbar_cancel)).setText(text);
        
        array.recycle();
    }
}&lt;/pre&gt;&lt;p&gt;The two buttons are defined in the following XML layout. As you can see, we use the &lt;code&gt;&amp;lt;merge /&amp;gt;&lt;/code&gt; tag to add the two buttons directly to the &lt;code&gt;OkCancelBar&lt;/code&gt;. Each button is included from the same external XML layout file to make them easier to maintain; we simply override their id:&lt;/p&gt;&lt;pre class="prettyprint"&gt;&amp;lt;merge xmlns:android="http://schemas.android.com/apk/res/android"&amp;gt;
    &amp;lt;include
        layout="@layout/okcancelbar_button"
        android:id="@+id/okcancelbar_ok" /&amp;gt;
        
    &amp;lt;include
        layout="@layout/okcancelbar_button"
        android:id="@+id/okcancelbar_cancel" /&amp;gt;
&amp;lt;/merge&amp;gt;&lt;/pre&gt;&lt;p&gt;We have created a flexible and easy to maintain custom view that generates an efficient view hierarchy:&lt;/p&gt;&lt;div style="text-align: center;"&gt;&lt;img src="http://progx.org/users/Gfx/android/merge5.png" alt="The resulting hierarchy is simple and efficient" /&gt;&lt;/div&gt;&lt;p&gt;The &lt;code&gt;&amp;lt;merge /&amp;gt;&lt;/code&gt; tag is extremely useful and can do wonders in your code. However, it suffers from a couple of limitation:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;code&gt;&amp;lt;merge /&amp;gt;&lt;/code&gt; can only be used as the root tag of an XML layout&lt;/li&gt;
&lt;li&gt;When inflating a layout starting with a &lt;code&gt;&amp;lt;merge /&amp;gt;&lt;/code&gt;, you &lt;strong&gt;must&lt;/strong&gt; specify a parent &lt;code&gt;ViewGroup&lt;/code&gt; and you must set &lt;code&gt;attachToRoot&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; (see the documentation of the &lt;a href="http://developer.android.com/reference/android/view/LayoutInflater.html#inflate(int,%20android.view.ViewGroup,%20boolean)"&gt;inflate()&lt;/a&gt; method)&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;In the next installment of &lt;em&gt;Android Layout Tricks&lt;/em&gt; you will learn about &lt;code&gt;ViewStub&lt;/code&gt;, a powerful variation of &lt;code&gt;&amp;lt;include /&amp;gt;&lt;/code&gt; that can help you further optimize your layouts without sacrificing features.&lt;/p&gt;&lt;p&gt;&lt;a href="http://progx.org/users/Gfx/android/MergeLayout.zip"&gt;Download the complete source code of this example&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-5845204995564817095?l=android-developers.blogspot.com'/&gt;&lt;/div&gt;&lt;div class="feedflare"&gt;
&lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=2bz5jPzNsMg:NatwZKRzlMY:yIl2AUoC8zA"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?d=yIl2AUoC8zA" border="0"&gt;&lt;/img&gt;&lt;/a&gt; &lt;a href="http://feeds.feedburner.com/~ff/blogspot/hsDu?a=2bz5jPzNsMg:NatwZKRzlMY:V_sGLiPBpWU"&gt;&lt;img src="http://feeds.feedburner.com/~ff/blogspot/hsDu?i=2bz5jPzNsMg:NatwZKRzlMY:V_sGLiPBpWU" border="0"&gt;&lt;/img&gt;&lt;/a&gt;
&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/blogspot/hsDu/~4/2bz5jPzNsMg" height="1" width="1"/&gt;</content><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/5845204995564817095?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/6755709643044947179/posts/default/5845204995564817095?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/blogspot/hsDu/~3/2bz5jPzNsMg/android-layout-tricks-3-optimize-by.html" title="Android Layout Tricks #3: Optimize by merging" /><author><name>Romain Guy</name><uri>http://www.blogger.com/profile/14359137835485363401</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="11053364165382206530" /></author><feedburner:origLink>http://android-developers.blogspot.com/2009/03/android-layout-tricks-3-optimize-by.html</feedburner:origLink></entry></feed>
