Android and Google App Engine – Build a simple message board app

Right. I have been building apps for sometime now and I realize I haven’t posted anything related in my blog! So this is my first tutorial based on Android and GAE, and really hope to put some more posts on other super cool technologies I have been learning. So this can be part 1 to a series of posts.

Today I’m gonna show how you can build a simple Android app that can connect to the server hosted on Google’s servers through Google App Engine(GAE). I will focus more on Android here and the connectivity will be done via localhost. It’s pretty easy to build sites on app engine and they have exhaustive tutorials for that.

Anyways the application we are going to build today is a Message board, that is anyone with some username can post a message to the public. Imagine that to be a simplified version of the Twitter. I’m not adding any authentication here (Might come up in future posts) and in trying to keep it simple I have not included exception handling and checks, which btw are very very important. Possibly I will update this post with these additions. Plus I deeply appreciate anyone who can suggest on how to improve this tutorial.

What you would be needing today on your machine is Eclipse with Android ADT plugin and Android SDK in the machine, the Google App Engine Launcher and well a text editor to edit the python and other files in the app engine application. So let’s begin!

Step 1 – Build the app engine application:

Today we are going to build a simple REST based application. If you are using Google App Engine Launcher, then you can create a new application from it’s options and automatically builds you the app.yaml . 

Edit the main.py. Create two models – Message and User.

class User(db.Model):
	# username
	username = db.StringProperty(required=True)
	
	def toDict(self):
		user = {}
		user["username"] = self.username
		return user

class Message(db.Model):
	# Message Content
	content = db.TextProperty(required=True)
	
	# Date Created
	created = db.DateTimeProperty(auto_now_add=True)
	
	# Owner
	owner = db.ReferenceProperty(User,collection_name='messages')
	
	def toDict(self):
		message = {}
		message["content"] = self.content
		message["date_created"] = convert_date(self.created)
		message["owner"] = self.owner.username
		return message

Now create REST handlers for these models.

class UserHandler(webapp2.RequestHandler):
	def post(self, id):
		#logging.info(self.request.get('username'))
		data = self.request.get('username')#json.loads(self.request.body)
		user = User.all().filter('username',data).get()
		if user == None:
			user = User(username=data)
			user.put()
		return self.response.out.write(json.dumps(user.toDict()))
		

class MessageHandler(webapp2.RequestHandler):
	def post(self, id):
		try:
			data = json.loads(self.request.body)
		except ValueError:
			data = {}
			request = self.request
			data['username'] = request.get('username')
			data['content'] = request.get('content')
		except:
			return self.error('403')
		user = User.all().filter('username',data['username']).get()
		logging.info(data['username'])
		if user:
			message = Message(content=data['content'],owner=user)
			message.put()
			return self.response.out.write(json.dumps(message.toDict()))
		return self.error('403')
	
	def get(self,id):
		if id != '':
			message = Message.get_by_id(int(id))
			if message:
				return self.response.out.write(json.dumps(message.toDict()))
			return self.error(403)
		try:
			data = json.loads(self.request.body)
			messages = User.all().filter('username',data['username']).get().messages
		except:
			messages = Message.all()
		messages_to_send = []
		for message in messages:
			messages_to_send.append(message.toDict())
		return self.response.out.write(json.dumps(messages_to_send))
	
	def put(self,id):
		if id != '':
			data = json.loads(self.request.body)
			message = Message.get_by_id(int(id))
			if message:
				message.content = data['content']
				message.put()
				return self.response.out.write(json.dumps(message.toDict()))
		return self.error(403)
	
	def delete(self,id):
		if id != '':
			message = Message.get_by_id(int(id))
			message.delete()

What’s left here is the main handler and if you had like, a test handler with a test html that has forms to test the app handlers.

Once done, check the app out using the preview option and see if everything works fine.

We have a working application, now we move on to android.

Step 2 – Build Android app:

We will have an Android app that will have a ListView to display all the messages and a button which will lead the user to create a message.

First the Main Activity will have a ListView that is populated by the messages from the app engine app you have just created. It also has a button that sends an intent to another activity that creates a new message. I called this app Post a Message that you can find on my github.

public class PaM_Main extends ListActivity {
	Handler handler;
	
	
	private OnClickListener postMessageListener = new OnClickListener() {
		
		public void onClick(View v) {
			Intent postMessageIntent = new Intent(PaM_Main.this, PaM_New_Post.class);
			startActivity(postMessageIntent);
		}
	};
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.pam_main);
        
        handler = new Handler();
        Button postButton = (Button) findViewById(R.id.post_button);
        postButton.setOnClickListener(postMessageListener);
    }
    
    @Override
    protected void onResume() {
    	super.onResume();
    	new GetMessages().execute("");
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.pam_main, menu);
        return true;
    }

    class GetMessages extends AsyncTask<String, Void, String> {

		@Override
		protected String doInBackground(String... params) {
			String uri = "http://10.0.2.2:8090/messages";
			HttpClient httpClient = new DefaultHttpClient();
			HttpGet httpGet = new HttpGet(uri);
			//Log.d("loltale:params", Integer.toString(params.length));
			
			try {
				HttpResponse response = httpClient.execute(httpGet);
				HttpEntity entity = response.getEntity();
				
				if(entity != null) {
					return EntityUtils.toString(entity);
				}
			} catch (UnsupportedEncodingException e) {
				e.printStackTrace();
			} catch (ClientProtocolException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return null;
		}
		
		@Override
		protected void onPostExecute(String result) {
			super.onPostExecute(result);
			Log.d("PaM:result:", result);
			try {
				JSONArray messages = new JSONArray(result);
				ArrayList<PaM_Message> list = new ArrayList<PaM_Message>();
				if (messages != null) { 
				   int len = messages.length();
				   for (int i=0;i<len;i++) { 
				    list.add(new PaM_Message(messages.get(i).toString()));
				   } 
				}
				
				final ArrayList<PaM_Message> mList = list;
				handler.post(new Runnable() {
					
					public void run() {
						setListAdapter(new MessagesAdapter(getApplicationContext(), mList));
					}
				});
			} catch (JSONException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
    	
    }
    
    class MessagesAdapter extends ArrayAdapter<PaM_Message> {
    	private List<PaM_Message> messages;
    	
    	public MessagesAdapter(Context context, List<PaM_Message> messages) {
    		super(context, android.R.layout.simple_list_item_2, messages);
    		this.messages = messages;
    	}
    	
    	@Override
    	public View getView(int position, View convertView, ViewGroup parent) {
    		TwoLineListItem view;
    		
    		if(convertView == null) {
    			LayoutInflater inflater = (LayoutInflater)getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = (TwoLineListItem)inflater.inflate(android.R.layout.simple_list_item_2, null);
    		}
    		else {
    			view = (TwoLineListItem)convertView;
    		}
    		PaM_Message data = messages.get(position);
            view.getText1().setText(data.getMessage());
            view.getText2().setText(data.getUser());
    		return view;
    	}
    }
} 

The New Message Activity will have two edit boxes and a button which will create a new message. Also note that I am creating a user of the username first and then post the message.

public class PaM_New_Post extends Activity {
	EditText contentEdit, usernameEdit;
	
	private OnClickListener postMessageListener = new OnClickListener() {
		
		public void onClick(View v) {
			String content = contentEdit.getText().toString();
			String username = usernameEdit.getText().toString();
			Log.d("PaM:content:username:",content + ":" + username);
			if(!content.equals("") && !username.equals("")) {
				String user_result = new PaM_API().postUser(username);
				try {
					JSONObject message_result = new JSONObject( new PaM_API().postMessage(content, username) );
					if ( message_result.getString("content").equals(content) ) {
						Toast.makeText(getApplicationContext(), "Message Successfully posted!", Toast.LENGTH_LONG).show();
						contentEdit.setText("");
						usernameEdit.setText("");
					}
					else {
						Toast.makeText(getApplicationContext(), "Something wrong... 😦 ", Toast.LENGTH_LONG).show();
					}
				} catch (JSONException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
			else {
				Toast.makeText(getApplicationContext(), "Some fields missing", Toast.LENGTH_LONG).show();
			}
		}
	};
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.new_post);
        
        contentEdit = (EditText)findViewById(R.id.messageContentEdit);
        usernameEdit = (EditText)findViewById(R.id.usernameEdit);
        ((Button) findViewById(R.id.postNewMessageButton)).setOnClickListener(postMessageListener);
    }
}

Few things to note, if you are testing on your system, you need to put http://10.0.2.2:/ to the uri the android app will connect to the GAE app. And do remember to change the url when the app is deployed to google app engine.

That’s it! You can run the android app and check it out. Plus if you deploy you GAE app, then anyone can access your app and post on the message board! The code’s on github

Hope this post was helpful. In the next series of posts, I will try to show a little more complex apps plus use some awesome frameworks like Backbone.js, Knockout.js, Node.js and many more to make some really cool apps!

Note: There will be a lot of revisions to this. This is my first attempt in writing a tutorial, so will be glad to know I can make this post better. Suggestions welcome!

Advertisements

Apps that I like to see made…

Using android for more than a year has left me a so called “app-maniac”. I like got around 300 apps in the phone and I check out apps almost daily! Surely android has etched a space in my life and I’m making it count too! (hopefully with me making new apps).

And there are times, when I am trying out apps, that I yearn for apps to made or wish the current apps be better. It certainly is a long list, but in this post I like to point out few which I feel would a make a real impact on the lives of not only android, but all mobile users.

Color app

I used to follow this app when it was released, but the idea of starting another relationship in a new social environment deterred me off. But until recently I stumbled upon this article which talks about integrating this app with Facebook. Then I started dreaming about it!

Ok, basically this app will let any user take a snapshot of wherever they are, like say you are in front of the Eifel tower, and you let friends check it out instantly. It’s as if friends can “visit” your place by seeing the pics you snapped at that moment! How cool is that! I’m totally gonna use this app! (more)

Infinity Blade on Android

Oh, it’s a lovely game. The graphics was awesome, and the game thrilling as ever. When will I ever get to see it running on my Galaxy S. And not only this, why aren’t there many great looking graphics games on android. Sure Angry Birds, Cut the rope and others have been ported to android, but come on games in iOS look far more polished – try Fruit Slice on both and see the difference!

Facebook new app with Timeline

Facebook’s new features are good, if not great. The profile cover feature is really awesome and has set apart from many of the social networking (though I’ve a nagging feeling there is reminiscence of Orkut in it’s UI). Now how would this transcend to the mobile front will be exciting to see.

Google Talk Video

Oh come on, when would it come? I’ve been waiting for this since a year, and now with hangout being a real cool feature of Google+, I just want it on my Galaxy S! Buhahahahaah… Please Sammy and Google, listen to me and will you oh so send that update already to the Indian galaxy S users!?!!?

Drums

I’m a big fan of the Drums app in iOS. It’s so slick and so addictive. Why can’t they port it over to android?? There are many Drums apps in the android market, but none are even close to the trademark Drums app in iOS. I sometimes used to head to the Apple store just to play with this app on iPad!

Similarly there are many instruments that I’d like to see on the android market (which are already there in the iTunes marketplace) (Tabla for example?)

VLC

I just can’t fathom why VLC has not been ported to android. It’s already been released (and rejected, so I’ve heard) in the iOS and android being open source should also get a version of the VLC. Is it the fragmentation that has made VLC shy getting into the android market. Right now it’s available in the pre-alpha stage (which is not official) but hopefully get to see it very soon.

Flourish of iOS on Android

Yeah, this is not an app. But this is something I’ve been a bit disappointed on Google when they announced many a iteration of the Android. iOS is famously known for the way everything carried out with a nice flourish. Yeah, Galaxy S2 might be the answer (faster processor, greater RAM) but the iPhones were never that strong on the hardware front and yet bring that beautiful flourish to everything in iOS. Maybe I’m asking too much but why not!?

 

Ok, that’s all I got to say about it for a while now. I most likely would keep updating this post whenever I get my yearnings for anything in android or mobile space. Until then do enjoy Pixlr-o-matic. A truly beautiful app!

The next leap of technology.

A few days ago, HP announced the tablet version of the WebOS – the TouchPad. WebOS is a great operating system for the mobile. Since the takeover of the Palm company, HP has wasted no time to put the acquired resources to place. Across the Atlantic ocean, Nokia has announced the partnership with Microsoft to ship Windows Phone 7 in the Nokia phones. Though a lot to be done, WP7 is a great OS in the making. Back to North America, Honeycomb was well received for being a great android OS for the tablet version, and many indications point to the fact that these slick features would be made available to the smartphones also. And iOS, as always, is the undisputed king of mobile operating systems around.

Now what’s common among all these operating systems and others I’m yet to mention? The user experience. Every manufacturer, be it the computers, smartphones, tablets etc know that usability has become the primary criteria for their successful business ventures. A good example is the Symbian platform. Even though it is a good OS, symbian failed in the category of user experience. The latest updates have failed to address this matter. As a result, their numbers among the hands of the users are declining drastically, and so is their desperate steps to join hands with Microsoft. RIM realized this fact too well, and has come up with Playbook that has the potential of a great device with a smart OS. Thus, there’s a general shift towards making the products more user-friendly than adding features.

But this trend has a side-effect. There would come a day when all the smartphone or computer operating systems would be equal in terms of user experience. And there is, I believe, a limit to how much more user-friendly a device can be made. Also as is evident in the present competition, the difference in features among the competing devices would be negligible. At that time, it would be a matter if taste of the users. That might lead to even-ing out of the competition, leading to lesser profit generation, finally ending up with lack of willingness among the producers to make these devices.

Or it could be that some new innovation can up the ante for any company. I believe that right now companies should look to look for new ideas, out of the box, that could spice up their devices and thus bring about change in the technological landscape. There are many examples in the past which validates this point. Take for instance the iPhone, which brought in a whole new way of how people see and use the touch phones. Apple also brought in the PC – personal computing revolution, which changed the entire world. Google and facebook has changed the way people use the Internet.

But the current trend is to copy what others started and add on some new features. Android, at it’s infancy, was very similar to iOS. And then it was made possible to make it available to a whole variety of the masses and thus gaining wider acceptance. Sony are using the android platform to push their PlayStation engine into the phones. Microsoft has made a brave effort to provide a different user interface for the smartphones, but still has lots to do to catch up. Nokia-Intel’s Meego project is on very similar lines as that if the android. There are many others to indicate that real innovation is stagnant, and all these companies are trying to do is make their product more attractive.

I guess we should now be looking at various ways technology can leap forward. Maybe there would be a time when people would be groping in air instead of on the touch screens. There maybe a time when the devices can do things just as we think about it by reading our mind. Maybe a combination of the technology used in Kinect, Pranav Mistry’s Sixth sense, and a mind reading technology could the hit the shelves of mobile stores one day. Maybe afterall we would be interacting the way the guys at Microsoft dreamt of, in their video of the world in 2019. Whatever it maybe, the times ahead may or may not be awesome, but I personally would look towards Apple for the next leap of technology. 🙂

Galaxy S update woes

Samsung announced that they had achieved the goal of selling 10 million Galaxy S before the end of 2010. It itself is a great achievement considering it faces stiff competition from iPhone and the myriad android devices around. But Samsung has failed in achieving one other thing – android updates.

With android being upgraded many a time in a year, it is a challenge for Samsung to provide the required update after applying their skin over the vanilla version.  Apple can do this very easily as they have only few types of devices to update, and the software through which they stream the update is great. Samsung, on the other hand, have got many different versions of Galaxy Ss to cater to, let alone the other android devices they sell. And their software is pretty unheard of (kies). Their biggest challenge is to stream the update to many galaxy Ss around the world. Moreover, every time they stream an update, the update would be plagued with many bugs. It gives an impression that they are under-staffed.

But HTC, as is reported, are doing a fine job in update streaming. So why not Samsung? I got the upgrade to froyo a month ago on my galaxy S. And now I regret doing it. It’s buggier than the previous eclair update. I have been experiencing many lags and reboots for the past month. And I’m eagerly waiting for the 2.2.1 froyo update for my phone, which from the things as it seems, will take ages. At this rate I really wonder when the Galaxy Ss around are going to taste gingerbread.

I guess the only way around is for Samsung to start giving vanilla updates to the galaxy s, as it seems integrating samsung’s layer over the android is taking a lot of time. Otherwise there would be 10million frustrated galaxy s users. 🙂