<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Google Data &#187; Dick Wall, Developer Advocate</title>
	<atom:link href="/author/dick-wall-developer-advocate/feed/" rel="self" type="application/rss+xml" />
	<link>https://googledata.org</link>
	<description>Everything Google: News, Products, Services, Content, Culture</description>
	<lastBuildDate>Tue, 31 Mar 2015 07:11:08 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.7.5</generator>
	<item>
		<title>WikiNotes for Android: Routing Intents</title>
		<link>https://googledata.org/google-android/wikinotes-for-android-routing-intents/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=wikinotes-for-android-routing-intents</link>
		<comments>https://googledata.org/google-android/wikinotes-for-android-routing-intents/#comments</comments>
		<pubDate>Wed, 19 Mar 2008 21:12:00 +0000</pubDate>
		<dc:creator><![CDATA[Dick Wall, Developer Advocate]]></dc:creator>
				<category><![CDATA[Google Android]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[Google Mobile]]></category>
		<category><![CDATA[google os]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[In the last article, we talked about using Linkify to turn wiki words (those that match a regular expression we defined) into a content: URI and defining a path to data that matched a note belonging to that wiki word. As an example, a matching word lik...]]></description>
				<content:encoded><![CDATA[<p>In <a href="http://android-developers.blogspot.com/2008/03/linkify-your-text.html">the last article</a>, we talked about using Linkify to turn wiki words (those that match a regular expression we defined) into a content: URI and defining a path to data that matched a note belonging to that wiki word. As an example, a matching word like <code>ToDoList</code> would be turned into a content: URI like <code>content://com.google.android.wikinotes.db.wikinotes/wikinotes/ToDoList</code> and then acted upon using the VIEW action from the Linkify class.</p>

<p>This article will examine how the Android operating system takes this combination of VIEW action and content: URI and finds the correct activity to fire in order to do something with the data. It will also explain how the other default links created by Linkify, like web URLs and telephone numbers, also result in the correct activity to handle that data type being fired. Finally, this article will start to examine the custom ContentProvider that has been created to handle WikiNotes data. The full description of the ContentProvider and what it does will span a couple more articles as well, because there is a lot to cover.</p>

<h3>The Linkify-calls-intent Workflow</h3>
<p>At a high level, the steps for Linkify to invoke an intent and for the resulting activity (if any) to handle it looks like this:</p>

<ol>
 <li>Linkify is invoked on a TextView to turn matching text patterns into Intent links.</li>
 <li>Linkify takes over monitoring for those Intent links being selected by the user.</li>
 <li>When the user selects a link, Linkify calls the VIEW action using the content: URI associated with the link.</li>
 <li>Android takes the content: URI that represents the data, and looks for a ContentProvider registered in the system that matches the URI.</li>
 <li>If a match is found, Android queries the ContentProvider using the URI, and asks what MIME type the data that will be returned from the URI is.</li>
 <li>Android then looks for an activity registered in the system with an intent-filter that matches both the VIEW action, and the MIME type for the data represented by the content: URI.</li>
 <li>Assuming a match is found, Linkify then invokes the intent for the URI, at which point the activity takes over, and is handed the content: URI.</li>
 <li>The activity can then use the URI to retrieve the data and act on it.</li>
</ol>

<p>If this sounds complicated, it really is a simpler process than it sounds, and it is quite lightweight as well. Perhaps a more understandable statement about how it works might be:</p>

<p>Linkify is used to turn matching text into hot-links. When the user selects a hot-link, Android takes the data locator represented by the hot-link and looks for a data handler for that data locator. If it finds one, it asks for what type of data is returned for that locator. It then looks for something registered with the system that handles that type of data for the VIEW action, and starts it, including the data locator in the request.</p>

<p>The real key here is the MIME type. MIME stands for <a href="http://en.wikipedia.org/wiki/MIME">Multipurpose Internet Mail Extensions</a> - a standard for sending attachments over email. The MIME type (which is the part Android uses) is a way of describing certain kinds of data. That type is then used to look for an Activity that can do something with that data type. In this way, ContentProviders and Activities (or other IntentReceivers) are decoupled, meaning that a given Content URI might have a different ContentProvider to handle it, but could still use the same MIME type meaning that the same activity could be called upon to handle the resulting data.</p>

<h3>Linkify on a Wiki Word</h3>

<p>Using the above workflow, let's take a look at exactly how the process works in WikiNotes for Android:</p>

<p>First, Linkify is used to turn text matching the wiki word regular expression into a link that provides a Content URI for that wiki word, for example <code>content://com.google.android.wikinotes.db.wikinotes/wikinotes/ToDoList</code>.</p>

<p>When the user clicks on the wiki word link, Linkify invokes the VIEW action on the Content URI. At this point, the Android system takes over getting the Intent request to the correct activity.</p>

<p>Next, Android looks for a ContentProvider that has been registered with the system to handle URIs matching our Content URI format.</p>

<p>In our case, we have a definition inside our application in the <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/WikiNotes/AndroidManifest.xml">AndroidManifest.xml</a> file that reads:</p>

<pre>&lt;provider name="com.google.android.wikinotes.db.WikiNotesProvider" 
    android:authorities="com.google.android.wikinotes.db.wikinotes" /></pre>

<p>This establishes that we have a ContentProvider defined in our application that provides the "root authority": <code>com.google.android.wikinotes.db.wikinotes</code>. This is the first part of the Content URI that we create for a wiki word link. Root Authority is just another way of thinking about a descriptor that is registered with Android to allow requests for certain URLs to be routed to the correct class.</p>

<p>So, the whole definition is that a class called <code>com.google.android.wikinotes.db.WikiNotesProvider</code> is registered with the system as able to handle the <code>com.google.android.wikinotes.db.wikinotes</code> root authority (i.e. URIs starting with that identifier).</p>

<p>From here, Android takes the rest of the URI and present it to that ContentProvider. If you look at the <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/WikiNotes/src/com/google/android/wikinotes/db/WikiNotesProvider.java">WikiNotesProvider class</a> and scroll to the very bottom - the static block there, you can see the pattern definitions to match the rest of the URL.</p>

<p>In particular, take a look at the two lines:</p>

<pre>URI_MATCHER.addURI(WikiNote.WIKINOTES_AUTHORITY, "wikinotes", NOTES);
URI_MATCHER.addURI(WikiNote.WIKINOTES_AUTHORITY, "wikinotes/*", NOTE_NAME);</pre>

<p>These are the definitions of URIs that our ContentProvider recognizes and can handle. The first recognizes a full URI of <code>content://com.google.android.wikinotes.db.wikinotes/wikinotes</code> and associates that with a constant called NOTES. This is used elsewhere in the ContentProvider to provide a list of all of the wiki notes in the database when the URI is requested.</p>

<p>The second line uses a wildcard - '*' - to match a request of the form that Linkify will create, e.g. <code>content://com.google.android.wikinotes.db.wikinotes/wikinotes/ToDoList</code>. In this example, the * matches the ToDoList part of the URI and is available to the handler of the request, so that it can fish out the matching note for ToDoList and return it as the data. This also associates that match with a constant called NOTE_NAME, which again is used as an identifier elsewhere in the ContentProvider.</p>

<p>The other matches in this static block are related to forms of searching that have been implemented in the WikiNotes for Android application, and will be covered in later articles. Likewise, how the data is obtained from this matching pattern will be the subject of the next article.</p>

<p>For right now we are concerned with the MIME type for the URI. This is defined in the getType() method also in the <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/WikiNotes/src/com/google/android/wikinotes/db/WikiNotesProvider.java">WikiNotesProvider class</a> (about half way through the file). Take a quick look at this. The key parts for now are:</p>

<pre>case NOTES:
    return "vnd.android.cursor.<b>dir</b>/vnd.google.wikinote";</pre>

and

<pre>case NOTE_NAME:
    return "vnd.android.cursor.<b>item</b>/vnd.google.wikinote";</pre>

<p>These are the same constant names we defined in our pattern matchers. In the first case, that of the all notes URI, the MIME type returned is <code>vnd.android.cursor.dir/vnd.google.wikinote</code> which is like saying an Android list (dir) of Google wiki notes (the vnd bit is MIME speak for "vendor specific definition"). Likewise, in the case of a NOTE_NAME match, the MIME type returned is <code>vnd.android.cursor.item/vnd.google.wikinote</code> which is like saying an Android item of Google wiki notes.</p>

<p>Note that if you define your own MIME data types like this, the <code>vnd.android.cursor.dir</code> and <code>vnd.android.cursor.item</code> categories should be retained, since they have meaning to the Android system, but the actual item types should be changed to reflect your particular data type.</p>

<p>So far Android has been able to find a ContentProvider that handles the Content URI supplied by the Linkify Intent call, and has queried the ContentProvider to find out the MIME types for that URI. The final step is to find an activity that can handle the VIEW action for that MIME type. Take a look in the the <a href="http://code.google.com/p/apps-for-android/source/browse/trunk/WikiNotes/AndroidManifest.xml">AndroidManifest.xml file</a> again. Inside the WikiNotes activity definition, you will see:</p>

<pre>&lt;intent-filter&gt;
    &lt;action name="android.intent.action.VIEW"/&gt;
    &lt;category name="android.intent.category.DEFAULT"/&gt;
    &lt;category name="android.intent.category.BROWSABLE"/&gt;
    &lt;data mimetype="vnd.android.cursor.item/vnd.google.wikinote"/&gt;
&lt;/intent-filter&gt;</pre>

<p>This is the correct combination of matches for the VIEW action on a WikiNote type that is requested from the LINKIFY class. The DEFAULT category indicates that the WikiNotes activity should be treated as a default handler (a primary choice) for this kind of data, and the BROWSABLE category means it can be invoked from a "browser", in this case the marked-up Linkified text.</p>

<p>Using this information, Android can match up the VIEW action request for the WikiNotes data type with the WikiNotes activity, and can then use the WikiNotes activity to handle the request.</p>

<h3>Why do it like this?</h3>

<p>It's quite a trip through the system, and there is a lot to absorb here, but this is one of the main reasons I wanted to write WikiNotes in the first place. If you follow and understand the steps here, you'll have a good grasp of the whole Intents mechanism in Android, and how it helps loosely coupled activities cooperate to get things done.</p>

<p>In this case, we could have found another way to detect wiki words based on a regular expression, and maybe written our own handler to intercept clicks within the TextView and dig out the right data and display it. This would seem to accomplish the same functionality just as easily as using intents, so what is the advantage to using the full Intents mechanism?</p>

<p>In fact there are several advantages:</p>

<p>The most obvious is that because we are using the standard Intent based approach, we are not limited to just linking and navigating to other wiki notes. We get similar behavior to a number of other data types as well. For example, a telephone number or web URL in a wiki note will be marked up by Linkify, and using this same mechanism (VIEW action on the linked data type) the browser or dialer activities will be automatically fired.</p>

<p>It also means that each operation on a wiki note can be treated as a separate life cycle by our activity. We are not dealing with swapping data in and out of an existing activity - each activity works on a particular wiki note and that's all you have to worry about.</p>

<p>Another advantage is that we now have a public activity to handle VIEW actions in WikiNotes no matter where the request comes from. Another application could request to view a wiki note (perhaps without even knowing what kind of data it is) and our activity could start up and handle it.</p>

<p>The backstack is automatically maintained for you too. As you forward navigate through WikiNotes, Android maintains the history of notes visited, and so when you hit the back button you go back to the last note you were on. All this is free because we rely on the Android intents mechanism.</p>

<p>Finally, if you run WikiNotes for Android and then start DDMS to take a look at the Activity threads in the WikiNotes application while it is running, you can see that despite what you might think, letting Android manage the navigation is very efficient. Create a few linked notes, as many links deep as you like, and then follow them. If you follow links hundreds of notes deep, you will still only see a handful of WikiNotes activities. Android is managing the activities, closing the older ones as necessary and using the life cycle to swap data in and out.</p>

<h3>Next Time</h3>

<p>This was a long article, but necessarily so. It demonstrates the importance of the Intents mechanism and to reinforce the notion that it should be used whenever possible for forward navigation, even within a single application. Illustrating this is one of the primary reasons I wrote WikiNotes for Android in the first place.</p>

<p>In the next article we will look deeper into the ContentProvider and examine how it turns a Content URI into a row (or several rows) of data that can be used by an activity.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-1117773263990278238?l=android-developers.blogspot.com' alt='' /></div>]]></content:encoded>
			<wfw:commentRss>https://googledata.org/google-android/wikinotes-for-android-routing-intents/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Linkify your Text!</title>
		<link>https://googledata.org/google-android/linkify-your-text/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=linkify-your-text</link>
		<comments>https://googledata.org/google-android/linkify-your-text/#comments</comments>
		<pubDate>Thu, 13 Mar 2008 21:42:00 +0000</pubDate>
		<dc:creator><![CDATA[Dick Wall, Developer Advocate]]></dc:creator>
				<category><![CDATA[Google Android]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[Google Mobile]]></category>
		<category><![CDATA[google os]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[This is the first in a series of technical articles about WikiNotes for Android, part of the Apps for Android project.

This article covers the use of Linkify to turn ordinary text views into richer link-oriented content that causes Android intents to ...]]></description>
				<content:encoded><![CDATA[<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_eTH0Jfo94Ww/R9g-aqOYGdI/AAAAAAAAAB8/WKG7QdGUeXA/s1600-h/WikiNotes.png"><img style="margin: 0pt 10px 10px 0pt; float: left;" src="http://bp0.blogger.com/_eTH0Jfo94Ww/R9g-aqOYGdI/AAAAAAAAAB8/WKG7QdGUeXA/s320/WikiNotes.png" alt="" id="BLOGGER_PHOTO_ID_5176956399394494930" border="0"></a><p>This is the first in a series of technical articles about <a href="http://android-developers.blogspot.com/2008/03/announcing-apps-for-android.html">WikiNotes for Android</a>, part of the <a href="http://code.google.com/p/apps-for-android/">Apps for Android</a> project.</p>

<p>This article covers the use of Linkify to turn ordinary text views into richer link-oriented content that causes Android intents to fire when a link is selected.</p>

<p><strong>Linkify</strong>: The <a title="Linkify class" href="http://code.google.com/android/reference/android/text/util/Linkify.html">Linkify class</a> in the SDK is perfect for creating a wiki note pad. This class lets you specify a <a title="regular expression" href="http://en.wikipedia.org/wiki/Regular_expression">regular expression</a> to match, and a scheme to prepend. The scheme is a string that, when the matched text is added, forms a Content URI to allow the correct data to be looked up.</p>

<p>For example, in our case we want to look for a regular expression match for a WikiWord (that is, a word with <a title="word with camel case" href="http://en.wikipedia.org/wiki/CamelCase">camel case</a> and no spaces). Linkify can then turn this into a Content URI - something like <code>>content://com.google.android.wikinotes.db.wikinotes/wikinotes/WikiWord</code> which can then be used to locate the correct wiki page from a <a title="content provider" href="http://code.google.com/android/reference/android/content/ContentProvider.html">content provider</a>.</p>

<p>As a bonus, the Linkify class also defines several default matches, in particular it is able to turn web URLs, email addresses and telephone numbers into active links which fire Android intents automatically.</p>

<p>Linkify can be passed any TextView in your application, and will take care of creating the links and enabling their "clickability" for you.</p>

<p><strong>Default Linkify</strong>: Using the set of default active link options is very straightforward - simply pass it a handle to a TextView with content in it, and the <code>Linkify.ALL</code> flag:</p>

<pre>TextView noteView = (TextView) findViewById(R.id.noteview);
noteView.setText(someContent);
Linkify.addLinks(noteView, Linkify.ALL);</pre>

<p>and that's it. The Linkify.ALL flag applies all of the predefined link actions, and the TextView will be immediately updated with a set of active links which, if you select them, fire default intents for the actions (e.g. a web URL will start the browser with that URL, a telephone number will bring up the phone dialer with that number ready to call, etc.).</p>

<p><strong>Custom Linkify</strong>: So what about our WikiWord? There is no pre-defined action for that, so it needs to be defined and associated with a scheme.</p>

<p>The first task is to defined a regular expression that matches the kind of WikiWords we want to find. The regex in this case is:</p>

<pre>\b[A-Z]+[a-z0-9]+[A-Z][A-Za-z0-9]+\b</pre>

<p>Obvious no? Well actually this is equivalent to the following description: "Starting with a word boundary (the \b) find at least one upper case letter, followed by at least one lower case letter or a numeric digit, followed by another upper case letter, and then any mix of upper case, lower case or numeric until the next word boundary (the final \b)". Regular expressions are not very pretty, but they are an extremely concise and accurate way of specifying a search pattern.</p>

<p>We also need to tell Linkify what to do with a match to the WikiWord. Linkify will automatically append whatever is matched to a scheme that is supplied to it, so for the sake of argument let's assume we have a <a title="ContentProvider" href="http://code.google.com/android/reference/android/content/ContentProvider.html">ContentProvider</a> that matches the following content URI:</p>

<pre>content://com.google.android.wikinotes.db.wikinotes/wikinotes/WikiWord</pre>

<p>The WikiWord part will be appended by Linkify when it finds a match, so we just need the part before that as our scheme.</p>

<p>Now that we have these two things, we use Linkify to connect them up:</p>

<pre>Pattern wikiWordMatcher = Pattern.compile("\\b[A-Z]+[a-z0-9]+[A-Z][A-Za-z0-9]+\\b");
String wikiViewURL =    "content://com.google.android.wikinotes.db.wikinotes/wikinotes/";
Linkify.addLinks(noteView, wikiWordMatcher, wikiViewURL);</pre>

<p>Note that the \b's had to be escaped with double backslashes for the Java Pattern.compile line.</p>

<p>Linkify can be used multiple times on the same view to add more links, so using this after the Default Linkify call means that the existing active links will be maintained and the new WikiWords will be added. You could define more Linkify actions and keep applying them to the same TextView if you wanted to.</p>

<p>Now, if we have a WikiWord in the TextView, let's say <code>MyToDoList</code>, Linkify will turn it into an active link with the content URI:</p>

<pre>content://com.google.android.wikinotes.db.wikinotes/wikinotes/MyToDoList</pre> 

<p>and if you click on it, Android will fire the default intent for that content URI.</p>

<p>For this to all work, you will need a ContentProvider that understands that Content URI, and you will need a default activity capable of doing something with the resulting data. I plan to cover these in future blog entries (and soon). In fact, the whole Wiki Note Pad application is currently undergoing some clean up and review, and will then hopefully be released as a sample application.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-3894647463857191023?l=android-developers.blogspot.com' alt='' /></div>]]></content:encoded>
			<wfw:commentRss>https://googledata.org/google-android/linkify-your-text/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="" length="" type="" />
		</item>
		<item>
		<title>Announcing: Apps for Android</title>
		<link>https://googledata.org/google-android/announcing-apps-for-android/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=announcing-apps-for-android</link>
		<comments>https://googledata.org/google-android/announcing-apps-for-android/#comments</comments>
		<pubDate>Tue, 04 Mar 2008 19:01:00 +0000</pubDate>
		<dc:creator><![CDATA[Dick Wall, Developer Advocate]]></dc:creator>
				<category><![CDATA[Google Android]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[Google Mobile]]></category>
		<category><![CDATA[google os]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[We are pleased to announce that a new open source project has been created on Google code hosting called apps-for-android. Our goal is to share some sample applications that demonstrate different aspects of the Android platform.

The first application ...]]></description>
				<content:encoded><![CDATA[<p><img style="margin: 0pt 10px 10px 0pt; float: left;" src="http://bp1.blogger.com/_eTH0Jfo94Ww/R8iSJlMBUiI/AAAAAAAAAB0/LSsL25R2Vzk/s320/Picture+1.png" alt="Screenshot of WikiNotes for Android" border="0" />We are pleased to announce that a new open source project has been created on Google code hosting called <a title="apps-for-android" href="http://code.google.com/p/apps-for-android/">apps-for-android</a>. Our goal is to share some sample applications that demonstrate different aspects of the Android platform.</p>

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

<p>For anyone not familiar with the concept of a wiki, it is a simple way to link up pages of information using WikiWords (words that use <a title="CamelCase" href="http://en.wikipedia.org/wiki/CamelCase">CamelCase</a>). For example, in the previous sentence, both WikiWords and CamelCase would become live links in a Wiki, and would take you to pages of information.</p>

<p>WikiNotes for Android is a form of wiki known as a <a title="personal wiki" href="http://en.wikipedia.org/wiki/Personal_wiki">personal wiki</a>. These run on desktops or (in this case) mobile computing devices, and many people like them. They bring a bit more structure to your notes than just a list of subjects. You can choose to link notes or pages up in any manner you like.</p>

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

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

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

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

<ul>
    <li>Multiple Activities in an Application (View, Edit, Search, etc.)</li>
    <li>Default intent filters for View/Edit/Search based on MIME types</li>
    <li><a href="http://code.google.com/android/intro/lifecycle.html">Life cycle of Activities</a></li>
    <li>Message passing via <a href="http://code.google.com/android/reference/android/os/Bundle.html">Bundles</a> in <a href="http://code.google.com/android/reference/android/content/Intent.html">Intents</a></li>
    <li>Use of <a href="http://code.google.com/android/reference/android/text/util/Linkify.html">Linkify</a> to add Intent-firing links to text data</li>
    <li>Using Intents within an application</li>
    <li>Using Intents to use an Activity within another application</li>
    <li><a href="http://code.google.com/android/devel/data/contentproviders.html#creatingacontentprovider">Writing a custom ContentProvider</a> that implements search by note title</li>
    <li>Registration of ReST-like URIs to match titles, and do contents searches</li>
    <li><a href="http://code.google.com/android/devel/data/databases.html">SQLite implementations</a> for insert, retrieve, update, delete and search</li>
    <li>UI layout and creation for multiple activities</li>
    <li><a href="http://code.google.com/android/kb/commontasks.html#addmenuitems">Menus</a> and keyboard shortcuts</li>
</ul>

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

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

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

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

<p>Happy wiki-ing.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-232704926430953730?l=android-developers.blogspot.com' alt='' /></div>]]></content:encoded>
			<wfw:commentRss>https://googledata.org/google-android/announcing-apps-for-android/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="" length="" type="" />
		</item>
		<item>
		<title>On the Road with Android</title>
		<link>https://googledata.org/google-android/on-the-road-with-android/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=on-the-road-with-android</link>
		<comments>https://googledata.org/google-android/on-the-road-with-android/#comments</comments>
		<pubDate>Wed, 19 Dec 2007 16:22:00 +0000</pubDate>
		<dc:creator><![CDATA[Dick Wall, Developer Advocate]]></dc:creator>
				<category><![CDATA[Google Android]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[Google Mobile]]></category>
		<category><![CDATA[google os]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[This week finds me at the Google offices in jolly old London after a quick dash out to Belgium last week. I have had the chance to meet the Mobile developers based here in London and give them an introduction to Android, as well as do the same for 70is...]]></description>
				<content:encoded><![CDATA[<p>This week finds me at the Google offices in jolly old London after a quick dash out to Belgium last week<a href="http://www.javapolis.com/confluence/display/JP07/Home"></a>. I have had the chance to meet the Mobile developers based here in London and give them an introduction to Android, as well as do the same for 70ish external developers from the London area. It has been a fun week of Android hackathons, brainstorming for Android application ideas and occasionally finding bugs and holes in the documentation.</p>

<p>It has been really valuable spending enough time with a group of motivated developers to move beyond the first steps and into real development work. A couple of my temporary office mates here are already well on their way to implementing a general puzzle application for Android. It will enable you to choose your favorite puzzle engines to install and then play a selection of puzzles downloaded on demand from a server &ndash; quite an ambitious project for a first try, but these guys are pretty determined and hope to have a prototype of the first puzzle (<a href="http://en.wikipedia.org/wiki/Battleship_%28puzzle%29">battleships</a>) working before I hit the road again on Friday. They are also treating the implementation as a chance to learn the architecture: learning the right way to use the architectural pieces in Android rather than opting for the quick and easy shortcuts, which is the best way to really learn a new platform in my experience (don't compromise, be true to your vision).</p>

<p>The week is far from over yet, with another internal and external hackathon planned, and as many more ideas sessions as we can cram in.</p>

<p>As for the London offices &ndash; well they are fantastic. Right in the middle of everything, <a href="http://en.wikipedia.org/wiki/Jaffa_Cake">Jaffa Cakes</a> in the kitchens (if you don't know what a Jaffa Cake is, or how to eat one in particular, check out this <a href="http://www.youtube.com/watch?v=26YNOdiykq0">informative video on the subject</a>). There are also a wealth of pubs within easy walking of the offices, a welcome feature for an ex-pat like me.</p>

<p>With the holidays getting close, don't forget that a new SDK version was announced last week with several improvements. It might be worth grabbing that before taking off for the holidays, just in case you get the urge to do some Android coding while trying to work out if you ate just a bit too much for dinner.</p>

<p>Happy Holidays...</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-4102690509658602216?l=android-developers.blogspot.com' alt='' /></div>]]></content:encoded>
			<wfw:commentRss>https://googledata.org/google-android/on-the-road-with-android/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google Developer Podcast: Android</title>
		<link>https://googledata.org/google-android/google-developer-podcast-android/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=google-developer-podcast-android</link>
		<comments>https://googledata.org/google-android/google-developer-podcast-android/#comments</comments>
		<pubDate>Wed, 05 Dec 2007 18:49:00 +0000</pubDate>
		<dc:creator><![CDATA[Dick Wall, Developer Advocate]]></dc:creator>
				<category><![CDATA[Google Android]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[Google Mobile]]></category>
		<category><![CDATA[google os]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[

Dianne Hackborn and Jason Parks are two of the architects on the Android engineering team, and in this podcast they talk to us about the Android platform from a technical perspective.

Dianne and Jason share a background at both Be and PalmSource, an...]]></description>
				<content:encoded><![CDATA[<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp0.blogger.com/_eTH0Jfo94Ww/R1b1c5mFa-I/AAAAAAAAAAc/0bp6U7yE0tQ/s1600-h/GoogleDevPodcastLogo.png"><img style="margin: 0px 20px 10px 0px; float: left; cursor: pointer;" src="http://bp0.blogger.com/_eTH0Jfo94Ww/R1b1c5mFa-I/AAAAAAAAAAc/0bp6U7yE0tQ/s320/GoogleDevPodcastLogo.png" alt="" id="BLOGGER_PHOTO_ID_5140565901535701986" border="0" /></a>

<p>Dianne Hackborn and Jason Parks are two of the architects on the Android engineering team, and <a href="http://google-code-updates.blogspot.com/2007/12/google-developer-podcast-episode-twelve.html">in this podcast</a> they talk to us about the Android platform from a technical perspective.</p>

<p>Dianne and Jason share a background at both Be and PalmSource, and talk about how that experience has been applied to Android. Other topics covered include:</p>

<ul>
    <li>Some history behind the project</li>
    <li>The high level architecture of Android. For example, how Linux processes handle the VM and manage security (the VM doesn't handle it)</li>
    <li>Details on the Dalvik VM and how it is optimized for small devices</li>
    <li>The architecture: From Intents to Views to Permissions and more</li>
    <li>How XML is slow, but the tools convert the XML to a nicer format for you</li>
    <li>The tooling and steps for building an application on Android</li>
    <li>How so many objects have a URL, and how the environment is like a mini-SOA (Services across processes instead of across the network)</li>
    <li>Thoughts on how you program for small devices, and things to watch out for if you move from the desktop</li>
    <li>The control, or lack of control that you have over the application lifecycle</li>
    <li>"Everything you do drains the battery"</li>
    <li>The thread story: they exist, you don't have to deal with them if you don't want to, and the UI</li>
    <li>Using XMPP for messaging</li>
</ul>

<p>You can <a href="http://google-developer-podcast.googlecode.com/files/googledev012.mp3" rel="enclosure">download the episode directly</a>, or <a href="http://feeds.feedburner.com/GoogleDeveloperPodcast">subscribe to the show</a> (<a href="http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewPodcast?id=257272708">click here for iTunes one-click subscribe</a>).</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-6826012721044439506?l=android-developers.blogspot.com' alt='' /></div>]]></content:encoded>
			<wfw:commentRss>https://googledata.org/google-android/google-developer-podcast-android/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="" length="" type="" />
		</item>
		<item>
		<title>A Maze of Twisty Little Passages</title>
		<link>https://googledata.org/google-android/a-maze-of-twisty-little-passages/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=a-maze-of-twisty-little-passages</link>
		<comments>https://googledata.org/google-android/a-maze-of-twisty-little-passages/#comments</comments>
		<pubDate>Thu, 29 Nov 2007 15:49:00 +0000</pubDate>
		<dc:creator><![CDATA[Dick Wall, Developer Advocate]]></dc:creator>
				<category><![CDATA[Google Android]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[Google Mobile]]></category>
		<category><![CDATA[google os]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[

The end of last week was Thanksgiving in the US, the tradition is to be with family, eat too much food and watch football (not necessarily in that order).

Apparently some folks took the chance to work on Android projects too. We are highlighting a f...]]></description>
				<content:encoded><![CDATA[<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp1.blogger.com/_eTH0Jfo94Ww/R07f6ULYxBI/AAAAAAAAAAU/FkaAuXLw7V8/s1600-h/twisty-screenshot.png"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp1.blogger.com/_eTH0Jfo94Ww/R07f6ULYxBI/AAAAAAAAAAU/FkaAuXLw7V8/s320/twisty-screenshot.png" alt="" id="BLOGGER_PHOTO_ID_5138290417818190866" border="0" /></a>

<p>The end of last week was Thanksgiving in the US, the tradition is to be with family, eat too much food and watch football (not necessarily in that order).</p>

<p>Apparently some folks took the chance to work on Android projects too. We are highlighting a few of the projects that caught our eye.</p>

<p>One of the coming of age rituals of any new platform is the porting of the <a href="http://en.wikipedia.org/wiki/Z-machine">Z-machine</a> &ndash; the interpreter used in the <a href="http://en.wikipedia.org/wiki/Zork_I">Zork</a> series of games from Infocom. Now Android has the Z-machine thanks to </span>      <a href="http://code.google.com/u/sussman/">sussman</a> and <a href="http://code.google.com/u/mariusm/">mariusm</a>. The project, called <a href="http://code.google.com/p/twisty/">Twisty</a>, is available on Google code hosting. Thanks for the lost productivity you guys.</p>

<p>Testing is also a hot topic on our Google groups. While <a href="http://code.google.com/android/reference/junit/framework/package-summary.html">JUnit</a> is bundled with the Android SDK to make it possible to do unit testing, there are many other kinds of testing, like automated acceptance testing. <a href="http://code.google.com/p/android-positron/">Positron</a> builds on the <a href="http://code.google.com/android/reference/android/app/Instrumentation.html">Android instrumentation</a> features from the SDK to make automated acceptance testing of Android applications possible. The author, </span>      <a href="http://code.google.com/u/phil.h.smith/">phil.h.smith</a>, has a <a href="http://code.google.com/p/android-positron/">pretty good introduction</a> on how to use Positron as well.</p>

<p>Plugins for other IDEs are another favorite on the Android Google groups. While there are only rumblings about a NetBeans plugin at present, the <a href="http://code.google.com/p/idea-android/">idea-android</a> project already has an early release for IntelliJ IDEA thanks to <a href="http://code.google.com/u/aefimov.box/">aefimov.box</a> and <a href="http://code.google.com/u/intelliyole/">intelliyole</a>.</p>

<p>Dion Almaer also <a href="http://google-code-updates.blogspot.com/2007/11/chronoscope-2-2-5-with-gwt-and-android.html">picked up on a crossover GWT/Android project</a> which looks pretty amazing too. <a href="http://timepedia.org/chronoscope/">Chronoscope</a> is an open source charting and visualization library written in GWT. The team were able to take the library, and with <a href="http://timepedia.blogspot.com/2007/11/gwt-and-android-marriage-made-in-heaven.html">8 hours of playing with Android</a>, had a port to the Android platform.</p>

<p>Of course, there are many more Android projects springing up all the time, as a <a href="http://code.google.com/hosting/search?q=label:android">search of the android label on Google code hosting</a> will demonstrate. It's great to see all this activity just a couple of weeks after the SDK was released.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-5411977571587017938?l=android-developers.blogspot.com' alt='' /></div>]]></content:encoded>
			<wfw:commentRss>https://googledata.org/google-android/a-maze-of-twisty-little-passages/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="" length="" type="" />
		</item>
		<item>
		<title>A Stitch in Time</title>
		<link>https://googledata.org/google-android/a-stitch-in-time/?utm_source=rss&#038;utm_medium=rss&#038;utm_campaign=a-stitch-in-time</link>
		<comments>https://googledata.org/google-android/a-stitch-in-time/#comments</comments>
		<pubDate>Wed, 21 Nov 2007 00:42:00 +0000</pubDate>
		<dc:creator><![CDATA[Dick Wall, Developer Advocate]]></dc:creator>
				<category><![CDATA[Google Android]]></category>
		<category><![CDATA[android]]></category>
		<category><![CDATA[Google Mobile]]></category>
		<category><![CDATA[google os]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[

Background: While developing my first useful (though small) application for Android, which was a port of an existing utility I use when podcasting, I needed a way of updating a clock displayed on the UI at regular intervals, but in a lightweight and ...]]></description>
				<content:encoded><![CDATA[<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://bp3.blogger.com/_eTH0Jfo94Ww/R0OJBkLYxAI/AAAAAAAAAAM/IRtvWckNk5Y/s1600-h/JFlubber.png"><img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://bp3.blogger.com/_eTH0Jfo94Ww/R0OJBkLYxAI/AAAAAAAAAAM/IRtvWckNk5Y/s320/JFlubber.png" alt="" id="BLOGGER_PHOTO_ID_5135098660116808706" border="0" /></a>

<p><strong>Background</strong>: While developing my first useful (though small) application for Android, which was a port of an existing utility I use when podcasting, I needed a way of updating a clock displayed on the UI at regular intervals, but in a lightweight and CPU efficient way.</p>

<p><strong>Problem</strong>: In the original application I used java.util.Timer to update the clock, but that class is not such a good choice on Android. Using a Timer introduces a new thread into the application for a relatively minor reason. Thinking in terms of mobile applications often means re-considering choices that you might make differently for a desktop application with relatively richer resources at its disposal. We would like to find a more efficient way of updating that clock.</p>

<p><strong>The Application</strong>: The rest of the story of porting the application will be detailed in future blog entries, but if you are interested in the application in question and the construction of it, you can read about it in a not-so-recent Developer.com article about using Matisse (a GUI builder for Swing). The original application is a Java Swing and SE application. It is like a stopwatch with a lap timer that we use when recording podcasts; when you start the recording, you start the stopwatch. Then for every mistake that someone makes, you hit the flub button. At the end you can save out the bookmarked mistakes which can be loaded into the wonderful <a href="http://audacity.sourceforge.net/" title="Audacity">Audacity</a> audio editor as a labels track. You can then see where all of the mistakes are in the recording and edit them out.</p>

<p>The article describing it is: <a href="http://www.developer.com/java/ent/print.php/3589961" title="http://www.developer.com/java/ent/print.php/3589961">http://www.developer.com/java/ent/print.php/3589961</a></p>

<p>In the original version, the timer code looked like this:</p>

<pre>class UpdateTimeTask extends TimerTask {
   public void run() {
       long millis = System.currentTimeMillis() - startTime;
       int seconds = (int) (millis / 1000);
       int minutes = seconds / 60;
       seconds     = seconds % 60;

       timeLabel.setText(String.format("%d:%02d", minutes, seconds));
   }
}</pre><p>And in the event listener to start this update, the following Timer() instance is used:
</p><pre>if(startTime == 0L) {
   startTime = evt.getWhen();
   timer = new Timer();
   timer.schedule(new UpdateTimeTask(), 100, 200);
}</pre>

<p>In particular, note the 100, 200 parameters. The first parameter means wait 100 ms before running the clock update task the first time. The second means repeat every 200ms after that, until stopped. 200 ms should not be too noticeable if the second resolution happens to fall close to or on the update. If the resolution was a second, you could find the clock sometimes not updating for close to 2 seconds, or possibly skipping a second in the counting, it would look odd).</p>

<p>When I ported the application to use the Android SDKs, this code actually compiled in Eclipse, but failed with a runtime error because the Timer() class was not available at runtime (fortunately, this was easy to figure out from the error messages). On a related note, the String.format method was also not available, so the eventual solution uses a quick hack to format the seconds nicely as you will see.</p>

<p>Fortunately, the role of Timer can be replaced by the android.os.Handler class, with a few tweaks. To set it up from an event listener:</p>

<pre>private Handler mHandler = new Handler();

...

OnClickListener mStartListener = new OnClickListener() {
   public void onClick(View v) {
       if (mStartTime == 0L) {
            mStartTime = System.currentTimeMillis();
            mHandler.removeCallbacks(mUpdateTimeTask);
            mHandler.postDelayed(mUpdateTimeTask, 100);
       }
   }
};</pre>

<p>A couple of things to take note of here. First, the event doesn't have a .getWhen() method on it, which we handily used to set the start time for the timer. Instead, we grab the System.currentTimeMillis(). Also, the Handler.postDelayed() method only takes one time parameter, it doesn't have a "repeating" field. In this case we are saying to the Handler "call mUpdateTimeTask() after 100ms", a sort of fire and forget one time shot. We also remove any existing callbacks to the handler before adding the new handler, to make absolutely sure we don't get more callback events than we want.</p>

<p>But we want it to repeat, until we tell it to stop. To do this, just put another postDelayed at the tail of the mUpdateTimeTask run() method. Note also that Handler requires an implementation of Runnable, so we change mUpdateTimeTask to implement that rather than extending TimerTask. The new clock updater, with all these changes, looks like this:</p>

<pre>private Runnable mUpdateTimeTask = new Runnable() {
   public void run() {
       final long start = mStartTime;
       long millis = SystemClock.uptimeMillis() - start;
       int seconds = (int) (millis / 1000);
       int minutes = seconds / 60;
       seconds     = seconds % 60;

       if (seconds &lt; 10) {
           mTimeLabel.setText("" + minutes + ":0" + seconds);
       } else {
           mTimeLabel.setText("" + minutes + ":" + seconds);            
       }
     
       mHandler.postAtTime(this,
               start + (((minutes * 60) + seconds + 1) * 1000));
   }
};</pre>

<p>and can be defined as a class member field.</p>

<p>The if statement is just a way to make sure the label is set to 10:06 instead of 10:6 when the seconds modulo 60 are less than 10 (hopefully String.format() will eventually be available). At the end of the clock update, the task sets up another call to itself from the Handler, but instead of a hand-wavy 200ms before the update, we can schedule it to happen at a particular wall-clock time &mdash; the line: start + (((minutes * 60) + seconds + 1) * 1000) does this.</p>

<p>All we need now is a way to stop the timer when the stop button is pressed. Another button listener defined like this:</p>

<pre>OnClickListener mStopListener = new OnClickListener() {
   public void onClick(View v) {
       mHandler.removeCallbacks(mUpdateTimeTask);
   }
};</pre>

<p>will make sure that the next callback is removed when the stop button is pressed, thus interrupting the tail iteration.</p>

<p>Handler is actually a better choice than Timer for another reason too. The Handler runs the update code as a part of your main thread, avoiding the overhead of a second thread and also making for easy access to the View hierarchy used for the user interface. Just remember to keep such tasks small and light to avoid slowing down the user experience.</p>

<p>So that's it for the first of what will be a series of Android tips. Hopefully this will save you a little head scratching on what will probably be a fairly common thing to want to do (i.e. make something happen or update at regular intervals in a lightweight way in your application). There is plenty of more material from my experience of porting this very simple application which will be covered in some of the future "tips" articles. There are some other great tips being discussed as well as an opportunity ask questions at the <a title="Android Developer Forum" href="http://groups.google.com/group/android-developers"> Android Developers Discussion Group</a>.</p><div class="blogger-post-footer"><img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/6755709643044947179-7739456644131925915?l=android-developers.blogspot.com' alt='' /></div>]]></content:encoded>
			<wfw:commentRss>https://googledata.org/google-android/a-stitch-in-time/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="" length="" type="" />
		</item>
	</channel>
</rss>
