<?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>Brad Abrams</title>
	<atom:link href="http://bradabrams.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://bradabrams.com</link>
	<description>Champion of the Obvious</description>
	<lastBuildDate>Sat, 08 Jun 2013 13:50:52 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.5.1</generator>
		<item>
		<title>Google I/O 2013 Session Overview: From Nothing to Nirvana in Minutes: Cloud Backend for your Android Application &#8211; Building Geek Serendipity</title>
		<link>http://bradabrams.com/2013/05/google-io-2013-session-overview-from-nothing-to-nirvana-in-minutes-cloud-backend-for-your-android-application-building-geek-serendipity/</link>
		<comments>http://bradabrams.com/2013/05/google-io-2013-session-overview-from-nothing-to-nirvana-in-minutes-cloud-backend-for-your-android-application-building-geek-serendipity/#comments</comments>
		<pubDate>Mon, 20 May 2013 20:53:06 +0000</pubDate>
		<dc:creator>Brad Abrams</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://bradabrams.com/?p=157</guid>
		<description><![CDATA[David Chandler and I just finished our session on cloud-enabling your Android applications at Google I/O 2013. the video of the talk is posted you YouTube. the source code for the demo published on github the Geek Serendipity application we created is on the Play Store Here is the Geek Serendipity app we built.  It enables [...]]]></description>
				<content:encoded><![CDATA[<div style="float: left;" ><g:plusone  position="prepend" size="standard" count="1" href="http://bradabrams.com/2013/05/google-io-2013-session-overview-from-nothing-to-nirvana-in-minutes-cloud-backend-for-your-android-application-building-geek-serendipity/" text="Google I/O 2013 Session Overview: From Nothing to Nirvana in Minutes: Cloud Backend for your Android Application &#8211; Building Geek Serendipity" ></g:plusone></div>
<p class="c2"><a href="http://turbomanage.wordpress.com/" target="_blank">David Chandler</a> and I just finished our session on<span class="c4"><a class="c3" href="https://developers.google.com/events/io/sessions/333508149"> cloud-enabling your Android applications </a></span>at Google I/O 2013.</p>
<ol class="c5" start="1">
<li class="c2 c6"><span class="c4"><a class="c3" href="https://developers.google.com/events/io/sessions/333508149">the video</a></span><span> of the talk is posted you YouTube.</span></li>
<li class="c6 c2"><span>the source code for the demo </span><span class="c4"><a class="c3" href="https://github.com/bradabrams/GeekSerendipity-io13">published on github </a></span><span><br />
</span></li>
<li class="c6 c2"><span>the Geek Serendipity application we created is </span><span class="c4"><a class="c3" href="https://play.google.com/store/apps/details?id=com.turbomanage.sample.geekwatch&amp;rdid=com.turbomanage.sample.geekwatch&amp;rdot=1&amp;feature=md">on the Play Store </a></span></li>
</ol>
<p class="c2"><span>Here is the Geek Serendipity app we built.  It enables you to share your Geekly interest and see what geeks are around you. In the bottom we are showing your lat long and a geohash which we use to find who is “near” you. </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/drawings/image?id=sVuv5dWopuLt_VQSDIlknLg&amp;rev=1&amp;h=574&amp;w=530&amp;ac=1" width="442" height="574" /></p>
<p class="c2"><span>There are four things that are important to me when we  started this application. </span></p>
<ol class="c5" start="1">
<li class="c9 c6 c2"><span class="c7"><strong>Client Focused Dev</strong> &#8211; we didn’t want to manage servers, deal with security patches, or figure out availability zones. As an android guy, David wanted to focus 95% of my energy on building an amazing android app rather than writing server code. </span></li>
<li class="c9 c6 c2"><span class="c7"><strong>Location Saved to Cloud</strong> &#8211; We need to share locations between users and that means we do need a cloud backend to share this state. </span></li>
<li class="c6 c2 c9"><span class="c7"><strong>Update Geeks Nearby Live</strong> &#8211; We like android apps that living and active. If I look at the app while I drink my soy latte double cappuccino I’d like to see geeks pop in as they come near by. </span></li>
<li class="c6 c2"><span class="c7"><strong>Avoid typing password</strong> &#8211; We don’t want my users to have to remember and type in passwords on the phone. Tiny screen, tiny keyboards and passwords don’t mix. </span></li>
</ol>
<p class="c2"><span>At Google I/O we are announcing the </span><span class="c4"><a class="c3" href="https://developers.google.com/cloud/samples/mbs/">Mobile Backend </a></span><span class="c4"><a class="c3" href="https://developers.google.com/cloud/samples/mbs/">St</a></span><span class="c4"><a class="c3" href="https://developers.google.com/cloud/samples/mbs/">arter.</a></span><span> This is a starter application that makes it easy for you to get started building your mobile backend in the cloud! We have focused on making it a no server code solution. So you can ship a production application with no server coding required. Of course if you’d like to download the server code you can customize it as much as you need. We have also added GCM support and continuous queries so you can register a query that will call you back at anytime in the future when it is true. All this with built in Google Authentication.</span></p>
<p class="c2"><span>With this starter application, you don’t need to write any server code to get the basic experience we are showing up and running. Right out of the box, you get two things. A backend that stores your data with </span><span class="c4"><a class="c3" href="https://cloud.google.com/products/app-engine">App Engine</a></span><span> and a front end in android that makes it trivially easily to access that data. </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=15I_OpCyMB3UKALUIn6rdvdtM1PaK_Y3oerQ0" width="614" height="461" /></p>
<p class="c2"><span>We have taken that very cool Mobile Backend Starter and extended it for our Geek Serendipity use case. For the data, we are storing the geohash of the location and last reported timestamp for each user. We are also using</span><span class="c4"><a class="c3" href="http://developer.android.com/google/gcm/index.html">Google Cloud Messaging for Android </a></span><span>and the continuous queries to keep each client up to date with where all the geeks are. And Finally we are using </span><span class="c4"><a class="c3" href="https://developers.google.com/maps/documentation/android/">Google Maps V2 </a></span><span>to display the locations.</span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1n8CAYh_q9pn5LMyuf6JKn_WEhVZ76lyWkHP8" width="614" height="461" /></p>
<p class="c2"><strong><span class="c8">Part One &#8212; Basic Cloud Connected App</span></strong></p>
<p class="c2"><span>To get started, go to the new </span><span class="c4"><a class="c3" href="http://cloud.google.com/console">Google Cloud Console</a></span><span>. This console will be the one stop shop for all your Google cloud developers needs from getting access to Google APIs such as Google Maps to accessing computing resources such as Google Compute Engine and App Engine. </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1DjTQAU0n4zYVufrH0zXtbHgwK1_1TVHDjtKd" width="689" height="367" /></p>
<p class="c2"><span>Here is our new Cloud Console. From here I can create and manage all my cloud backends. From here you can create a new project. We give the project a name, then we have an app ID that is used for programmatic access. Notice this is our startup name generator&#8230; let’s see if we can get a good one&#8230; I like dauntless-bay-213, but I’ll change it to geek-serendipity.</span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1IqzvdXVawhWFC-r2ETUQk5Aw5SrLm_GECmRS" width="451" height="201" /></p>
<p class="c2"><span>Now I have a project, we need to mobile enable it. To do that I will just click deploy here on this mobile backend. What this does is install the mobile backend starter on the app engine application </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=18bHxhNSWkQruqDENk1dcpu57vht0IRbP0KsU" width="412" height="106" /></p>
<p class="c2"><span>Clicking on deploy, starts the magic! </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=11xICxm5EweJ-yqVSGuAGQx_sYJNe-ojPmmDA" width="499" height="221" /></p>
<p class="c2"><span>Step number 2 is to check out the settings for this backend. By clicking on the settings button there we are navigated to the setting page for the mobile backend. </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=19QtpiT8mx5ziaVqIAGaN8BPPzd2DKV3zcuD3" width="629" height="368" /></p>
<p class="c2"><span>By default this is set to locked down, no http requests will be accepted. We will move it to Open, this will make it so that anyone unauthorized client can access my backend, so this mode is suggested only for development. </span></p>
<p class="c2"><span>Step #3 is to download the source code for the android client. We have pre-built a sample guestbook application that is intended for you to use as a way to get started. At the talk, we used Android with the </span><span class="c4"><a class="c3" href="http://developer.android.com/tools/sdk/eclipse-adt.html">latest version of the ADT</a></span><span> installed. </span></p>
<p class="c2"><span> Just import this into eclipse (this works just as well in Android Studio). </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1FRZA3YDltHu1e5H3B_vF5nQk1pps_JaYGlha" width="319" height="332" /></p>
<p class="c2">Then select the unzipped directory we downloaded&#8230;</p>
<p class="c2">&#8230;and import this project.</p>
<p class="c2"><img alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1Dd2LMP6lmXMrARh9IwZ433AJtOl6HbasmzH0" width="505" height="344" /></p>
<p class="c2"><span> As you can see we have a few libraries here, then a main guestbook application.</span></p>
<p class="c2"> <img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1zfemueMh6cpQbkWzQm1PaCza21HpYwW5LLpz" width="384" height="512" /></p>
<p class="c2"><span>We can open up Const.java and paste in our appid we gave when we created this app. </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1l94BaHUs_ZDgRc0UjxSXF8zL3q4os4_EJ9R5" width="460" height="220" /></p>
<p class="c2"><span>And set the project Id to the one we gave when we created the app.</span></p>
<pre class="brush: java; title: ; notranslate">
 public static final String PROJECT_ID = &quot;geek-serendipity&quot;;;
</pre>
<p class="c2"><span>As you can see here, we have given the project ID on the client and that is the</span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1E4hPoVkljTAw7pi2Wrutxh6Fw1TBkD-qgv9a" width="450" height="143" /></p>
<p class="c2"><span>Now we can run it and enter a few messages.</span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1Rh-hZB3ZoI17-F5bo2ngCk57Pf2CgdAAh5_W" width="323" height="167" /></p>
<p class="c2"><span>If we flip over to the Cloud Console and look at the Datastore, we see our two messages </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=13lFQzzsL9FGp8gZ20B-vxds5JC8B_Rc91tIK" width="666" height="331" /></p>
<p class="c2"><span>Wow, that is pretty cool&#8230; 5 mins into this demo we already have a cloud connected application that will store it’s state in the cloud so it works perfectly as users change devices. </span></p>
<p class="c2"><span>What we have done so far is spin up a backend on app engine, download the client, add the project ID and run it. </span></p>
<p class="c2"><span class="c8"><strong>Part Two &#8212; Push Notifications</strong> </span></p>
<p class="c2"><span>We are going to want a vibrant app that does live updates. Let’s see how we can work live updates into this application. A naive way to do this would be poll every few minutes by calling back to the server and see if there are new items. While this is a common technique the biggest problem is battery life, network traffic and load on your server. Not to mention latency the user sees for new messages arriving.</span></p>
<p class="c2"><span>Google has already established a channel to communicate to the Google apps on the device. Google+, GMail and Chat, etc all get called back from the server whenever there is new content for you. Google handles making sure that connection stays active with the minimum power usage and network traffic. Wouldn’t it be cool if your applications could use that that exact same channel&#8230;. You can! </span><span class="c4"><a class="c3" href="http://developer.android.com/google/gcm/index.html">Google Cloud Messaging for Android</a></span><span> is exposed for your applications to use for exactly this reason. </span></p>
<p class="c2"><span>But the setup for using Google Cloud Messaging has been tricky. You need to setup your own server, handle and track device registration, do OAuth2 auth, REST calls back to the GCM service, etc. Let’s see how easy it is with the Mobile Backend Starter. </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1FY3OsWHBMgtNYWJJjED6odGjK7YRF3Ol9hMc" width="449" height="205" /></p>
<p class="c2"><span>We need to do two things. First, on the server side we need to enable GCM and enter the Server API key into the Mobile Backend Starter setting page. The Server API key identifies who (which project) is making the calls to GCM to register devices and send notifications. </span></p>
<p class="c2"><span>The second thing we need to do is paste in the project number into the Const.java file in the client project. This is used as part of device registration with GCM. It tells GCM which notifications to send to this device. </span></p>
<p class="c2"><span>Let’s look at how we do this. </span></p>
<p class="c2"><span>First, we enable Cloud Messaging for Android in the API List of the Cloud Console by selecting APIs, and then enabling Cloud Messaging for Android. </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1PaikQv95Y94aRPdLI4hQB8L8YC6nGrQWYfi5" width="679" height="220" /></p>
<p class="c2"><span>Then we go to the Mobile Backend Starter setting page and enable GCM. </span><span> As you see it needs a API Key. </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=104Kd10yZUoelpHlABmltfH-w2B-VGYnQ_iJT" width="337" height="202" /></p>
<p class="c2"><span>I can create this in API Access by going back into the API Listing page and register a new app. In this case, I am registering the mobile backend app&#8230; such that it can access the GCM API we just enabled. </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1H57JSA8sn0pr3tM6hUZm57NabWARom8LRZGo" width="452" height="273" /></p>
<p class="c2"><span>Now I can just grab that Server API Key and paste it into the config page and I am done!</span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1NHh2ycknESHc6RmuT6x5waLcKCHsqRHIjTz2" width="302" height="257" /></p>
<p class="c2"><span>T</span><span>he last step</span><span> is to add the project number to the Const.java file. We are in the middle of transitioning to the new cloud console, but it isn’t easy to see the project number from the new console yet. You need to bounce back to the old APIs console to see it. The easy way to do that is to click on </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1vjhOmyJv1yxCpAEWP006yxTjmZlFYy9aUxkD" width="446" height="287" /></p>
<p class="c2"><span>And finally, we need to paste the project number into the client project. </span></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=11GjqJjGG9cnMnHzb2Fcw05Zxvq3S8Wji8GJx" width="434" height="220" /></p>
<p class="c2"><span>Now, we really need two devices to really test this out. If you are not lucky enough to have two, you can run them in virtual devices as well. If all is working well, when you click send on one a few seconds later you see the message show up on the other. </span></p>
<p class="c2"><img class="alignleft" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1-SMaUCKuKe8kPEhJaOFQ3m2eXJIhPna_gK0x" width="259" height="461" /></p>
<p class="c2"><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1liI1dhaqIjJUQv2_4RizHaF6cXXoV0ka23gG" width="259" height="461" /></p>
<p class="c2"><strong><span class="c8">Part Three &#8212; Add Map</span></strong></p>
<p dir="ltr">The sample app for our talk shows the locations of geeks on a map. You can create a new MapActivity in your project by following the instructions at <a href="https://developers.google.com/maps/documentation/android/start">Getting Started with Google Maps Android API v2</a>. To enable backward compatibility with older versions of Android, the demo app uses the MapFragment from the Android support library. The layout looks like this:</p>
<p class="c2"><b><b> </b></b></p>
<pre class="brush: xml; title: ; notranslate">

</pre>
<p>The FrameLayout and TextView are not required for maps. We’re using the TextView overlay to show authentication status directly on the map. Here is our corresponding MapActivity:</p>
<p><b><b> </b></b></p>
<pre class="brush: java; title: ; notranslate">
package com.google.cloud.backend.android;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.view.Menu;
import android.widget.TextView;

import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.SupportMapFragment;

public class MapActivity extends FragmentActivity {

	private GoogleMap mMap;

	private void setUpMapIfNeeded() {
		// Do a null check to confirm that we have not already instantiated the
		// map.
		if (mMap == null) {
			// Try to obtain the map from the SupportMapFragment.
			mMap = ((SupportMapFragment) getSupportFragmentManager()
					.findFragmentById(R.id.map)).getMap();
			// Check if we were successful in obtaining the map.
			if (mMap != null) {
				setUpMap();
			}
		}
	}

	private void setUpMap() {
		mMap.setMyLocationEnabled(true);
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_map);
		setUpMapIfNeeded();
	}

	@Override
	protected void onResume() {
		super.onResume();
		setUpMapIfNeeded();
		TextView overlay = (TextView) findViewById(R.id.overlay);
		overlay.setText(&quot;Not signed in&quot;);
	}

}

</pre>
<p><strong>Part Four &#8212; Store Location in the Cloud</strong></p>
<p><b><b> </b></b></p>
<p>To send our location to the cloud backend, we need to get notified of location updates, then make a request to our backend service. To get notified of location updates, we’ll register the MapActivity class as an OnMyLocationChangeListener. To do this, we call mMap.setOnMyLocationChangeListener(this) in the setUpMap() method and let the MapActivity class implement OnMyLocationChangeListener. The required method looks like this:</p>
<pre class="brush: java; title: ; notranslate">
	private void setUpMap() {
		mMap.setMyLocationEnabled(true);
		mMap.setOnMyLocationChangeListener(this);
	}

	protected String myLocation;
	protected static boolean locSent;
	private static final Geohasher gh = new Geohasher();

	@Override
	public void onMyLocationChange(Location location) {
		this.myLocation = gh.encode(location);
		if (!locSent) {
			sendMyLocation();
		}
	}

</pre>
<p>To send our location to the server, we can use the features of the Mobile Backend Starter project. MBS provides a generic entity (CloudEntity) on which we can set arbitrary properties and a set of CRUD services that know how to send and receive it. To implement sendMyLocation(), we simply let our MapActivity extend CloudBackendActivity, then create a new CloudEntity and update the server:</p>
<p><b><b> </b></b></p>
<pre class="brush: java; title: ; notranslate">
	private void sendMyLocation() {
		CloudEntity self = new CloudEntity(&quot;Geek&quot;);
		self.put(&quot;interest&quot;, &quot;Cloud&quot;);
		self.put(&quot;location&quot;, this.myLocation);
		getCloudBackend().update(self, new CloudCallbackHandler() {
			@Override
			public void onComplete(CloudEntity results) {
				locSent = true;
				drawMyMarker();
			}
		});
	}

</pre>
<p>Note: at the time of this writing, CloudBackendActivity extends the basic Activity class. To use it with a MapFragment and the support library, you’ll need to modify CloudBackendActivity to instead extend FragmentActivity from the support library.</p>
<p><b><b> </b></b></p>
<p><strong>Part Five &#8212; Add Authentication</strong></p>
<p><strong> </strong></p>
<p>We are now storing sensitive information (your location) up in the cloud and as such we want to be sure we have locked down access to our server to only our client.  We also want users to authenticate so that we know who they are even if they use different devices.   Authentication can be difficult on mobile devices.  Are you going to ask your users to type in a username and password on the little keyboard?  Will they even be able to remember a username and password for just your app?  what if they lose their password or it gets stolen?</p>
<p><b><b> </b></b></p>
<p>The Mobile Backend Starter makes it very easy to use Google Authentication.   Nearly every Android phone has a Google account that your customers are already using for GMail, Chat, Google Now or other google services.     You can use that same account in our application no passwords for our users to remember, no admin headaches for you.</p>
<p>We will just go in and enable auth in the Mobile Backend Starter setting page.</p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1Qb6Me3OR79aW1jsKIFtYTEw8GTFoTngOjnc5" width="502" height="308" /></p>
<p><span>There are three steps to enabling auth. The first step is to ensure that we have strong identity for the android client. We want to lock down access to our Cloud Endpoints (our REST API) to only our own Android client. </span></p>
<p><span>That is way the first box is asking for &#8212; the Android Client ID. The Android Client ID is how we uniquely identify your application run in an android device. It allows for secure access between your code on the device and your code in the cloud. One common way to do this is to create a “secret” and embed that into the client application. The problem with this approach is that it is easy to find that secret. How many of you have ever decompiled a class file? yea &#8212; not that hard. The secrets don’t work well if they are easy to find. </span></p>
<p><span>We are going to use a different approach. The same approach in fact that Google Play uses to uniquely identify an application to update. You might imagine it would be “bad” to update the wrong app. So we have developed a mechanism that is </span><span>client-s</span><span>ecret free to strongly identify an application. </span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=19KEQ5A4tPLiGaqbcMt0G5A6fTTQbzjaLlX8x" width="449" height="269" /></p>
<p><span>To do this, let’s create a client ID for Android in the Cloud Console, in the API section, select Register App. This time we want to register the Android client, so we select Android and directly from Android. </span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1tV9FrmIxW8Mo7svIO5XOcJgfAl_-LWqCt91w" width="415" height="291" /></p>
<p><span>In the Android Identification section it asks for a package name and SHA1 fingerprint. It is a cryptographically secure </span><span class="c4"><a class="c3" href="https://developers.google.com/console/help/#installed_applications">hash of the manifest we use to sign the android app</a></span><span>. There is a handy keytool app (you can get that for Windows as well) and run it over your keystore. Eclipse users can find it in ~/.android/debug.keystore. For the debug.keystore, there is likely not a password, so just hit return there. </span></p>
<p><img alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1nLLUXur59OTYhYXBjfLaibydmKRzhQ_NQY_t" width="532" height="239" /></p>
<p><span>There that is our SHA1 hash&#8230; now we give that to the Cloud Console along with our package name (com.google.cloud.backend.android) to give us a </span><span>key</span><span>. </span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1HTr8P9bKoZbVajU8GdgdQ5H-MTk-MINrPnXZ" width="334" height="218" /></p>
<p><span>And we give that key to the Mobile Backend Starter. </span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1OA1uuwcgp2K3yGWqTerO7smSG9fgpHxXnU-h" width="486" height="227" /></p>
<p><span>OK, I mentioned there’d be three steps for enabling auth&#8230; That was step 1, restricting access to just our client. Now for step 2, establishing the client and the server are from the same developer so we can avoid the standard OAuth2 prompt. You may have seen an OAuth2 dialog when an application is asking for permission to, for example, access your data on Google+.</span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1e8F5LxlDX-syudT8Q18XFu0WNSijpm4Qp837" width="129" height="230" /></p>
<p><span>It makes perfect sense that in this case the application has to ask the user for permission to access their data stored in google+. But in our case there is no 3rd party here. Our users are using our app to access their data stored by us. There is really no reason to prompt the user in this case. </span></p>
<p><span>So to avoid this dialog, we need to establish that the same developer is building the client and the server. To do this we share a token between them. Notice this is NOT a secret. Feel free to publish this client ID. Even if someone has this token they will still not be able to access your server as the requests would not be coming from a signed application. </span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1LEPek_BsV1YEE2LcM_8TEvY39ZDFQpRW-A-C" width="340" height="223" /></p>
<p><span>We already have a Web Server Application created for GCM, we just need to grab the OAuth2 client ID.</span></p>
<p><span>And add it</span><span> to the Mobile </span><span>Backend</span><span> Starter.</span></p>
<p><span> We just add this to the backend and the client.. and set the client to be auth enabled.. </span></p>
<p><span>The final step is to pass the user name from the client to the server. Luckily Android, App Engine and the Mobile Backend Starter all have built in support for Google Auth so it is very easy to have the same user on the client and server. No explicit code need to enable it. </span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1uIs00hncBUL4AxirqNvOeYEn-NB0PBnmK5Vf" width="443" height="221" /></p>
<p><span>Now you see we are giving a chance to select an account (because I have more than </span><span>on</span><span>e). and NO password typing on the phone!</span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=18WILIiIyFM7k3pSV1HpwyOFbLYJD-zKLSAeH" width="259" height="461" /></p>
<p><span>You can see the client has access to my user name&#8230;</span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1VLtxavZlyNsm_tr0aiAxsmRYeMJlE8_n_4Vq" width="259" height="461" /></p>
<p><span>And there we see in Datastore in cloud console you see the entities are now owned by users. We keep up with who created and who updated each entity.</span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1EFSIZ12ggvDJ_yZJYZ2cPnt6IE8zPT1WXtcX" width="583" height="210" /></p>
<p><strong><span class="c8">Part Six &#8212; Continuous Queries</span></strong></p>
<p>One powerful feature of the Mobile Backend Starter code is continuous queries. Built on the <a href="https://developers.google.com/appengine/docs/java/prospectivesearch/overview" target="_blank">App Engine Prospective Search API</a>, this capability notifies the mobile client via Google Cloud Messaging whenever query results change on the server. For our Geek Serendipity app, the process works like this:</p>
<p><strong><b><b> </b></b></strong></p>
<ol>
<li dir="ltr">The client sends an updated location to the server.</li>
<li dir="ltr">Prospective Search notifies the MBS App Engine code.</li>
<li dir="ltr">The MBS server sends a GCM message to the client.</li>
<li dir="ltr">The MBS client calls the original query for to get updated results.</li>
<li dir="ltr">The MBS client invokes the query handler with the results.</li>
</ol>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=16AN_F3BHyd4WY138pq9O097vJXRhzqrKPzcQ" width="452" height="237" /></p>
<p><span> </span></p>
<p>All of this happens transparently using a single feature of the app. The relevant code for the Geek Serendipity app is here:</p>
<p><b><b> </b></b></p>
<pre class="brush: java; title: ; notranslate">
private void queryGeeks() {
		CloudCallbackHandler&lt;List&gt; handler = new CloudCallbackHandler&lt;List&gt;() {
			@Override
			public void onComplete(List results) {
				drawMarkers(results);
			}

			@Override
			public void onError(IOException e) {
				Toast.makeText(getApplicationContext(), e.getMessage(),
						Toast.LENGTH_LONG).show();
			}
		};

		CloudQuery cq = new CloudQuery(&quot;Geek&quot;);
		cq.setLimit(50);
		cq.setSort(CloudEntity.PROP_UPDATED_AT, Order.DESC);
		cq.setScope(Scope.FUTURE_AND_PAST);
		getCloudBackend().list(cq, handler);
	}

</pre>
<p>The queryGeeks() method registers a continuous query to return the top 50 most recent location updates. By setting Scope.FUTURE_AND_PAST, the handler passed to getCloudBackend().list() will be invoked whenever there are updated results on the server.</p>
<p><b><b> </b></b></p>
<p>Because our geek query is a continuous query, we only need to register it once, but we want to do that only after MBS has been initialized (GCM has been registered and MBS is ready for query subscriptions). In addition, if authentication is enabled on the MBS settings page, we want to wait until the user has been authenticated. MBS has a special hook that meets all these criteria. To use it, simply override the onPostCreate() method from CloudBackendActivity:</p>
<p><b><b> </b></b></p>
<pre class="brush: java; title: ; notranslate">
	@Override
	protected void onPostCreate() {
	    queryGeeks();
	}

</pre>
<p><b id="docs-internal-guid-1ce02710-c3bb-e2c9-9f71-5d515ad72c21"><br />
</b>Now our query will run immediately on initialization and thereafter whenever there are new geek location updates on the server.</p>
<p><strong><span class="c8">Part Seven &#8212; Customizing the Backend</span></strong></p>
<p><span>Well, we have just about got this application wrapped up. And that Mobile Backend Starter we used has served us really well. We have not had to do any server coding at all. And that is great. This is a great way to get started, but what if I need more? What if I need to write a some custom server code? Well with the Mobile Backend Starter you never hit a limitation or roadblock you can’t work around. </span></p>
<p><span>The backend we deployed at the start of this talk, is actually an app engine application that you can go and download yourself. All the </span><span class="c4"><a class="c3" href="https://github.com/GoogleCloudPlatform/solutions-mobile-backend-starter-java">source code is on github</a></span><span>. You can download it, see how we implemented it, and customize it to meet your needs. </span></p>
<p><span>To show that off, let’s look at how to add some </span><span>custom client logging to server. As Googlers, we **LOVE** to make data driven decisions. </span><span>Data on how our app is used on the client can help us make it better if we can see it in aggregate over time. So let’s add some logic for the clients to log directly to the server and stick them in App Engine’s logs where then can be </span><span class="c4"><a class="c3" href="http://googleappengine.blogspot.com/2012/07/analyzing-your-google-app-engine-logs.html">imported in BigQuery</a></span><span> for </span><span class="c4"><a class="c3" href="https://developers.google.com/bigquery/">analysis</a></span><span>. </span></p>
<p><span>So basically we are going to add a new custom Endpoint to the App Engine app (ClientLoggingEndpoint) that stores data in the app engine logs store, then add a CloudLog class to android app that sends client logs up to the server. </span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1hkaxiXa3BoCsUV0bmEiPlvjNAMmTbdEMj9pX" width="439" height="216" /></p>
<p><span>Lets’ start by downloading the backend, now we will important it into eclipse in the same workspace as our android project. (Note, for this part you do need the </span><span class="c4"><a class="c3" href="https://developers.google.com/eclipse/">Google Plugin for Eclipse</a></span><span> installed). </span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1luxzLU0o5tBWGFnK9UGihSM2kCo9y5K3zWgL" width="237" height="154" /></p>
<p><span>Now, let’s add our custom method&#8230;</span></p>
<p><span>ClientLoggingEndpoint.java</span></p>
<pre class="brush: java; title: ; notranslate">
@ApiMethod(
   name = &quot;logs.log&quot;,
   path = &quot;logs/log/{message}&quot;,
   httpMethod = HttpMethod.POST
)
public void logFromClient(@Named(&quot;message&quot;) String message) {
   log.info(&quot;client log: &quot; + message);
   return ;
}

</pre>
<p><span>Now we need to be able to access this method from the client. Well that is pretty easy. Right click on Google menu and select Generate Cloud Endpoint Library.</span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1UkQxXIO5j0-ZI2N_HQUvtYSv2KzICa_JiImz" width="428" height="359" /></p>
<p><span>Now, the library will be generated in the endpoints-libs director. You see we have a new directory there for our logging service.</span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1ir9iwksyU2Tzxmo5PIOrXjRmzGIRZKgBNmII" width="230" height="204" /></p>
<p><span>Now we simply need to copy this into the android project (you can just drag it down into the endpoints-libs of the android project. </span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1hn2oe6GWJJQtF7v-hbo-k9vjNRaH3-aZFR2H" width="228" height="148" /></p>
<p><span>Now we just add this library to the java build path&#8230; We actually need the clientlogging-v1-generated-source to the build path. </span></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1GKj3I5HHA22gg25yxoS4DlVmMk1W2bmKeKVU" width="371" height="185" /></p>
<p><img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=107sOA9de1O_EGHG7M5-gWD70pC-5xS_oADHc" width="482" height="371" /></p>
<p><span>OK, great. Now we just need to use this client library from the Android app. To make that easy, I created a simple CloudLog.java class to encapsulate access. The main method of which is below. </span></p>
<p><span>Notice we are using a thread to get the network calls off the main UI thread. We want to be sure that this logging does not in anyway negatively affect the experience for the user. No laggy UI while we are posting the logs to the server. Also note, I am sending each log directly to the server&#8230; a better pattern would likely to be to batch, but I will leave that as an exercise for the user. </span></p>
<pre class="brush: java; title: ; notranslate">
	public void Log (final String message) {

			new Thread(new Runnable() {
			    public void run() {

					Clientlogging.Builder builder = new Clientlogging.Builder (
							   AndroidHttp.newCompatibleTransport(),
                                                           new GsonFactory(), null);
					Clientlogging service = builder.build();
					try {
						String msg = android_id +&quot;:&quot;+ message;
						service.logs().log(msg).execute();
						android.util.Log.d(&quot;log&quot;, msg);

					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
						android.util.Log.e(&quot;log&quot;, e.toString());

					}
			    }
			  }).start();
	}

</pre>
<p><span>Now we just need to make some changes to the main activity to call it in GeekWatchActivity.java. </span></p>
<p><span>First we created the CloudLog class, passing the unique ID of this device (do we can look at pre-device usage patterns later). </span></p>
<pre class="brush: java; title: ; notranslate">
android_id = Secure.getString(getApplicationContext().getContentResolver(),
		                Secure.ANDROID_ID);

cloudLog = new CloudLog (android_id);
</pre>
<p><span>Then we add some logging to interesting places, here is one example:</span></p>
<pre class="brush: java; title: ; notranslate">
        @Override
        public void onCameraChange(CameraPosition position) {
                LatLngBounds visibleBounds = mMap.getProjection().getVisibleRegion().latLngBounds;
                findGeeks(visibleBounds);
                cloudLog.Log(&quot;Camera Changed&quot;);
        }
</pre>
<p class="c2"><span>Deploy the backend to App Engine and run the client app and use the app a bit. Logs are being written to the App Engine logs store. </span></p>
<p class="c2"> <img class="alignnone" alt="" src="https://docs.google.com/document/d/1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c/pubimage?id=1aTh7QQRtDZSzmiQqxrXDD5uNyP9EAIdB2t-NGDpLa6c&amp;image_id=1prfze8rqwRC5UNtcH4QV0EAp94q5-u-spcSW" width="564" height="194" /></p>
<p dir="ltr">Now that we have it in GAE logs, we can easily import this into <a href="https://developers.google.com/bigquery/" target="_blank">BigQuery</a> or other tool to get meaning and drive improvements.</p>
<p class="c2"><b><b> </b></b></p>
<p dir="ltr"><strong>Conclusion</strong></p>
<p class="c2"><b><b> </b></b></p>
<p dir="ltr">Hopefully you’ll find that the Mobile Backend Starter project is an easy way to get started building a cloud back end for your Android app. The CloudEntity and corresponding CRUD endpoints allow you to update and query data in the cloud without having to write any server code, and continuous queries offer Google Cloud Messaging functionality right out of the box.</p>
<p class="c2"><b><b> </b></b></p>
<p dir="ltr">To learn more, please see these resources:</p>
<p dir="ltr"><a href="https://developers.google.com/events/io/sessions/333508149">Google I/O 13 session video</a></p>
<p class="c2"><b id="docs-internal-guid-1ce02710-c3c2-1f58-5166-b29333cfdd0b"><a href="https://github.com/bradabrams/GeekSerendipity-io13">Geek Serendipity source</a></b></p>
<p class="c2">Geek Serendipity application on <a href="https://play.google.com/store/apps/details?id=com.turbomanage.sample.geekwatch&amp;rdid=com.turbomanage.sample.geekwatch&amp;rdot=1&amp;feature=md">Play Store</a></p>
]]></content:encoded>
			<wfw:commentRss>http://bradabrams.com/2013/05/google-io-2013-session-overview-from-nothing-to-nirvana-in-minutes-cloud-backend-for-your-android-application-building-geek-serendipity/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>PM Tip #15: Define the Situation</title>
		<link>http://bradabrams.com/2011/05/pm-tip-15-define-the-situation/</link>
		<comments>http://bradabrams.com/2011/05/pm-tip-15-define-the-situation/#comments</comments>
		<pubDate>Wed, 25 May 2011 13:36:36 +0000</pubDate>
		<dc:creator>Brad Abrams</dc:creator>
				<category><![CDATA[PM Tips]]></category>

		<guid isPermaLink="false">http://bradabrams.com/?p=152</guid>
		<description><![CDATA[I learned this one from watching my wife be a wonderful mother to our elementary aged kids.  Often on the way back from an outing she’ll say: “We sure had fun today”.  Or at dinner she’ll say: “We are really looking forward to Grammy and Grampy’s visit”.   The kids will nod, agree and expand on [...]]]></description>
				<content:encoded><![CDATA[<div style="float: left;" ><g:plusone  position="prepend" size="standard" count="1" href="http://bradabrams.com/2011/05/pm-tip-15-define-the-situation/" text="PM Tip #15: Define the Situation" ></g:plusone></div>
<div>
<p id="internal-source-marker_0.5334283486008644">I learned this one from watching my wife be a wonderful mother to our elementary aged kids.  Often on the way back from an outing she’ll say: “We sure had fun today”.  Or at dinner she’ll say: “We are really looking forward to Grammy and Grampy’s visit”.   The kids will nod, agree and expand on those ideas.  There are many possible, valid ways for our kids to make sense out of their feelings.  My wife does a great job of guide them to the most constructive interpretations.</p>
</div>
<div>
<p>Strange how being a PM is not that different than being a mom <img src='http://bradabrams.com/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /> .   When you lead a software project crazy things happen.  Deadlines are missed, reorgs happen, competitors ship similar products.   The team needs a leader that will define the situation.  Someone that will choose from the myriad of possible reactions to find the one that will be most constructive.  To put words to the feelings everyone is having and help harness those feelings to a productive result.</p>
<p>In the recent push to shipping a beta of a product I was going to demo at Google IO I had a chance to put this into practice.  It was the night before my talk and the product release was a mere 14 or so hours away.  The team had been crunching hard for the last few weeks to get ready and I had found a ship stopping bug.  We gathered in the lobby of Moscone, I showed the team the bug,  incredulously, several of them setup the repro on their own machines believing it was a configuration issue.  But alas, the bug reproduced on every machine.  This meant a late night for the team to find, fix, test, build and release new bits.  At that moment, when the team was a bit down, I remembered this tip and announced: “We are having fun now!”.  And I meant it.. it was fun.  If you have ever been there you will attest to it.  It is fun to have an indisputable “top priority” with a clear deadline.  Lots of pressure, but lots of pay off as well.  With a team of people you know well and like working with&#8230;. I mean, what could be better!    “We are having fun now”&#8230;  It turned the conversation from possibly going into despair to a conversation full of excitement and adventure.  And we did get that bug fixed and ship on schedule!</p>
<p>Now you need to be careful with this technique.  You must always be honest &#8211; your team will see right through you if you are anything else.  The goal is NOT to paint a bad situation as rosey &#8212; that would be a lie.  The goal is to find the most productive attitude to handle the situation and rally the team around that idea.</p>
</div>
<div><a href="http://bradabrams.com/2010/12/pm-tips-product-manager-tips/" target="_blank">See more PM Tips</a></div>
<div>I&#8217;d love your comments and thoughts!</div>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://bradabrams.com/2011/05/pm-tip-15-define-the-situation/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Google IO Session Overview: Android + App Engine: A Developer&#8217;s Dream Combination</title>
		<link>http://bradabrams.com/2011/05/google-io-session-overview-android-app-engine-a-developers-dream-combination/</link>
		<comments>http://bradabrams.com/2011/05/google-io-session-overview-android-app-engine-a-developers-dream-combination/#comments</comments>
		<pubDate>Wed, 11 May 2011 06:14:25 +0000</pubDate>
		<dc:creator>Brad Abrams</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://bradabrams.com/?p=94</guid>
		<description><![CDATA[Xavier Ducrohet and I had a great time today demoing “BigDaddy” which is the codename for the Google Plugin for Eclipse 2.4 Beta that we released today. I started off with the following products installed: Eclipse Helios, Android Developments Tools and, of course the Google Plugin for Eclipse 2.4 beta. See the video of the [...]]]></description>
				<content:encoded><![CDATA[<div style="float: left;" ><g:plusone  position="prepend" size="standard" count="1" href="http://bradabrams.com/2011/05/google-io-session-overview-android-app-engine-a-developers-dream-combination/" text="Google IO Session Overview: Android + App Engine: A Developer&#8217;s Dream Combination" ></g:plusone></div>
<p> <span class="c3"><a class="c4" href="http://twitter.com/#!/droidxav">Xavier Ducrohet </a></span><span>and </span><span class="c3"><a class="c4" href="http://twitter.com/#!/brada">I </a></span><span>had a great time today demoing “BigDaddy” which is the codename for the </span><span class="c3"><a class="c4" href="http://code.google.com/eclipse/beta/docs/download.html">Google Plugin for Eclipse 2.4 Beta </a></span><span>that we released today.</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>I started off with the following products installed:</span></p>
<p class="c1"><span class="c3"><a class="c4" href="http://www.eclipse.org/downloads/">Eclipse Helios</a></span><span>, </span><span class="c3"><a class="c4" href="http://developer.android.com/sdk/index.html">Android Developments Tools </a></span><span>and, of course the </span><span class="c3"><a class="c4" href="http://code.google.com/eclipse/beta/docs/download.html">Google Plugin for Eclipse 2.4 beta</a></span><span>.</span></p>
<p class="c1 c2"><span> </span></p>
<ul>
<li>See the video of the talk: <a href="http://www.youtube.com/watch?v=M7SxNNC429U" target="_blank">http://www.youtube.com/watch?v=M7SxNNC429U </a></li>
<li>Download the complete source code for the demo: <a class="c4" href="https://code.google.com/p/cloud-tasks-io">https://code.google.com/p/cloud-tasks-io</a></li>
<li>See the demo live (but please only use test data): <span class="c3"><a class="c4" href="http://cloudtasksio.appspot.com/" target="_blank">http://cloudtasksio.appspot.com</a>.  For the Android client, browse to the bottom of this page on your phone to find the link to the APK. </span><span> </span></li>
<li>You can also check out the default Big Daddy application: <span class="c3"><a class="c4" href="http://bigdaddy-io.appspot.com/" target="_blank">http://bigdaddy-io.appspot.com/</a></span></li>
<li>Access the slides <a href="http://www.slideshare.net/brada/androidandroid-app-engine-a-developers-dream-combination " target="_blank">http://www.slideshare.net/brada/androidandroid-app-engine-a-developers-dream-combination </a></li>
</ul>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Our goal is to create a task tracking application for Larry Page.  As he takes over as CEO, Larry has a lot of tasks that he needs to track and this app will help him (and the rest of us) track tasks.  ;-)</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>The basic architecture of the task app looks very similar to a wide range of applications </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image211.jpg" alt="" width="438" height="332" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>First, we have an Android application that talks, via RPC to an App Engine server where your business logic is and the data is stored in the </span><span class="c3"><a class="c4" href="http://code.google.com/appengine/docs/java/gettingstarted/usingdatastore.html">app engine datastore</a></span><span>. We also needed a standards based web client that can work from anywhere on the same data with the same business logic.  We built that out with </span><span class="c3"><a class="c4" href="http://code.google.com/webtoolkit/">GWT</a></span><span> to keep with the same programing language and tools, but of course, any web client technology will work.   Finally, we use </span><span class="c3"><a class="c4" href="http://code.google.com/android/c2dm/index.html">C2DM</a></span><span> to do push notification when new tasks are added to the database. </span></p>
<p class="c1"><span> </span></p>
<p class="c1"><span>OK, so let’s look at how we build this task tracking application. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>The first step is to create a new App Engine Connected Android Project. This project gives you a very useful starting project with the plumbing code in libraries and the code that you may want to change and tweak generated into the project.   This project gives you a few  things:</span></p>
<p class="c1 c6"><span>1. An authenticated Hello world RPC service with the logic in app engine and clients in GWT and Android. </span></p>
<p class="c1 c6"><span>2. All the C2DM infrastructure .</span></p>
<blockquote>
<p class="c1 c7"><span>a. App Engine based datastore for handing registration</span></p>
<p class="c1 c7"><span>b. Android client with default UI for picking a user and responding to C2DM messaging</span></p>
<p class="c1 c7"><span>c. GWT based client for sending C2DM pings through the app engine server.</span></p>
</blockquote>
<p class="c1"><span>Let’s take a look at how this works.</span></p>
<p class="c1 c2"><span> </span></p>
<h3 class="c5"><a name="h.6u6066lo7e8m"></a><span>Creating the Starter Project </span></h3>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>In Eclipse select File\New then Other.  Under the Android node you will find the “App Engine connected Android project”. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image081.jpg" alt="" width="461" height="361" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>In the first page of the wizard, simply give your project a name and namespace.  From these the tool will create Android, App Engine and GWT projects. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image271.jpg" alt="" width="324" height="319" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>note:  if you see the warning to “configure Android SDK” just click on the link and select the Android SDK with at least API level 8 (to support C2DM).  You will also likely want to select an a Google APIs enabled SDK to support the google authentication that we will be using. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>The next page of the wizard asks for your C2DM role account.  You can </span><span class="c3"><a class="c4" href="http://code.google.com/android/c2dm/signup.html">sign up for a C2DM role account</a></span><span> from this wizard. </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image291.jpg" alt="" width="396" height="390" /></p>
<p class="c1"><span> </span></p>
<p class="c1"><span>A tip: You can auto fill this in if you put a file called c2dm.properties in your home directory with the format:</span></p>
<pre class="c1" style="padding-left: 30px;"><span>user=yourid@gmail.com
</span>passwd=yourpassword</pre>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>This wizard creates two projects&#8230; An Android client and App Engine server. Along with a shared code directory for storing code that is compiled into both projects. </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image341.jpg" alt="" width="280" height="491" /></p>
<p class="c1"><span>To run this, you will want to connect your android phone via USB or create an virtual device via the </span><span class="c3"><a class="c4" href="http://developer.android.com/guide/developing/devices/managing-avds.html">Android SDK and AVD manager</a></span><span> and launch it.  For the AVD I found targeting google </span><span>API level </span><span>9 and 256 meg SD card more than sufficient.   I used a screen size of 9 to be small enough to manage, but still readable.  I also found that saving a snapshot once after boot then only launching from snapshot NOT having to the snap shot made testing on a clean image with a very fast start-up helpful. </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image121.jpg" alt="" width="461" height="274" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>You can verify you have your device connected by looking at the DDMS perspective in eclipse.  You should see your emulator up and the list of all the process.  This indicates that you are ready to go. </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image141.jpg" alt="" width="623" height="303" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<h3 class="c5"><a name="h.diymu4276lum"></a><span>Running the Starter Project </span></h3>
<p class="c1"><span>Once you have a device connected, you right click on the Android project and select Debug As then Local App Engine Connected Android Project. </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image231.jpg" alt="" width="393" height="305" /></p>
<p class="c1"><span>What this does is wire up the android application to talk to the local app engine dev app server. </span></p>
<p class="c1"><span>In the emulator, we see the application pop up.   The first thing it asks you to do is log in (if you don’t see it, click options and then accounts).  This very important &#8212; many android devices have google accounts built in.  A coworker of mine recently told me he’d rather stand naked in the rain than type his password on the phone.   Using the google accounts makes it possible to authenticate without typing a password.  This will also enable authenticated RPCs and C2DM pings as you will see. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image031.jpg" alt="" width="292" height="503" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Once you connect, your device will be registered to receive C2DM messages.  In particular, the app engine application with store a unique code for pinging your device when a message is sent to you.  You can look in the app engine datastore to see exactly what the app engine application is storing for you.  Browse to </span><span class="c3"><a class="c4" href="http://127.0.0.1:8888/_ah/admin/">http://127.0.0.1:8888/_ah/admin/</a></span><span> and select DataStore viewer. </span></p>
<p class="c1"><span>As you can see here, we store the user’s email address and the unique device ID.  This allows us to send C2DM pings through the App Engine server later. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image021.jpg" alt="" width="450" height="144" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Back in the Android client, click on the Say Hello button, you will see a message back from the app engine server.  It calls the getMessage() functional found in the HelloWorldService.java file in the com.cloudtasks.server package.    Notice that it is return the user’s email address from the server.  That is fantastically cool.  It means that the app engine server knows the same user identity information as the android client. </span></p>
<pre class="c1"><span> </span><span class="c0">public static String getMessage() {</span></pre>
<pre class="c1"><span class="c0"> UserService userService = UserServiceFactory.getUserService();
</span> User user = userService.getCurrentUser();</pre>
<pre class="c1"><span class="c0"> String message;</span></pre>
<pre class="c1"><span class="c0"> if (user == null) {</span></pre>
<pre class="c1"><span class="c0">    message = "No one is logged in!\nSent from App Engine at " + new Date();</span></pre>
<pre class="c1"><span class="c0"> } else {</span></pre>
<pre class="c1"><span class="c0">    message = "Hello, " + user.getEmail() + "!\nSent from App Engine at " + new Date();</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1"><span class="c0"> log.info("Returning message \"" + message + "\"");</span></pre>
<pre class="c1"><span class="c0"> return message;</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image041.jpg" alt="" width="360" height="381" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Also, once that C2DM registration is successful, you get a C2DM ping.  This is unlikely the right user experience for your application when completed, but it is a good, clear way to start and is very easy to update. </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image101.jpg" alt="" width="348" height="239" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Now, let’s take a look at the standards based web client that is written in GWT.   You can start this up by flipping to the Development Mode tab and click on the URL there. </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image181.jpg" alt="" width="627" height="241" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>That will launch a web browser.  If you have not installed the GWT plugin for development mode only you will need to.  Notice that in production it is just javascript no plugin required. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Now you will see the local app engine test log in experience.  This is because we have setup the default project to require authentication.  That is down in the App Engine project under war/web.xml.  Notice this section:</span></p>
<pre class="c1"><span class="c0"> &lt;security-constraint&gt;</span></pre>
<pre class="c1"><span class="c0"> &lt;web-resource-collection&gt;</span></pre>
<pre class="c1"><span class="c0">    &lt;url-pattern&gt;/*&lt;/url-pattern&gt;</span></pre>
<pre class="c1"><span class="c0"> &lt;/web-resource-collection&gt;</span></pre>
<pre class="c1"><span class="c0"> &lt;auth-constraint&gt;</span></pre>
<pre class="c1"><span class="c0">    &lt;role-name&gt;*&lt;/role-name&gt;</span></pre>
<pre class="c1"><span class="c0"> &lt;/auth-constraint&gt;</span></pre>
<pre class="c1"><span class="c0"> &lt;/security-constraint&gt;</span></pre>
<p class="c1 c2"><span class="c0"> </span></p>
<p class="c1"><span>This indicates that all urls in this project require authentication. </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image071.jpg" alt="" width="501" height="276" /></p>
<p class="c1"><span>You could easily add another node if you wanted some unsecured access URLs for general information, etc.  See </span><span class="c3"><a class="c4" href="http://code.google.com/appengine/docs/java/config/webxml.html">the App Engine documentation </a></span><span>for more information. </span><span>This functionality enables you to “log in” with any email address when running in test mode.  Notice no password is required because this is just a test model.  When deployed to app engine this will be replaced with the typical Google log in dialog.   See </span><span class="c3"><a class="c4" href="http://code.google.com/appengine/docs/java/gettingstarted/usingusers.html">more information</a></span><span>.   We log in with the same email address as we used on the android client.  That will be important later when we share data. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>In the GWT application, we have the same  “Say Hello” button.  Click on it does the RPC round trip to the server.   Already we are sharing identity and business logic between the android client, the GWT web front end and the App engine based server. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image191.jpg" alt="" width="645" height="387" /></p>
<p class="c1 c2"><span class="c8"> </span></p>
<p class="c1 c2"><span class="c8"> </span></p>
<h3 class="c5"><a name="h.44i6ne4rrq9d"></a><span class="c8">Sending  a C2DM Ping </span></h3>
<p class="c1 c2"><span class="c8"> </span></p>
<p class="c1"><span class="c8">Now, let’s send a C2DM ping. </span></p>
<p class="c1"><span class="c8">Notice I use the same email address as I logged into my Android phone with. </span></p>
<p class="c1 c2"><span class="c8"> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image301.jpg" alt="" width="396" height="240" /></p>
<p class="c2 c9"><span> </span></p>
<p class="c1"><span>Then I flip over to the phone and presto&#8230; A C2DM message arrives.</span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image321.jpg" alt="" width="307" height="301" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>So that is basically what is in the starter app.  A very solid way to get started!</span></p>
<p class="c1"><span>Want to try it live yourself?   Check out the running app here:</span></p>
<p class="c1"><span><a href="http://bigdaddy-io.appspot.com/">http://bigdaddy-io.appspot.com/ </a></span></p>
<p class="c1"><span>You can install the APK from this site on your phone.</span></p>
<p class="c1"><span>Be sure to log in to the android app before you test sending C2DM pings</span></p>
<p class="c1"><span><br />
</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<h3 class="c5"><a name="h.fmi9uox631wx"></a><span>Tasks Data Layer and RPC Layer</span></h3>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Now let’s focus on building out the custom logic for our task tracking application for Larry Page. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>First we will need a task entity.  We will just create a new java class in the app engine server project in the com.cloudtasks.server package. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Here is a snippet of it.. a very simple java class with no data access logic.. Just fields and accessors. </span></p>
<pre class="c1"><span class="c0">@Entity</span></pre>
<pre class="c1"><span class="c0">public class Task {</span></pre>
<pre class="c1 c2"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> private String name;</span></pre>
<pre class="c1"><span class="c0"> private String notes;</span></pre>
<pre class="c1"><span class="c0"> private Date dueDate;</span></pre>
<pre class="c1"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> @Id</span></pre>
<pre class="c1"><span class="c0"> @GeneratedValue(strategy = GenerationType.IDENTITY)</span></pre>
<pre class="c1"><span class="c0"> private Long id;</span></pre>
<pre class="c1"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> private String userId;</span></pre>
<pre class="c1"><span class="c0"> private String emailAddress;</span></pre>
<pre class="c1 c2"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> public Task () {}</span></pre>
<pre class="c1"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> public String getName() {</span></pre>
<pre class="c1"><span class="c0">    return name;</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1"><span class="c0"> </span></pre>
<pre class="c1"><span> </span></pre>
<p class="c1"><span>Now we need to create our Service class.  This is the place we want to write our shared business logic that can be called from the GWT client and the Android client via JSON over http. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>We do this with the new RPC tooling wizard in GPE 2.4.  Right click on the com.cloudtasks.server project, select New and then Other and find the “RPC Service” under the Google directory.</span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image201.jpg" alt="" width="487" height="379" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>As you can see, the wizard looks in your server project for all the entities (</span><span>marked with an attribute of “@Entity”</span><span> or “@PresistenceCapable”).   The wizard will create Query + Create, Update and Delete methods for each entity you select.  You can add more custom methods, add custom params, etc in the code.    The wizard will also generate custom code in the com.cloudtasks.shared directory for calling the this service.  We will see that code a bit later. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image151.jpg" alt="" width="466" height="365" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Now, let’s flush this out a bit.  One of the beautiful parts of this system is that by the time the caller gets to one of these methods you the serialisation, authentication and validation is complete.  In other words, all the plumbing code is gone.  You simply need to implement your storage logic.  You can use any store you want from some legacy system, to S3.  But of course we will show how to use </span><span class="c3"><a class="c4" href="http://code.google.com/appengine/docs/java/gettingstarted/usingdatastore.html">App Engine’s </a></span><span class="c3"><a class="c4" href="http://code.google.com/appengine/docs/java/gettingstarted/usingdatastore.html">Datastore</a></span><span>. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>I wrote a simple data layer that uses JDO to store entities.  I called the class DataStore. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>First, let’s create an instance of the DataStore:</span></p>
<p class="c1 c2"><span> </span></p>
<pre class="c1"><span class="c0">public class CloudTasksService {</span></pre>
<pre class="c1"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0">   static DataStore db = new DataStore();</span></pre>
<pre class="c1 c2"><span> </span></pre>
<p class="c1"><span>Then let’s handle implementing the queryTasks() method.  As you can see, it is pretty simple.</span></p>
<pre class="c1"><span> </span>public static List&lt;Task&gt; queryTasks() {</pre>
<pre class="c1"><span class="c0">    return db.findAll();</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<p class="c1"><span>But let’s take a look at what that db.findAll() method does.</span></p>
<p class="c1">&nbsp;</p>
<pre class="c1">public List&lt;Task&gt; findAll() {</pre>
<pre class="c1"><span class="c0"> PersistenceManager pm = PMF.get().getPersistenceManager();</span></pre>
<pre class="c1"><span class="c0"> try {</span></pre>
<pre class="c1"><span class="c0">    Query query = pm.newQuery("select from " + Task.class.getName()</span></pre>
<pre class="c1"><span class="c0">                              + " where emailAddress=='" + getUserEmail() + "'");</span></pre>
<pre class="c1"><span class="c0">     List&lt;Task&gt; list = (List&lt;Task&gt;) query.execute();</span></pre>
<pre class="c1"><span class="c0">     if (list.size() == 0) { //workaround for known issue</span></pre>
<pre class="c1"><span class="c0">     list.size();</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1"><span class="c0"> return lis</span><span class="c0">t;</span></pre>
<pre class="c1"><span class="c0"> } finally {</span></pre>
<pre class="c1"><span class="c0">    pm.close();</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1"><span class="c0">}</span></pre>
<pre class="c1"><span>
</span></pre>
<p class="c1"><span>Notice that query..  the App Engine datastore is a highly scalable no-sql database</span><span>, but you can do sql-like queries over it</span><span>.  In this case, we are looking at the task items, but only those where the emailAddress of the task matches that of the currently logged on user.  So even thought we are storing all the tasks in a single datastore, a given user can only ever access their own tasks.  Notice again how the common notion of identity between app engine and Android really helps us out. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Delete is pretty much what you’d expect.  We actually do delete the item from the datastore, but you could of course use some sort of </span><span class="c3"><a class="c4" href="http://en.wikipedia.org/wiki/Tombstone_(programming)">tombstoning</a></span><span> technique if you’d like.</span></p>
<p class="c1"><span><br />
</span></p>
<p class="c1 c2"><span> </span></p>
<pre class="c1"><span class="c0"> public static void deleteTask(Task task) {</span></pre>
<pre class="c1"><span class="c0">    db.delete(task.getId());</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1 c2"><span> </span></pre>
<pre class="c1"><span>But update is more interesting</span></pre>
<pre class="c1 c2"><span> </span></pre>
<pre class="c1"><span class="c0"> public static Task updateTask(Task task) {</span></pre>
<pre class="c1"><span class="c0">    task.setEmailAddress(DataStore.getUserEmail());</span></pre>
<pre class="c1"><span class="c0">    return db.update(task);</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1 c2"><span> </span></pre>
<p class="c1"><span>As you can see, here we are not just updating the task, but we are also tromping over whatever email address the user sent in.  We are doing this to ensure that no one else tries to submit a task with Larry Page’s email address.  Of course our clients would not allow that, but remeber this is just Json over http, so some rouge client cloud. </span></p>
<p class="c1"><span>The implementation of getUserEmail() is also very basic&#8230; again leveraging the power app engine knowing about google identities.</span></p>
<p class="c1"><span><br />
</span></p>
<pre class="c1"><span class="c0"> public static String getUserEmail() {</span></pre>
<pre class="c1"><span class="c0">    UserService userService = UserServiceFactory.getUserService();</span></pre>
<pre class="c1"><span class="c0">    User user = userService.getCurrentUser();</span></pre>
<pre class="c1"><span class="c0">    return user.getEmail();</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1"><span class="c0">
</span></pre>
<p class="c1"><span>The implementation of db.update() is also very basic.  The hard work is all handed by app engine.</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1">&nbsp;</p>
<pre class="c1"><span class="c0">public Task update(Task item) {</span></pre>
<pre class="c1"><span class="c0"> PersistenceManager pm = PMF.get().getPersistenceManager();</span></pre>
<pre class="c1"><span class="c0"> try {</span></pre>
<pre class="c1"><span class="c0">    pm.makePersistent(item);</span></pre>
<pre class="c1"><span class="c0">    return item;</span></pre>
<pre class="c1"><span class="c0"> } finally {</span></pre>
<pre class="c1"><span class="c0">    pm.close();</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1"><span class="c0">
</span></pre>
<p class="c1"><span>The implementation of create and read are also very simple.</span></p>
<p class="c1">&nbsp;</p>
<pre class="c1"><span class="c0">public static Task createTask() {</span></pre>
<pre class="c1"><span class="c0">    return db.update(new Task());</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1 c2"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> public static Task readTask(Long id) {</span></pre>
<pre class="c1"><span class="c0">    return db.find(id);</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1 c2"><span> </span></pre>
<pre class="c1"><span>
</span></pre>
<p class="c1"><span>Notice in createTask() we round trip the task the datastore in order to get a unique ID for it, such that update can work later. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>While this was very simple, it is also very scalable&#8230;  we have app engine customers storing hundreds of millions of entities using this same pattern. </span></p>
<p class="c1 c2"><span> </span></p>
<h3 class="c5"><a name="h.hqq8vur34lmu"></a><span>Basic GWT Web Client</span></h3>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>OK.. I think we are ready to build the Android app out, but before we do, we hand better do a quick test of these methods.  To do so, I will make some quick modifications to the default GWT web client to simply test each of these methods.</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>So in com.cloudtasks.client.CloudTasks.java I added buttons for Add, Update, Query and Delete.</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>From the Create button, we simply call the “createTask” method, this is the client proxy for the createTask method we implemented in the App Engine project.  We call it off the TaskRequest class which was generated by the RPC tooling wizard. Notice we use a TaskProxy, that is the client proxy for the Task class in the server project. </span></p>
<p class="c1">&nbsp;</p>
<pre class="c1"><span class="c0">private void create() {</span></pre>
<pre class="c1"><span class="c0"> TaskRequest request = taskRequestFactory.taskRequest();</span></pre>
<pre class="c1"><span class="c0"> request.createTask().fire(new Receiver&lt;TaskProxy&gt;() {</span></pre>
<pre class="c1"><span class="c0">    @Override</span></pre>
<pre class="c1"><span class="c0">    public void onSuccess(TaskProxy task) {</span></pre>
<pre class="c1"><span class="c0">       Window.alert("CREATE SUCCESS:(" + task.getId() + ")" );</span></pre>
<pre class="c1"><span class="c0">       taskProxy = task;</span></pre>
<pre class="c1"><span class="c0">   }</span></pre>
<pre class="c1"><span class="c0"> </span> });</pre>
<pre class="c1"><span class="c0">}</span></pre>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image131.jpg" alt="" width="420" height="253" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Update looks just like you’d expect</span></p>
<p class="c1">&nbsp;</p>
<pre class="c1"><span class="c0">private void update(TaskProxy task) {</span></pre>
<pre class="c1"><span class="c0"> TaskRequest request = taskRequestFactory.taskRequest();</span></pre>
<pre class="c1"><span class="c0"> taskProxy = request.edit(taskProxy);</span></pre>
<pre class="c1"><span class="c0"> taskProxy.setName(getTaskName());</span></pre>
<pre class="c1"><span class="c0"> request.updateTask(task).fire(new Receiver&lt;TaskProxy&gt;() {</span></pre>
<pre class="c1"><span class="c0">    @Override</span></pre>
<pre class="c1"><span class="c0">    public void onSuccess(TaskProxy task) {</span></pre>
<pre class="c1"><span class="c0">    Window.alert("UPDATE SUCCESS:(" + task.getId() + "): " + task.getName());</span></pre>
<pre class="c1"><span class="c0">    }</span></pre>
<pre class="c1"><span class="c0"> });</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image161.jpg" alt="" width="426" height="258" /></pre>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Query looks pretty much like you might expect:</span></p>
<pre class="c1"><span> </span><span class="c0">private void query() {</span></pre>
<pre class="c1"><span class="c0"> taskRequestFactory.taskRequest().queryTasks().fire(</span></pre>
<pre class="c1"><span class="c0"> new Receiver&lt;List&lt;TaskProxy&gt;&gt;() {</span></pre>
<pre class="c1"><span class="c0">    @Override</span></pre>
<pre class="c1"><span class="c0">    public void onSuccess(List&lt;TaskProxy&gt; taskList) {</span></pre>
<pre class="c1"><span class="c0">       String names = "\n";</span></pre>
<pre class="c1"><span class="c0">       for (TaskProxy task : taskList) {</span></pre>
<pre class="c1"><span class="c0">          names += " (" + task.getId() + "): " + task.getName() + "\n";</span></pre>
<pre class="c1"><span class="c0">       }</span></pre>
<pre class="c1"><span class="c0">      Window.alert("QUERY SUCCESS: Count[" + taskList.size  </span>+ "] Values:" + names);</pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1"><span class="c0"> });</span></pre>
<pre class="c1 c2"><span> </span></pre>
<pre class="c1"><span>
</span></pre>
<p class="c1"><span>Running it after adding a few more tasks for Larry looks like:</span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image261.jpg" alt="" width="481" height="292" /></p>
<p class="c1"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Now that we have the basic data layer and RPC service complete, it is time for Xav to come up and implement the Android client.</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<h3 class="c5"><a name="h.acgjy7ixq59d"></a><span>Basic Android Client </span></h3>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>We have seen a very basic GWT based client, but now let’s look at how to build out the Android client.  You will notice it looks very similar to the RPC calling code we have shown above.</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>The CloudTasksActivity.java class contains the main activity for the application.  In onCreate() we setup the list adapter.</span></p>
<p class="c1"><span><br />
</span></p>
<p class="c1 c2"><span> </span></p>
<pre class="c1"><span class="c0"> TaskApplication taskApplication = (TaskApplication) getApplication();</span></pre>
<pre class="c1"><span class="c0"> adapter = taskApplication.getAdapter(this);</span></pre>
<pre class="c1"><span class="c0"> listView.setAdapter(adapter);</span></pre>
<pre class="c1 c2"><span> </span></pre>
<p class="c1"><span>Then on onStart() we fetch the tasks, passing -1 to indicate that we need to get all the tasks</span></p>
<p class="c1">&nbsp;</p>
<pre class="c1"><span class="c0">protected void onStart() {</span></pre>
<pre class="c1"><span class="c0"> super.onStart();</span></pre>
<pre class="c1 c2"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0">    // only fetch task on start if the registration has happened.</span></pre>
<pre class="c1"><span class="c0">    SharedPreferences prefs = Util.getSharedPreferences(mContext);</span></pre>
<pre class="c1"><span class="c0">    String deviceRegistrationID = prefs.getString(Util.DEVICE_REGISTRATION_ID, null);</span></pre>
<pre class="c1"><span class="c0">    if (deviceRegistrationID != null) {</span></pre>
<pre class="c1"><span class="c0">    fetchTasks(-1);</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1"><span class="c0">
</span></pre>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Then in CloudTaskActivity.java we  click off an async fetch. </span></p>
<p class="c1">&nbsp;</p>
<pre class="c1"><span class="c0">public void fetchTasks(long id) {</span></pre>
<pre class="c1"><span class="c0">    progressBar.setVisibility(View.VISIBLE);</span></pre>
<pre class="c1"><span class="c0">    if (task != null) {</span></pre>
<pre class="c1"><span class="c0">      task.cancel(true);</span></pre>
<pre class="c1"><span class="c0">    }</span></pre>
<pre class="c1"><span class="c0">    task = new AsyncFetchTask(this);</span></pre>
<pre class="c1"><span class="c0">    task.execute(id);</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1 c2"><span class="c0"> </span></pre>
<p class="c1"><span>The AsyncFetchTask fires the RPC to get the task list.</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1">&nbsp;</p>
<pre class="c1"><span class="c0">protected List&lt;TaskProxy&gt; doInBackground(Long... arguments) {</span></pre>
<pre class="c1"><span class="c0"> final List&lt;TaskProxy&gt; list = new ArrayList&lt;TaskProxy&gt;();</span></pre>
<pre class="c1 c2"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> CloudTasksRequestFactory factory = Util.getRequestFactory(activity,</span></pre>
<pre class="c1"><span class="c0"> CloudTasksRequestFactory.class);</span></pre>
<pre class="c1"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> factory.taskRequest().queryTasks().fire(new Receiver&lt;List&lt;TaskProxy&gt;&gt;() {</span></pre>
<pre class="c1"><span class="c0">    @Override</span></pre>
<pre class="c1"><span class="c0">    public void onSuccess(List&lt;TaskProxy&gt; arg0) {</span></pre>
<pre class="c1"><span class="c0">     list.addAll(arg0);</span></pre>
<pre class="c1"><span class="c0">    }</span></pre>
<pre class="c1"><span class="c0"> });</span></pre>
<pre class="c1 c2"><span class="c0"> </span> return list;</pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1"><span class="c0">
</span></pre>
<p class="c1"><span class="c0">The AsyncFetchTask fires the RPC to get the task list.</span></p>
<p class="c1 c2"><span class="c0"> </span></p>
<p class="c1">&nbsp;</p>
<pre class="c1"><span class="c0">protected List&lt;TaskProxy&gt; doInBackground(Long... arguments) {</span></pre>
<pre class="c1"><span class="c0"> final List&lt;TaskProxy&gt; list = new ArrayList&lt;TaskProxy&gt;();</span></pre>
<pre class="c1 c2"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> CloudTasksRequestFactory factory = Util.getRequestFactory(activity,</span></pre>
<pre class="c1"><span class="c0"> CloudTasksRequestFactory.class);</span></pre>
<pre class="c1"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> factory.taskRequest().queryTasks().fire(new Receiver&lt;List&lt;TaskProxy&gt;&gt;() {</span></pre>
<pre class="c1"><span class="c0">    @Override</span></pre>
<pre class="c1"><span class="c0">     public void onSuccess(List&lt;TaskProxy&gt; arg0) {</span></pre>
<pre class="c1"><span class="c0">     list.addAll(arg0);</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1"><span class="c0"> });</span></pre>
<pre class="c1 c2"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> return list;</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1 c2"><span class="c0"> </span></pre>
<pre class="c1"><span>
</span></pre>
<p class="c1"><span>The AsyncFetchTask fires the RPC to get the task list.</span></p>
<p class="c1 c2"><span class="c0"> </span></p>
<p class="c1">&nbsp;</p>
<pre class="c1"><span class="c0">protected List&lt;TaskProxy&gt; doInBackground(Long... arguments) {</span></pre>
<pre class="c1"><span class="c0"> final List&lt;TaskProxy&gt; list = new ArrayList&lt;TaskProxy&gt;();</span></pre>
<pre class="c1 c2"><span class="c0"> </span></pre>
<pre class="c1">CloudTasksRequestFactory factory = Util.getRequestFactory(activity,</pre>
<pre class="c1"><span class="c0"> CloudTasksRequestFactory.class);</span></pre>
<pre class="c1"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> factory.taskRequest().queryTasks().fire(new Receiver&lt;List&lt;TaskProxy&gt;&gt;() {</span></pre>
<pre class="c1"><span class="c0">    @Override</span></pre>
<pre class="c1"><span class="c0">    public void onSuccess(List&lt;TaskProxy&gt; arg0) {</span></pre>
<pre class="c1"><span class="c0">      list.addAll(arg0);</span></pre>
<pre class="c1"><span class="c0">    }</span></pre>
<pre class="c1"><span class="c0"> });</span></pre>
<pre class="c1 c2"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> return list;</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<pre class="c1 c2"><span> </span></pre>
<p class="c1"><span>And we run it and it looks great!</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image221.jpg" alt="" width="351" height="241" /></p>
<h3 class="c5"><a name="h.n85ao642hfb7"></a><span>Nice GWT Client </span></h3>
<p class="c1"><span>Wow, that Android client looks great, let’s see what we can do to make the GWT client look good as well. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>A few updates to HTML and CSS in the CloudTasks-AppEngine\war folder and some updates to the GWT client code in CloudTasks-AppEngine\com.cloudtasks.client, we get a nice looking web client that can be accessed from anywhere. </span></p>
<p class="c1"><span>One tip for GWT development&#8230;  You don’t need to stop and start GWT Development mode.  Simply hit refresh in the browser and see your changes. </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image241.jpg" alt="" width="632" height="464" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Now, we add a new task, but that task does not show up in the Android client until the user manually refreshes it.    That is not great &#8211; Larry could easily miss tasks he adds via the web page.   We could make the Android client poll the server every few minutes for new tasks, but that is a huge battery and network drain on the device, and creates unnecessary load on the server. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Cloud to Device Messaging to the rescue!  C2DM allows you send a ping the android client to let it know there are new tasks to pick up.   You can’t send a lot of data over this channel, so we will just send the ID of the task to that was updated. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Luckily we have a very convenient place to add this logic on the server.  Let’s look at CloudTasksService.java in the CloudTasks-AppEngine\com.cloudtasks.server directory. </span></p>
<p class="c1 c2"><span> </span></p>
<pre class="c1"><span class="c0"> public static Task updateTask(Task task) {</span></pre>
<pre class="c1"><span class="c0">    task.setEmailAddress(DataStore.getUserEmail());</span></pre>
<pre class="c1"><span class="c0">    task =  db.update(task);</span></pre>
<pre class="c1"><span class="c0">    DataStore.sendC2DMUpdate(TaskChange.UPDATE +
    TaskChange.SEPARATOR + task.getId());</span></pre>
<pre class="c1"><span class="c0"> return task;</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>First, check out that sendC2DMUpdate() method.  The default project makes it very easy to send a C2DM message. </span></p>
<pre class="c1"><span class="c0"> public static void sendC2DMUpdate(String message) {</span></pre>
<pre class="c1"><span class="c0">    UserService userService = UserServiceFactory.getUserService();</span></pre>
<pre class="c1"><span class="c0">    User user = userService.getCurrentUser();</span></pre>
<pre class="c1"><span class="c0">    ServletContext context = RequestFactoryServlet.getThreadLocalRequest().getSession().getServletContext();</span></pre>
<pre class="c1"><span class="c0">    SendMessage.sendMessage(context, user.getEmail(), message);</span></pre>
<pre class="c1"><span class="c0">}</span></pre>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>We call the SendMessage class passing the email address of the owner of the task that was updated.  Recall that we verified this was not spoofed when we updated the task. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>For the messaging, you can see we are using the TaskChange class that we define in the Shared directory.  This ensures that the App Engine server and Android client projects share the exact same definition of this class. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>To run this, we need to reload the App Engine development time server by clicking the refresh button in the Development Mode tab.</span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image171.jpg" alt="" width="611" height="242" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Now, when we run this and add a new task, we get a ping on the Android client.</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image311.jpg" alt="" width="615" height="353" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>That is very cool, but the UI isn’t quite right here.  We really want to just trigger an RPC call for the task when the C2DM message arrives rather than notifying the user.   Luckily that is very easy to do.</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>In the Android project, in C2DMReceiver.java that the default project generated, we want to remove the notifications message and instead handling it programmatic. To do that we replace the onMessage() implementation as follows.</span></p>
<p class="c1 c2"><span> </span></p>
<pre class="c1"><span class="c0"> public void onMessage(Context context, Intent intent) {</span></pre>
<pre class="c1"><span class="c0">    TaskApplication app = (TaskApplication) getApplication();</span></pre>
<pre class="c1"><span class="c0">    app.notifyListener(intent);</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<p class="c1"><span>The in TaskApplication.java we handle the notification. Notice we use the TaskChange class from the shared code directory that we also used in the App Engine project.   To handle it we simply call onTaskUpdated() passing the message which includes the ID of the item being updated. </span></p>
<p class="c1 c2"><span> </span></p>
<pre class="c1"><span class="c0"> public void notifyListener(Intent intent) {</span></pre>
<pre class="c1"><span class="c0">    if (listener != null) {</span></pre>
<pre class="c1"><span class="c0">       Bundle extras = intent.getExtras();</span></pre>
<pre class="c1"><span class="c0">       if (extras != null) {</span></pre>
<pre class="c1"><span class="c0">          String message = (String) extras.get("message");</span></pre>
<pre class="c1"><span class="c0">          String[] messages = message.split(Pattern</span>.quote(TaskChange.SEPARATOR));</pre>
<pre class="c1"><span class="c0">          listener.onTaskUpdated(messages[0], Long.parseLong(messages[1]));</span></pre>
<pre class="c1"><span class="c0">       }</span></pre>
<pre class="c1"><span class="c0">    }</span></pre>
<pre class="c1"><span class="c0"> }</span></pre>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Finally, we do the actual update:</span></p>
<p class="c1 c2"><span> </span></p>
<pre class="c1"><span class="c0"> public void onTaskUpdated(final String message, final long id) {</span></pre>
<pre class="c1"><span class="c0">    runOnUiThread(new Runnable() {</span></pre>
<pre class="c1"><span class="c0">    public void run() {</span></pre>
<pre class="c1"><span class="c0">       if (TaskChange.UPDATE.equals(message)) {</span></pre>
<pre class="c1"><span class="c0">         fetchTasks(id);</span></pre>
<pre class="c1"><span class="c0">       }</span></pre>
<pre class="c1"><span class="c0">   }</span></pre>
<pre class="c1"><span class="c0"> });</span></pre>
<p class="c1"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Now we can see when I add a new task via the web front end, I get the wait icon while an async fetch of that task is done.</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image251.jpg" alt="" width="344" height="116" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>then magically the new task just shows up with the minimum of battery life and network.</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image111.jpg" alt="" width="353" height="374" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>And of course, this works two way&#8230; when you add a new task from the android phone, the browser app automatically updates without a refersh. </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image091.jpg" alt="" width="351" height="570" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image281.jpg" alt="" width="553" height="406" /></p>
<p class="c1 c2"><span> </span></p>
<h3 class="c5"><a name="h.pjpdw3n2vqfq"></a><span>Deployment </span></h3>
<p class="c1"><span>The final step here is to deploy your application to the production app engine.  This is very easy to do from eclipse. </span></p>
<p class="c1"><span>First you go to </span><span class="c3"><a class="c4" href="https://appengine.google.com/">https://appengine.google.com/</a></span><span> and create an App ID.  Go ahead it is free to get started! </span></p>
<p class="c1"><span>Next go to the Android project and find the Setup.java file and update the App name to match the one you just created. </span></p>
<p class="c1 c2"><span> </span></p>
<pre class="c1"><span class="c0">public class Setup {</span></pre>
<pre class="c1 c2"><span class="c0"> </span></pre>
<pre class="c1"><span class="c0"> /**</span></pre>
<pre class="c1"><span class="c0"> * The AppEngine app name, used to construct the production service URL</span></pre>
<pre class="c1"><span class="c0"> * below.</span></pre>
<pre class="c1"><span class="c0"> */</span></pre>
<pre class="c1"><span class="c0"> private static final String APP_NAME = "androidcloudtasks";</span></pre>
<pre class="c1 c2"><span class="c0"> </span></pre>
<pre class="c1 c2"><span class="c0"> </span></pre>
<pre class="c1"><span>Then you click on the App Engine button and select the App Engine Project to deploy.</span></pre>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image061.jpg" alt="" width="570" height="419" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Next click on App Engine project settings and verify that the correct Application ID is set.   Notice you can also change the version string.   You can use things like “beta” or “testing” as well as numbers.  This helps with the staging, testing, release process. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image051.jpg" alt="" width="588" height="432" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Then you click deploy.   It might take a while for the project to build.  GWT creates very optimized  javascript for different classes of browsers.   Once it is done you should be able to browse to </span><span class="c3"><a class="c4" href="http://yourappid.appspot.com">http://yourappid.appspot.com</a></span><span>.</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Notice that asks you to log in.   This is for real, unlike the test client.  So you need to give a valid google ID. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image011.jpg" alt="" width="555" height="229" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Next, App Engine verifies that the user is giving permission for your application to use their email address. </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image001.jpg" alt="" width="521" height="300" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>Finally, we see the application running.   Notice that you will not see any data at first as this is running against the live App Engine server.  You will need to add some tasks here&#8230; but once you do you can access them from any web browser anywhere and a nice rich client on your phone! </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><img src="http://bradabrams.com/wp-content/uploads/2011/05/image331.jpg" alt="" width="597" height="391" /></p>
<p class="c1 c2"><span> </span></p>
<p class="c1 c2"><span> </span></p>
<h3 class="c5"><a name="h.b2uwfbisb3y1"></a><span>Summary </span></h3>
<p class="c1"><span>Wow &#8211; that was a whole load of stuff.   Just to review:</span></p>
<p class="c1 c6" style="padding-left: 30px;"><span>1. We created a new App Engine connected Android project with built in support for C2DM and RPC.</span></p>
<p class="c1 c6" style="padding-left: 30px;"><span>2. We add a data layer in App Engine for storing tasks</span></p>
<p class="c1 c6" style="padding-left: 30px;"><span>3. Exposed it over RPC</span></p>
<p class="c1 c6" style="padding-left: 30px;"><span>4. Built an Android client for viewing and updating tasks</span></p>
<p class="c1 c6" style="padding-left: 30px;"><span>5. Built a standards based GWT client for viewing and updating tasks</span></p>
<p class="c1 c6" style="padding-left: 30px;"><span>6. plumbed in C2DM for doing push notifications of new tasks</span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>All in less than 45 mins!    Imagine what you can do! </span></p>
<p class="c1 c2"><span> </span></p>
<p class="c1"><span>We’d love your feedback on BigDaddy (GPE 2.4)&#8230;  Please post the the </span><span class="c3"><a class="c4" href="http://groups.google.com/group/Google-Web-Toolkit">GWT forums </a></span><span>or comment here.</span></p>
]]></content:encoded>
			<wfw:commentRss>http://bradabrams.com/2011/05/google-io-session-overview-android-app-engine-a-developers-dream-combination/feed/</wfw:commentRss>
		<slash:comments>62</slash:comments>
		</item>
		<item>
		<title>Under the Dome Book Review</title>
		<link>http://bradabrams.com/2010/12/under-the-dome-book-review/</link>
		<comments>http://bradabrams.com/2010/12/under-the-dome-book-review/#comments</comments>
		<pubDate>Sat, 25 Dec 2010 19:23:25 +0000</pubDate>
		<dc:creator>Brad Abrams</dc:creator>
				<category><![CDATA[Book Review]]></category>

		<guid isPermaLink="false">http://bradabrams.com/?p=42</guid>
		<description><![CDATA[I have never been a big Stephen King fan.  His work always struck me as horror-and-gore fare that I’d just as soon avoid.  But when my brother-in-law gave me a copy of Under the Dome and told me it was actually more of a science fiction book, I thought I’d give it a try. I [...]]]></description>
				<content:encoded><![CDATA[<div style="float: left;" ><g:plusone  position="prepend" size="standard" count="1" href="http://bradabrams.com/2010/12/under-the-dome-book-review/" text="Under the Dome Book Review" ></g:plusone></div>
<div><a href="http://bradabrams.com/wp-content/uploads/2010/12/n305882.jpg"><img class="alignleft" title="Under the done" src="http://bradabrams.com/wp-content/uploads/2010/12/n305882-193x300.jpg" alt="Under the Dome Book Cover" width="193" height="300" /></a>I have never been a big Stephen King fan.  His work always struck me as horror-and-gore fare that I’d just as soon avoid.  But when my brother-in-law gave me a copy of <a href="https://www.amazon.com/dp/1439148503?tag=bradabramsblo-20&amp;camp=213381&amp;creative=390973&amp;linkCode=as4&amp;creativeASIN=1439148503&amp;adid=131GP9F0WV0NSK2YXXFW&amp;">Under the Dome</a> and told me it was actually more of a science fiction book, I thought I’d give it a try.<br />
I was quickly immersed in the odd predicament the good citizens of <a href="http://www.chestersmill.com/">Chester&#8217;s Mill </a>find themselves in when the dome comes down.  The best science fiction unfolds from the natural results when extraordinary events happen to normal people.  That is just what King does in <a href="https://www.amazon.com/dp/1439148503?tag=bradabramsblo-20&amp;camp=213381&amp;creative=390973&amp;linkCode=as4&amp;creativeASIN=1439148503&amp;adid=131GP9F0WV0NSK2YXXFW&amp;">Under the Dome.</a> We get to know a large and complex set of characters as they struggle with the implications of the dome.<br />
While all the events of the book take place in a small Maine town, the parallels for the rest of the world are clear.    The world has a larger, but equally finite atmosphere and the world also has despots that prey on the fears of the people to lead them down hell’s path.  King lets us see clearly the stages of the fall.  From the “we all support the team” to fear mongering at a grocery store.  We see a set of small decisions can lead to utter disaster.   By the end I found myself wishing the 1074 page book was a bit longer <img src='http://bradabrams.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>I did quickly lose interest in carrying such a big book around, so I bought <a href="https://www.amazon.com/dp/B0030H7UIU?tag=bradabramsblo-20&amp;camp=213381&amp;creative=390973&amp;linkCode=as4&amp;creativeASIN=B0030H7UIU&amp;adid=09A93M09H2QWEMYA2R7S&amp;">the Kindle version</a>.  I found the reading experience fantastic.  I easily prefer <a href="https://www.amazon.com/dp/B002Y27P3M?tag=bradabramsblo-20&amp;camp=213381&amp;creative=390973&amp;linkCode=as4&amp;creativeASIN=B002Y27P3M&amp;adid=1Y9VK363VR8P23DB4766&amp;">my wife’s Kindle </a>to a real book and <a href="http://www.amazon.com/gp/redirect.html?ie=UTF8&amp;location=http%3A%2F%2Fwww.amazon.com%2Fgp%2Ffeature.html%3Fie%3DUTF8%26ref_%3Dred_lnd_shrt_url%26docId%3D165849822&amp;tag=bradabramsblo-20&amp;linkCode=ur2&amp;camp=1789&amp;creative=390957">the Android version</a> was very good.  Having them kept in sync was very helpful.. I never lost my page.</p>
<p>Some fun with Under the Dome on the Web:</p>
<blockquote>
<ul>
<li><a href="http://www.bigjimrennie.com/">Big Jim Rennie&#8217;s Used Cars</a></li>
<li><a href="http://www.sweetbriarrose.com/">Sweet Briar Rose Diner</a></li>
<li><a href="http://www.chestersmilldemocrat.com/">Chester&#8217;s Mill Democrat Newspaper</a></li>
<li><a href="http://www.chestersmill.com/">Town of Chester&#8217;s Mill</a></li>
<li><a href="http://www.scarecrowjoe.com/">the blog of Scarecrow Joe</a></li>
</ul>
</blockquote>
<p>Enjoy!</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://bradabrams.com/2010/12/under-the-dome-book-review/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>PM Tips: Product Manager Tips</title>
		<link>http://bradabrams.com/2010/12/pm-tips-product-manager-tips/</link>
		<comments>http://bradabrams.com/2010/12/pm-tips-product-manager-tips/#comments</comments>
		<pubDate>Sat, 25 Dec 2010 02:23:46 +0000</pubDate>
		<dc:creator>Brad Abrams</dc:creator>
				<category><![CDATA[PM Tips]]></category>

		<guid isPermaLink="false">http://bradabrams.com/?p=37</guid>
		<description><![CDATA[Over the years I have collected a few tips on how to run software projects.  Many of these are from my days at Microsoft, but I hope to be adding some soon from my (new) days at Google. PM Tip #10: Interview Tips for Landing a Great Program Management Job PM tip# 11: Information is [...]]]></description>
				<content:encoded><![CDATA[<div style="float: left;" ><g:plusone  position="prepend" size="standard" count="1" href="http://bradabrams.com/2010/12/pm-tips-product-manager-tips/" text="PM Tips: Product Manager Tips" ></g:plusone></div>
<p> Over the years I have collected a few tips on how to run software projects.  Many of these are from my days at Microsoft, but I hope to be adding some soon from my (new) days at Google.</p>
<ul>
<li><a href="http://blogs.msdn.com/brada/archive/2009/06/24/pm-tip-10-interview-tips-for-landing-a-great-program-management-job.aspx">PM Tip #10: Interview Tips for Landing a Great Program Management Job</a></li>
<li><a id="ctl00___ctl00___ctl01___Results___postlist___EntryItems_ctl14_PostTitle" href="http://blogs.msdn.com/brada/archive/2006/04/10/InformationIsTheCurrency.aspx"><span style="color: #176db5;">PM tip# 11: Information is the Currency of Program Management</span></a></li>
<li><a href="https://blogs.msdn.com/brada/archive/2007/10/24/pm-tip-14-great-teams-have-members-that-defy-roles.aspx">PM Tip #14: Great teams have members that defy roles</a></li>
<li><a href="https://blogs.msdn.com/brada/archive/2007/05/06/pm-tip-12-don-t-waist-keystrokes.aspx">PM Tip #12: Don&#8217;t waste keystrokes</a></li>
<li><a href="http://blogs.msdn.com/brada/archive/2006/02/22/536644.aspx">PM Tip #21: Sanity Will Prevail</a></li>
<li><a href="http://blogs.msdn.com/brada/archive/2006/02/21/535235.aspx">PM Tip # 32: Nothing kills excitement like ambiguity</a></li>
<li><a href="https://blogs.msdn.com/brada/archive/2006/02/03/522857.aspx">PM Tip #57: Write the agenda on the board</a></li>
<li><a href="http://blogs.msdn.com/brada/archive/2006/03/30/564573.aspx">PM Tip #72 Instant feedback&#8230;</a></li>
<li><a href="http://blogs.msdn.com/brada/archive/2006/01/28/BeMoreVisibleSham.aspx">PM Tip #73: The &#8220;Be More Visible&#8221; Sham</a></li>
<li><a id="ctl00___ctl00___ctl01___Results___postlist___EntryItems_ctl06_PostTitle" href="http://blogs.msdn.com/brada/archive/2005/12/17/RevealYourStupidity-.aspx">PM Tip  #78: Reveal your stupidity</a></li>
</ul>
<p>Some bonus material:</p>
<ul>
<li><a href="http://blogs.msdn.com/brada/archive/2009/03/27/presentation-tip-they-remember-the-mistakes-more-than-the-polish.aspx">Presentation tip: They Remember the Mistakes more than the Polish</a></li>
<li><a href="http://blogs.msdn.com/brada/archive/2006/12/23/building-consensus.aspx">Building Consensus</a></li>
<li><a id="ctl00___ctl00___ctl01___Results___postlist___EntryItems_ctl06_PostTitle" href="http://blogs.msdn.com/brada/archive/2007/07/28/that-is-a-full-day-s-work.aspx"><span style="color: #176db5;">That is a full day&#8217;s work!</span></a></li>
<li><a id="ctl00___ctl00___ctl01___Results___postlist___EntryItems_ctl12_PostTitle" href="http://blogs.msdn.com/brada/archive/2006/10/07/The-What-and-the-How.aspx"><span style="color: #176db5;">The What and the How</span></a></li>
<li><a id="ctl00___ctl00___ctl01___Results___postlist___EntryItems_ctl13_PostTitle" href="http://blogs.msdn.com/brada/archive/2006/09/09/748066.aspx"><span style="color: #176db5;">Thoughts on writing reviews&#8230;</span></a></li>
<li><a href="http://blogs.msdn.com/brada/archive/2007/05/18/the-wisdom-of-crowds-rethinking-consensus.aspx">The Wisdom of Crowds: Rethinking consensus</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://bradabrams.com/2010/12/pm-tips-product-manager-tips/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>My Day in the Chair</title>
		<link>http://bradabrams.com/2010/08/my-day-in-the-chair/</link>
		<comments>http://bradabrams.com/2010/08/my-day-in-the-chair/#comments</comments>
		<pubDate>Wed, 11 Aug 2010 15:34:01 +0000</pubDate>
		<dc:creator>Brad Abrams</dc:creator>
				<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://bradabrams.com/?p=31</guid>
		<description><![CDATA[Today I will spend about 360 minutes or about 6 hours in the chair.   They are taking blood out of my left arm, pushing it through a apheresis machine and putting in back in my right arm. The machine uses a centrifuge to separate out the red blood cells, plasma and white blood cells.  They [...]]]></description>
				<content:encoded><![CDATA[<div style="float: left;" ><g:plusone  position="prepend" size="standard" count="1" href="http://bradabrams.com/2010/08/my-day-in-the-chair/" text="My Day in the Chair" ></g:plusone></div>
<div>Today I will spend about 360 minutes or about 6 hours in the chair.   They are taking blood out of my left arm, pushing it through a <a href="http://en.wikipedia.org/wiki/Apheresis">apheresis machine </a>and putting in back in my right arm. The machine uses a centrifuge to separate out the red blood cells, plasma and white blood cells.  They are grabbing some of the white blood cells that contain stem cells and putting them in a bag.  In my time in the chair the complete volume of my blood will flow through the machine three times.</p>
<p>I am donating for the <a href="http://www.marrow.org/">National Bone Marrow Donors Program.</a> I know very little about the recipient.  She is 44 years old, could be living anywhere in the world, and has a rare form of leukemia.  Without a transplant, she will die.</p>
<p>Over the last 5 days, I have come in each morning to get a shot of filgrastim that has greatly raised my stem cell count and caused minor headaches and bone aches in the process.  In the same time, the recipient has been getting a massive dose of chemo and radiation to hopefully completely kill off her cancer.  Being a crude, imprecise tool that it is, it has also killed off all her bone marrow.  By this time her body has lost its ability to produce blood cells.  She is living off whole blood donations, but those cells die off in matter of days.   A medical courier is standing by ready to fly my stem cells to her, where they will hopefully begin to re-grow bone marrow in her, which will produce the blood cells she needs in order to live.</p>
<p>This all started years ago.. when I was in high-school.  I gave blood for the Red Cross mostly to impress girls.  One time I checked a box to join the <a href="http://www.marrow.org/">National Bone Marrow Donors Program</a> having no real idea what that meant.  Nearly 18 years later, they called me and said I was a possible match.   Only about 1 in 100 folks who are a possible matches turn out to be close enough to actually donate.  So I went to the local blood bank and they took a few vials of blood to do further testing.  I didn’t think about it for weeks.  Then I got the call&#8230;  I was a perfect match!  They did a complete physical to ensure I was healthy enough to donate and it would be safe for her.</p>
<p>I have not often prayed specifically for someone I do not know, but my thoughts have been with her these last few weeks.  I don’t know if she is a mom, an aunt, a sister-in-law.  But I bet she has a wedding, graduation, or birthday to go to.  With this treatment she has a 40% chance of living.  Not fantastic odds, but way better than her chances without it.</p>
<p>Some donors are able to find a match among family, but even though you may have a lot in common with your brother, there is no guarantee that the specific six factors that affect marrow rejection will be among them.  That is where the <a href="http://www.marrow.org/">National Bone Marrow Donors Program</a> comes in.  They find matches anywhere in the world.  But of course only among those in the registry.</p>
</div>
<div><a href="http://www.marrow.org/JOIN/Join_Now/join_now.html">Please consider joining</a>!</div>
]]></content:encoded>
			<wfw:commentRss>http://bradabrams.com/2010/08/my-day-in-the-chair/feed/</wfw:commentRss>
		<slash:comments>18</slash:comments>
		</item>
		<item>
		<title>Why Google Cares About Developers</title>
		<link>http://bradabrams.com/2010/08/why-google-cares-about-developers/</link>
		<comments>http://bradabrams.com/2010/08/why-google-cares-about-developers/#comments</comments>
		<pubDate>Sun, 01 Aug 2010 19:06:49 +0000</pubDate>
		<dc:creator>Brad Abrams</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://bradabrams.com/?p=25</guid>
		<description><![CDATA[A couple of folks have pointed out that I haven’t blog a bunch since I joined Google.  Rest assured I have not lost my passion for blogging nor does Google frown on blogging by its employees (quite the opposite in fact).    I have been spending the time getting my head around Google.  I am far [...]]]></description>
				<content:encoded><![CDATA[<div style="float: left;" ><g:plusone  position="prepend" size="standard" count="1" href="http://bradabrams.com/2010/08/why-google-cares-about-developers/" text="Why Google Cares About Developers" ></g:plusone></div>
<div>A couple of folks have pointed out that I haven’t blog a bunch since I joined Google.  Rest assured I have not lost my passion for blogging nor does Google frown on blogging by its employees (quite the opposite in fact).    I have been spending the time getting my head around Google.  I am far from figuring out Google, but I think I have figured it out enough to get started sharing my learnings with you and get your feedback and thoughts.<br />
My first mission at Google (after figuring out the gourmet <a href="http://www.youtube.com/watch?v=Z8k9O3dK6IU">free food</a> of course) was to ask why Google cares about developers.   This needed to be done as some of my friends accused me of going to work for an advertising company after all (they work wrong, Google is a computer science company, but that is for another blog post).</p>
<p>Google cares about developers for one reason: To make web applications better.   Historically, culturally, spiritually and financially Google cares deeply about the web.   Google participates in a virtuous cycle with the web.  The more the web gets better, the better that makes Google, which causes the web to get better.   Clearly this is true in the search and ads space, but it is equally true of our developer assets.  All of our developer assets are in one way or another targeted at making web applications better, which in turn makes the web better.   If Google offers simple, scalable cloud hosting, easy Ajax development tools, great web APIs, the resulting applications will be better and that will make the web better.</p>
<p>As I think about the very broad developer assets google is bringing to bare to make the web better there are four areas that I think are meaningful to look at.</p>
<h3>Web Platform</h3>
<p><a href="http://www.google.com/chrome/">Chrome</a> and the <a href="http://code.google.com/p/v8/">V8 JavaScript engine</a> were built to be a headpin for emerging web standards such as HTML5.  A fast browser that we can use to implement the latest thinking on how the web can get better in the fervent hope that other browser vendors will follow.<br />
But it doesn’t stop there, the royalty free <a href="http://www.webmproject.org/">WebM Video </a>format and the <a href="http://code.google.com/speed/">Make the Web Faster initiative </a>are other examples of where Google is working to make the web platform better.<br />
Check out the <a href="http://blog.chromium.org/2009/06/developer-tools-for-google-chrome.html">Chrome Developer Tools</a> that let you edit, debug, and monitor CSS, HTML, and JavaScript live in any web page and <a href="http://code.google.com/webtoolkit/speedtracer/">Speed Tracer</a> which is a Chrome extension that helps you understand where every millisecond of execution time is going in your  AJAX applications.</p>
<h3>Web APIs</h3>
<p>The web is becoming programmable.  Google is offering very interesting set of services that let you harness its tremendous infrastructure for everything from human language translation to blog feeds.  Check out the <a href="http://code.google.com/apis/ajax/playground/">Google Code Playground</a> to see the full list and play with live code examples right from your browser.  Here is a scenario I thought was interesting&#8230;</p>
<p>You could use the <a href="http://code.google.com/apis/buzz/">Buzz firehouse API </a>to find conversations about your product on the Web, load them into <a href="http://code.google.com/apis/storage/">Google Storage,</a> do advanced queries across the entire dataset with <a href="http://code.google.com/apis/bigquery/">BigQuery</a>,  do <a href="http://en.wikipedia.org/wiki/Sentiment_analysis">sentiment analysis</a> with the <a href="http://code.google.com/apis/predict/">Google Prediction APIs</a>, use the Translate API to get them all to your native language and expose them as a <a href="http://code.google.com/apis/ajaxfeeds/">feed so anyone can access them easily</a>.<br />
The set of scenarios and combinations is enumerable&#8230;  I bet you can come up with a better one!</p>
<h3>Hosting</h3>
<p>As interesting as the web APIs are, you of course need to write your own application logic as well.  Setting up your own server on the Internet is too complex for most of us and many hosting companies are too expense when you just getting started on a side project.   Google offers <a href="http://code.google.com/appengine/">AppEngine</a><a href="http://code.google.com/appengine/"> </a>which makes it easy to build, maintain and scale your application.   You build your app and Google handles all the plumbing work.  We run the application in our data centers so you don’t need to have someone on “pager-duty” to keep a watch on the servers and they can scale almost limitlessly on a moments notice<a href="http://code.google.com/appengine/"> </a>when your side project hits it big.  And the best part &#8212; you pay for only what you need and it is free to get started.  There is no base cost, you pay only when your app is working.</p>
<h3>Tools</h3>
<p>Great engineers use great tools and Google offers some of the best tools to help you build better web applications.</p>
<p>The <a href="http://code.google.com/webtoolkit/">Google Web Toolkit </a>(produced “gwit” by many Googlers) lets you write complex Ajax applications in Java and compile them to JavaScript that works on any browser.   Recently with our <a href="http://www.vmware.com/company/news/releases/vmware-google.html">partnership</a> with <a href="http://www.springsource.com/">VMware Springsource </a>you can use the very popular enterprise java framework Spring to build the back-end of your application and get great portability that works on premises, on AppEngine or many other hosting providers.</p>
<p><a href="http://code.google.com/closure/">Closure</a> offers (among other things) an optimizing JavaScript compiler.  It takes as input JavaScript and uses common compiler techniques such as dead code removal,  identifier renaming to greatly reduce the size of your javascript which improves the latency of your Ajax apps.  You can even use the <a href="http://closure-compiler.appspot.com/home">hosted version of the compiler.</a></p>
<p>Of course you need somewhere to store all that great source code, track issues, document and share releases. And what better place than the Cloud!  Google offers free <a href="http://code.google.com/p/support/wiki/GettingStarted">Project Hosting</a> for open-source projects.</p>
<h3>And more to come&#8230;</h3>
<p>Google has a passion and history for rapid innovation and the developer space is no exception.   There are more exciting things to come.   It is a great time to be a web developer!</p>
<p>That is my learnings so far about Google and the developer space.. I hope they were valuable to you.   I’d love to hear your comments\thoughts and feedback.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://bradabrams.com/2010/08/why-google-cares-about-developers/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Going Google</title>
		<link>http://bradabrams.com/2010/05/going-google/</link>
		<comments>http://bradabrams.com/2010/05/going-google/#comments</comments>
		<pubDate>Mon, 03 May 2010 20:06:14 +0000</pubDate>
		<dc:creator>Brad Abrams</dc:creator>
				<category><![CDATA[Personal]]></category>

		<guid isPermaLink="false">http://bradabrams.com/2010/05/going-google/</guid>
		<description><![CDATA[“Going Google” is the phrase companies use when they choose to move over to Google Apps for some of their IT needs.&#160; I will be &#34;going Google&#34; on a more personal level &#8212; I have accepted a position in Product Management at Google! We are still working on the details of exactly what I will [...]]]></description>
				<content:encoded><![CDATA[<div style="float: left;" ><g:plusone  position="prepend" size="standard" count="1" href="http://bradabrams.com/2010/05/going-google/" text="Going Google" ></g:plusone></div>
<p>“Going Google” is the phrase companies use when they choose to move over to Google Apps for some of their IT needs.&#160; I will be &quot;going Google&quot; on a more personal level &#8212; I have accepted a position in Product Management at Google! We are still working on the details of exactly what I will be working on but it will be something in cloud/web development space and I will be based here in Kirkland/Seattle.</p>
<p><a href="http://bradabrams.com/wp-content/uploads/2010/04/image.png"><img title="image" border="0" alt="image" src="http://bradabrams.com/wp-content/uploads/2010/04/image_thumb.png" width="240" height="94" /></a></p>
<p><b>Why did I make this transition?</b></p>
<p>I needed a change personally, to learn something new, see the tech world from a fresh perspective. And what better place than Google! As I look at where things are going in the industry (and where I think they should go), it is clear that the web, and cloud+devices specifically, are the dominant trends of the future. Working at Google will give me an opportunity to have a deep and meaningful impact on that future.</p>
<p>Google has benefited more than any other company from the rapid growth of the web and as such they have a responsibility to help the web grow to the next level. I am excited to see what that will look like: from the ubiquity of the rich web with HTML5 to the maturing of the cloud as an integral part of every company&#8217;s IT portfolio to open, powerful personal devices to help us navigate it all anywhere. I am excited to work at Google to help make the future arrive sooner <img src='http://bradabrams.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> </p>
<p>As far as exactly what I will do – I don’t know yet. But I have a huge passion for building and releasing software and love the developer space. I am super excited that my first week at Google will be spent at <a href="http://code.google.com/events/io/2010/">Google I/O</a>. This conference has been sold out for weeks, so I guess the only way you can attend now is to join Google <img src='http://bradabrams.com/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' /> .&#160; If you are going, I’d love to connect.&#160; I clearly have a lot to learn!&#160; </p>
<p>This is obviously a HUGE change for me and I’d love to hear any advice or thoughts you have as I make the transition to being a Noogler (a new Google employee).</p>
]]></content:encoded>
			<wfw:commentRss>http://bradabrams.com/2010/05/going-google/feed/</wfw:commentRss>
		<slash:comments>95</slash:comments>
		</item>
		<item>
		<title>Book Review: Beggars in Spain</title>
		<link>http://bradabrams.com/2010/04/book-review-beggars-in-spain/</link>
		<comments>http://bradabrams.com/2010/04/book-review-beggars-in-spain/#comments</comments>
		<pubDate>Sat, 24 Apr 2010 02:49:19 +0000</pubDate>
		<dc:creator>Brad Abrams</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Books]]></category>

		<guid isPermaLink="false">http://bradabrams.com/2010/04/book-review-beggars-in-spain/</guid>
		<description><![CDATA[Only a few hours into my time off and I accomplished my first goal.&#160;&#160; I finished reading Beggars in Spain today.&#160;&#160; Clearly a great book that really made me think.&#160;&#160; It has the basic scifi stuff I like such as a view of the future, genetic engineering, a new form of cheap energy and its [...]]]></description>
				<content:encoded><![CDATA[<div style="float: left;" ><g:plusone  position="prepend" size="standard" count="1" href="http://bradabrams.com/2010/04/book-review-beggars-in-spain/" text="Book Review: Beggars in Spain" ></g:plusone></div>
<p>Only a few hours into my time off and I accomplished my first goal.&#160;&#160; I finished reading <a href="http://www.amazon.com/gp/product/B000AEFEMA?ie=UTF8&amp;tag=bradabramsblo-20&amp;link_code=as3&amp;camp=211189&amp;creative=373489&amp;creativeASIN=B000AEFEMA"><u>Beggars in Spain</u></a> today.&#160;&#160; Clearly a great book that really <a href="http://www.amazon.com/gp/product/B000AEFEMA?ie=UTF8&amp;tag=bradabramsblo-20&amp;link_code=as3&amp;camp=211189&amp;creative=373489&amp;creativeASIN=B000AEFEMA"><img style="border-bottom: 0px; border-left: 0px; margin: 0px 15px 0px 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" align="left" src="http://bradabrams.com/wp-content/uploads/2010/04/image2.png" width="164" height="244" /></a>made me think.&#160;&#160; It has the basic scifi stuff I like such as a view of the future, genetic engineering, a new form of cheap energy and its effect on the economy.&#160;&#160;&#160; </p>
<p>The book starts by proposing an interesting question:&#160; are we wasting time sleeping.&#160;&#160; Personally, I love to sleep, but it does feel like a waste of almost 1/3 of our lives sometimes.&#160;&#160; </p>
<p>But <a href="http://www.amazon.com/gp/product/B000AEFEMA?ie=UTF8&amp;tag=bradabramsblo-20&amp;link_code=as3&amp;camp=211189&amp;creative=373489&amp;creativeASIN=B000AEFEMA"><u>Beggars in Spain</u></a> is not about the scifi nor this “sleeper” question.&#160; The books heart is about how the strong relate to the weak.&#160; Do the weak have any claims on the strong?&#160; Does a poor beggar in Spain have any right to ask for money or help from a the rich?&#160;&#160;&#160; Oddly enough, I found my free-market economy, <a href="https://www.amazon.com/dp/1420932063?tag=bradabramsblo-20&amp;camp=213381&amp;creative=390973&amp;linkCode=as4&amp;creativeASIN=1420932063&amp;adid=0Q32Y3KCWN8MN5PWAPXM&amp;"><u>The Wealth of Nations</u></a>, roots agreeing with one of the main characters that “the weak have no claims on the strong”.&#160; But as they find out, this is a shallow argument.&#160; My personal view is while the weak may have no claims on the strong, the strong DO have an obligation on the weak.&#160; Not only because the weak may one day be strong (as the book argues) but because we are all created by God and of certain inalienable value.&#160; </p>
<p>Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://bradabrams.com/2010/04/book-review-beggars-in-spain/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>Stay Tuned!</title>
		<link>http://bradabrams.com/2010/04/stay-tuned/</link>
		<comments>http://bradabrams.com/2010/04/stay-tuned/#comments</comments>
		<pubDate>Mon, 19 Apr 2010 02:15:25 +0000</pubDate>
		<dc:creator>Brad Abrams</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://bradabrams.com/2010/04/stay-tuned/</guid>
		<description><![CDATA[Look for more information about what I will be doing next….]]></description>
				<content:encoded><![CDATA[<div style="float: left;" ><g:plusone  position="prepend" size="standard" count="1" href="http://bradabrams.com/2010/04/stay-tuned/" text="Stay Tuned!" ></g:plusone></div>
<p>Look for more information about what I will be doing next….</p>
]]></content:encoded>
			<wfw:commentRss>http://bradabrams.com/2010/04/stay-tuned/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
	</channel>
</rss>
