Google IO Session Overview: Android + App Engine: A Developer’s Dream Combination

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.

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.  ;-)

The basic architecture of the task app looks very similar to a wide range of applications

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 app engine datastore. 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 GWT to keep with the same programing language and tools, but of course, any web client technology will work.   Finally, we use C2DM to do push notification when new tasks are added to the database.

OK, so let’s look at how we build this task tracking application.

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:

1. An authenticated Hello world RPC service with the logic in app engine and clients in GWT and Android.

2. All the C2DM infrastructure .

a. App Engine based datastore for handing registration

b. Android client with default UI for picking a user and responding to C2DM messaging

c. GWT based client for sending C2DM pings through the app engine server.

Let’s take a look at how this works.

Creating the Starter Project

In Eclipse select FileNew then Other.  Under the Android node you will find the “App Engine connected Android project”.

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.

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.

The next page of the wizard asks for your C2DM role account.  You can sign up for a C2DM role account from this wizard.

A tip: You can auto fill this in if you put a file called c2dm.properties in your home directory with the format:

user=yourid@gmail.com
passwd=yourpassword

This wizard creates two projects… An Android client and App Engine server. Along with a shared code directory for storing code that is compiled into both projects.

To run this, you will want to connect your android phone via USB or create an virtual device via the Android SDK and AVD manager and launch it.  For the AVD I found targeting google API level 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.

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.

Running the Starter Project

Once you have a device connected, you right click on the Android project and select Debug As then Local App Engine Connected Android Project.

What this does is wire up the android application to talk to the local app engine dev app server.

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 — 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.

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 http://127.0.0.1:8888/_ah/admin/ and select DataStore viewer.

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.

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.

 public static String getMessage() {
 UserService userService = UserServiceFactory.getUserService();
 User user = userService.getCurrentUser();
 String message;
 if (user == null) {
    message = "No one is logged in!nSent from App Engine at " + new Date();
 } else {
    message = "Hello, " + user.getEmail() + "!nSent from App Engine at " + new Date();
 }
 log.info("Returning message "" + message + """);
 return message;
 }

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.

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.

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.

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:

 <security-constraint>
 <web-resource-collection>
    <url-pattern>/*</url-pattern>
 </web-resource-collection>
 <auth-constraint>
    <role-name>*</role-name>
 </auth-constraint>
 </security-constraint>

This indicates that all urls in this project require authentication.

You could easily add another node if you wanted some unsecured access URLs for general information, etc.  See the App Engine documentation for more information. 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 more information.   We log in with the same email address as we used on the android client.  That will be important later when we share data.

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.

Sending  a C2DM Ping

Now, let’s send a C2DM ping.

Notice I use the same email address as I logged into my Android phone with.

Then I flip over to the phone and presto… A C2DM message arrives.

So that is basically what is in the starter app.  A very solid way to get started!

Want to try it live yourself?   Check out the running app here:

http://bigdaddy-io.appspot.com/

You can install the APK from this site on your phone.

Be sure to log in to the android app before you test sending C2DM pings


Tasks Data Layer and RPC Layer

Now let’s focus on building out the custom logic for our task tracking application for Larry Page.

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.

Here is a snippet of it.. a very simple java class with no data access logic.. Just fields and accessors.

@Entity
public class Task {
 
 private String name;
 private String notes;
 private Date dueDate;
 
 @Id
 @GeneratedValue(strategy = GenerationType.IDENTITY)
 private Long id;
 
 private String userId;
 private String emailAddress;
 
 public Task () {}
 
 
 public String getName() {
    return name;
 }
 
 

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.

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.

As you can see, the wizard looks in your server project for all the entities (marked with an attribute of “@Entity” 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.

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 App Engine’s Datastore.

I wrote a simple data layer that uses JDO to store entities.  I called the class DataStore.

First, let’s create an instance of the DataStore:

public class CloudTasksService {
 
   static DataStore db = new DataStore();
 

Then let’s handle implementing the queryTasks() method.  As you can see, it is pretty simple.

 public static List<Task> queryTasks() {
    return db.findAll();
 }

But let’s take a look at what that db.findAll() method does.

 

public List<Task> findAll() {
 PersistenceManager pm = PMF.get().getPersistenceManager();
 try {
    Query query = pm.newQuery("select from " + Task.class.getName()
                              + " where emailAddress=='" + getUserEmail() + "'");
     List<Task> list = (List<Task>) query.execute();
     if (list.size() == 0) { //workaround for known issue
     list.size();
 }
 return list;
 } finally {
    pm.close();
 }
}

Notice that query..  the App Engine datastore is a highly scalable no-sql database, but you can do sql-like queries over it.  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.

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 tombstoning technique if you’d like.


 public static void deleteTask(Task task) {
    db.delete(task.getId());
 }
 
But update is more interesting
 
 public static Task updateTask(Task task) {
    task.setEmailAddress(DataStore.getUserEmail());
    return db.update(task);
 }
 

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.

The implementation of getUserEmail() is also very basic… again leveraging the power app engine knowing about google identities.


 public static String getUserEmail() {
    UserService userService = UserServiceFactory.getUserService();
    User user = userService.getCurrentUser();
    return user.getEmail();
 }

The implementation of db.update() is also very basic.  The hard work is all handed by app engine.

 

public Task update(Task item) {
 PersistenceManager pm = PMF.get().getPersistenceManager();
 try {
    pm.makePersistent(item);
    return item;
 } finally {
    pm.close();
 }
 }

The implementation of create and read are also very simple.

 

public static Task createTask() {
    return db.update(new Task());
 }
 
 public static Task readTask(Long id) {
    return db.find(id);
 }
 

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.

While this was very simple, it is also very scalable…  we have app engine customers storing hundreds of millions of entities using this same pattern.

Basic GWT Web Client

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.

So in com.cloudtasks.client.CloudTasks.java I added buttons for Add, Update, Query and Delete.

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.

 

private void create() {
 TaskRequest request = taskRequestFactory.taskRequest();
 request.createTask().fire(new Receiver<TaskProxy>() {
    @Override
    public void onSuccess(TaskProxy task) {
       Window.alert("CREATE SUCCESS:(" + task.getId() + ")" );
       taskProxy = task;
   }
  });
}

Update looks just like you’d expect

 

private void update(TaskProxy task) {
 TaskRequest request = taskRequestFactory.taskRequest();
 taskProxy = request.edit(taskProxy);
 taskProxy.setName(getTaskName());
 request.updateTask(task).fire(new Receiver<TaskProxy>() {
    @Override
    public void onSuccess(TaskProxy task) {
    Window.alert("UPDATE SUCCESS:(" + task.getId() + "): " + task.getName());
    }
 });
 }

Query looks pretty much like you might expect:

 private void query() {
 taskRequestFactory.taskRequest().queryTasks().fire(
 new Receiver<List<TaskProxy>>() {
    @Override
    public void onSuccess(List<TaskProxy> taskList) {
       String names = "n";
       for (TaskProxy task : taskList) {
          names += " (" + task.getId() + "): " + task.getName() + "n";
       }
      Window.alert("QUERY SUCCESS: Count[" + taskList.size  + "] Values:" + names);
 }
 });
 

Running it after adding a few more tasks for Larry looks like:

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.

Basic Android Client

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.

The CloudTasksActivity.java class contains the main activity for the application.  In onCreate() we setup the list adapter.


 TaskApplication taskApplication = (TaskApplication) getApplication();
 adapter = taskApplication.getAdapter(this);
 listView.setAdapter(adapter);
 

Then on onStart() we fetch the tasks, passing -1 to indicate that we need to get all the tasks

 

protected void onStart() {
 super.onStart();
 
    // only fetch task on start if the registration has happened.
    SharedPreferences prefs = Util.getSharedPreferences(mContext);
    String deviceRegistrationID = prefs.getString(Util.DEVICE_REGISTRATION_ID, null);
    if (deviceRegistrationID != null) {
    fetchTasks(-1);
 }
 }

Then in CloudTaskActivity.java we  click off an async fetch.

 

public void fetchTasks(long id) {
    progressBar.setVisibility(View.VISIBLE);
    if (task != null) {
      task.cancel(true);
    }
    task = new AsyncFetchTask(this);
    task.execute(id);
 }
 

The AsyncFetchTask fires the RPC to get the task list.

 

protected List<TaskProxy> doInBackground(Long... arguments) {
 final List<TaskProxy> list = new ArrayList<TaskProxy>();
 
 CloudTasksRequestFactory factory = Util.getRequestFactory(activity,
 CloudTasksRequestFactory.class);
 
 factory.taskRequest().queryTasks().fire(new Receiver<List<TaskProxy>>() {
    @Override
    public void onSuccess(List<TaskProxy> arg0) {
     list.addAll(arg0);
    }
 });
  return list;
 }

The AsyncFetchTask fires the RPC to get the task list.

 

protected List<TaskProxy> doInBackground(Long... arguments) {
 final List<TaskProxy> list = new ArrayList<TaskProxy>();
 
 CloudTasksRequestFactory factory = Util.getRequestFactory(activity,
 CloudTasksRequestFactory.class);
 
 factory.taskRequest().queryTasks().fire(new Receiver<List<TaskProxy>>() {
    @Override
     public void onSuccess(List<TaskProxy> arg0) {
     list.addAll(arg0);
 }
 });
 
 return list;
 }
 

The AsyncFetchTask fires the RPC to get the task list.

 

protected List<TaskProxy> doInBackground(Long... arguments) {
 final List<TaskProxy> list = new ArrayList<TaskProxy>();
 
CloudTasksRequestFactory factory = Util.getRequestFactory(activity,
 CloudTasksRequestFactory.class);
 
 factory.taskRequest().queryTasks().fire(new Receiver<List<TaskProxy>>() {
    @Override
    public void onSuccess(List<TaskProxy> arg0) {
      list.addAll(arg0);
    }
 });
 
 return list;
 }
 

And we run it and it looks great!

Nice GWT Client

Wow, that Android client looks great, let’s see what we can do to make the GWT client look good as well.

A few updates to HTML and CSS in the CloudTasks-AppEnginewar folder and some updates to the GWT client code in CloudTasks-AppEnginecom.cloudtasks.client, we get a nice looking web client that can be accessed from anywhere.

One tip for GWT development…  You don’t need to stop and start GWT Development mode.  Simply hit refresh in the browser and see your changes.

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 – 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.

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.

Luckily we have a very convenient place to add this logic on the server.  Let’s look at CloudTasksService.java in the CloudTasks-AppEnginecom.cloudtasks.server directory.

 public static Task updateTask(Task task) {
    task.setEmailAddress(DataStore.getUserEmail());
    task =  db.update(task);
    DataStore.sendC2DMUpdate(TaskChange.UPDATE +
    TaskChange.SEPARATOR + task.getId());
 return task;
 }

First, check out that sendC2DMUpdate() method.  The default project makes it very easy to send a C2DM message.

 public static void sendC2DMUpdate(String message) {
    UserService userService = UserServiceFactory.getUserService();
    User user = userService.getCurrentUser();
    ServletContext context = RequestFactoryServlet.getThreadLocalRequest().getSession().getServletContext();
    SendMessage.sendMessage(context, user.getEmail(), message);
}

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.

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.

To run this, we need to reload the App Engine development time server by clicking the refresh button in the Development Mode tab.

Now, when we run this and add a new task, we get a ping on the Android client.

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.

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.

 public void onMessage(Context context, Intent intent) {
    TaskApplication app = (TaskApplication) getApplication();
    app.notifyListener(intent);
 }

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.

 public void notifyListener(Intent intent) {
    if (listener != null) {
       Bundle extras = intent.getExtras();
       if (extras != null) {
          String message = (String) extras.get("message");
          String[] messages = message.split(Pattern.quote(TaskChange.SEPARATOR));
          listener.onTaskUpdated(messages[0], Long.parseLong(messages[1]));
       }
    }
 }

Finally, we do the actual update:

 public void onTaskUpdated(final String message, final long id) {
    runOnUiThread(new Runnable() {
    public void run() {
       if (TaskChange.UPDATE.equals(message)) {
         fetchTasks(id);
       }
   }
 });

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.

then magically the new task just shows up with the minimum of battery life and network.

And of course, this works two way… when you add a new task from the android phone, the browser app automatically updates without a refersh.

Deployment

The final step here is to deploy your application to the production app engine.  This is very easy to do from eclipse.

First you go to https://appengine.google.com/ and create an App ID.  Go ahead it is free to get started!

Next go to the Android project and find the Setup.java file and update the App name to match the one you just created.

public class Setup {
 
 /**
 * The AppEngine app name, used to construct the production service URL
 * below.
 */
 private static final String APP_NAME = "androidcloudtasks";
 
 
Then you click on the App Engine button and select the App Engine Project to deploy.

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.

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 http://yourappid.appspot.com.

Notice that asks you to log in.   This is for real, unlike the test client.  So you need to give a valid google ID.

Next, App Engine verifies that the user is giving permission for your application to use their email address.

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… but once you do you can access them from any web browser anywhere and a nice rich client on your phone!

Summary

Wow – that was a whole load of stuff.   Just to review:

1. We created a new App Engine connected Android project with built in support for C2DM and RPC.

2. We add a data layer in App Engine for storing tasks

3. Exposed it over RPC

4. Built an Android client for viewing and updating tasks

5. Built a standards based GWT client for viewing and updating tasks

6. plumbed in C2DM for doing push notifications of new tasks

All in less than 45 mins!    Imagine what you can do!

We’d love your feedback on BigDaddy (GPE 2.4)…  Please post the the GWT forums or comment here.

63 thoughts on “Google IO Session Overview: Android + App Engine: A Developer’s Dream Combination

  1. Pingback: Dew Drop – May 11, 2011 | Alvin Ashcraft's Morning Dew

  2. Supreeth

    Awesome session, too bad I couldn’t get tickets this year
    Anyways, I don’t see the video of this session uploaded on youtube. How long should we wait? And also can’t find the android client apk nor the source (the trunk is empty)

    Thanks …

  3. Shaun

    How do I get the run as local app engine android application for an existing android app? Or is their a migration guide? Thanks!

    1. Brad Abrams Post author

      Yes, Yu-Hsuan, that was my fault… I submitted it to the wrong repro… Should be there now… let me know what you think

  4. Supreeth

    Brad,
    I just saw the session on youtube, loved it – you guys were funny too :) … Was waiting for a tutorial like this for some time now. Cause I implemented my own C2DM-rpc a month ago on appengine-android, which is kinda crude.

    Also just wanted to let you know that, there’s only source for the Android project on http://code.google.com/p/cloud-tasks-io/ Its missing the appengine source.

    Thanks a ton !!!

  5. Stephen

    Thanks for the talk guys – It’s inspired me to expand my meddling from Android into App Engine :-)

    As with the above two posters, if we could see the source to the appengine/webui side as well that’d be extremely helpful.

  6. Spotvite

    There are several parts missing, any idea on CloudTasks Java page?

    I keep getting this error message

    The method fire(Receiver) in the type Request is not applicable for the arguments (new Receiver(){})

  7. Pingback: Google IO: A Developer’s Dream Combination | Mapsys.info

  8. Pingback: Cheatsheet: 2011 05.10 ~ 05.16 - gOODiDEA.NET

  9. Patrick

    Anyone else having issues with the sample project?
    It complies and runs on server and android, but when I send message I get an error.

  10. Davy

    What about the security ?

    I read carefully the code generated by the plugin eclipse, and I’m a little concerned about security issues, mostly due to the implementation of the “registrationInfo” service.

    I will try to explain my concerns:
    In order to register the phone, the Android client send his email + device registration id as you can see here -> http://code.google.com/p/cloud-tasks-io/source/browse/trunk/CloudTasks-Android/src/com/cloudtasks/DeviceRegistrar.java#57.
    Both information are useful in order to fully use C2DM (the email is used to identify the owner, and the registration id to identify the phone).
    Now, look at the server side. The server pushes those information in the datastore without checking that the user sending those information is the owner of the email address sent -> http://code.google.com/p/cloud-tasks-io/source/browse/trunk/CloudTasks-AppEngine/src/com/cloudtasks/server/RegistrationInfo.java#100

    So, you can send a register request to the server and using the email address of the user you want. The consequence is simple, your device will be considered as the latest device registered by the user owner of this email address and you will receive all C2DM push of this user.

    More over, AppEngine’s RPC data is plain JSON, and it’s easy to reproduce a request. Maybe I will give it a try in order to confirm what I’m saying…

    Do you think I misunderstand something ? Is there other mechanism under the hood ?

  11. Brad Abrams Post author

    Thanks Davey — I talked it over with the other folks on the team and looks like you have a good point. Glad we shared the source code ;-)

    Look for a fix in the next drop… It is likely a pretty easy fix along the same lines as I showed in validating the email address in the Update() method.

  12. Davy

    I don’t think that we can use the UserService on the AppEngine side to retrieve the e-mail address of the user and check that he is the owner of the e-mail address sent (like in the update method), because the user isn’t connected… I mean, the user with his Android device isn’t “logged in” in the application website (appspot) and so he can’t send his auth cookie with the register request, which means that the UserService is useless…

    I’m not sure that there is an elegant way to solve this issue except opening a browser on the Android device and asking the user to authenticate on the application website (or doing this under the hood, but that mean we need the login + password of the user). But, in both cases the user experience will not be good =0/

    Have you got another mechanism under the hood at Google to solve this tricky thing ?

    I will follow this carefully because your “Big Daddy” give me the opportunity to put my thoughts in a “cloud application” and security is an essential part of my idea.
    By the way, I admit that “Big Daddy” is an awesome idea! Before this plugin mixing all those technologies was frightening for the developer (C2DM, Android, AppEngine). And it’s more true when you are developing on your spare time… I wish you will continue to simplify developer’s life =0)

  13. Franklin

    Well, I have no idea what I’m doing wrong, but … every time I create the Android and AppEngine project and try to register my account on the Android device using the default test app, I get ‘Failed to register/unregister’ in the notification bar. When I look in my logcat, I get ‘W/DeviceRegistrar( 489): Failure, got :Connection to http://127.0.1.1:8888 refused’.

    However, when I try to browse to that url using Chrome, I have no problem at all. Telnetting into that port is no problem either. No matter what I try, ‘failed to register/unregister’ is as far as I can get.

    I reinstalled everything, using the latest version of all SDKs and the new beta of the Google Plugin for Eclipse, in a fresh install of Eclipse Helios. That didn’t make any difference at all. :(

    Looks like I will have to give up on this unless anyone has a suggestion … any suggestion.

  14. Franklin

    I tried changing the url in /assets/debugging_prefs.properties so that it would point to my workstation instead of 127.0.1.1 but every time I launch the project, it gets reset to 127.0.1.1. Should I change that value, and if so … how do I do that in a persistent way?

  15. Franklin

    Ok, I just hardcoded another address in Util.java at line 194 and now it seems to be working. But why should I do that? What’s wrong on my side?

  16. Davy

    @ Franklin

    The AVD create a new virtual ethernet interface. In most of case the AVD IP is 10.0.2.1 and the IP of your computer through the AVD is 10.0.2.2.
    Again, this is an example in my case and can vary, but try to put this in the “debugging_prefs.properties” -> url=http://10.0.2.2:8888
    It works for me !

  17. Franklin

    @Davy: Thanks for your reply. The AVD should create a virtual interface on the host computer, I presume? I can only see the regular ones (eth0, lo and wlan0). Needless to say, none of those have an address in the 10.*.*.* range. ;-)

  18. Jason

    Thanks for putting together the new integration of app engine, c2dm, and Android. It came about the time I was thinking “Wouldn’t it be nice if….”

    I do have one problem though. I created a new project and I can register for C2DM and do the “hello” RPC’s, but when I send a message from the web client it fails and the console shows:

    [WARN] Authentication error: Unable to respond to any of these challenges: {}
    [WARN] Unauthorized – need token

    Any suggestions?

    Thanks

  19. Malte Jäger

    Brad: trying to start Android / AppEngine Project: Everything works while i followed your great tutorial. The problem: i do not get a connection on my local testing. Does the whole always connect to google to proof my c2dm account? From your video a thought everything would also work with test@example.com like i am using it for gwt.

  20. Admin

    I am trying to install the Android client with link to the APK in http://cloudtasksio.appspot.com. But I give this message in my cell phone: “Há um problema com a análise do pacote” (There is a problem analying the package).
    What can I do to install and test your system in my Android cell phone?

  21. Kelly Elton

    I really wish there was a way to run gwt+app engine “apps” on other servers, instead of having to use google

  22. Josh Clemm

    While awesome at first, App Engine’s new pricing model is not a dream at all and will actually kill one of my Android apps. If Google promotes these two technologies because of their synergy, then they need to remember that when raising prices and angering app devs like me.

  23. Roma

    Hi Brad.
    Great demo.
    I tried to run the project on my own machine. After battling with some incompatibilities (the project is a little old), it runs fine but throws an exception on the server as soon as I try to add a task from Android.

    The lowest message on the stack that makes any sense is this:

    11-13 23:13:04.704: E/AndroidRuntime(6190): Caused by: java.lang.RuntimeException: Server Error: The client payload version is out of sync with the server

    Any idea what this means ?

  24. mg

    Nice, but the Google RPC Service wizard supports primitive types only.

    What is about App Engine specific Datastory types like com.google.appengine.api.datastore.Link, com.google.appengine.api.datastore.Text or com.google.appengine.api.users.User?

    The generated shared proxy class cannot resolve non standard java classes.

  25. daniel aranias

    Hi,
    I am trying to implement this concept step by step, but i am still stuck in the first step.

    1. Do I need to create new Gmail account for the “Role mail Address”?
    1.1 Do I need to register in the “C2DM sing up page” with this email?

    2. What should I insert in “Role Password” field the C2DM wizard?

    3. When launching the App. on the emulator, which email address and
    password should I enter?

    Thanks a lot,
    Daniel.

  26. Ruchita Bora

    I am trying to make changes in CloudTasks.css, but I cannot see any changes on GWT client. What should I do in order to reflect my css changes on GWT client?

  27. F. Michael

    Hi !
    I’m stuck at the beginning… When I clic on connect after selecting my gmail account, I have no register via C2DM and eclipse told me : the jar file c2dm.jar has no source attachment, idem for the android.jar and some other in the c2dmbasereceiver.class.
    I spend A week to try to fix it but no way ! I don’t understand what’s wrong.

    1. Guest

      Hi! Did you finally manage to solve it? I’m also stuck with the some problem for over a week, how did you go through it?

    2. Uttamgupta

      Make a copy of folder lib in same -Android/ and rename to libs. It will work. I also spend 1 week to resolve this.

  28. Rekha Rupa

    when i click “say hello” in emulator connected with app engine it is giving error “no one is logged in”.pls tel me wht i did wrong?

  29. Joostwestra

    I am testing your demo on my Android 4 device. Sometimes the communication works. But most of the the Android app crashes when receiving a message. Any tips?

  30. DanPride

    I am starting on my second week just trying to install and get hello world working, Using Indigo eclipse ? Is this a problem? I seem to get varying results each time, frankly beginning to wonder if this thing is going to be an endless nightmare to work with ?????

  31. Dorian Gray

    Only one year and it is deprecated. And there is no documentation about whats going on. Can you at least provide a simple application that works without C2DM. Just authentication, storing and retrieving data.

  32. Ellis Thomas

    Nice overview for android package. Android apps are meant for extreme extent for the job to be done up without any obligations. And more over the integration and synchronization between apps and tools make more sense to get with the things done up easily and appreciatively.

    I too that’s why prefer having tools featuring the approach. And more with the strategy the tool that I have been using for the sort of task management and tracking to get the perfect end result is Replicon’s task management app ( http://www.replicon.com/olp/task-management-software.aspx ) which I have downloaded recently that comes with an open API and which helps manage the things to get the ends up in a perfect manner.