Twitter | Integrating social connectors within an Android App

The article is part of Android Series that aims to discuss the fundamentals of developing applications on the Android Platform
Integrating social connectors such as Twitter, Facebook, Google+ etc. helps an Android develop personalise the user’s experience. Integrating social connectors also enables the user to recommend the usefulness of your app and in-turn helps promote your application through social advertisement. In this tutorial we build an application that integrates Twitter within your application.

Use case 

An Android application asks a user to authorise its use of the user’s Twitter identity.

Difficulty 

Moderate to Advance 

Pre-requisites 

Android [Moderate]

Tools 

Eclipse with Android Development Toolkit

Following are steps we will undertake to understand and implement the use-case.

  1. Create a simple Android application that asks the user to authorise its use of the users Twitter identity and supported operations.
  2. Create and register a Twitter application on Twitter Developers
  3. Modify the Android application to handle the redirect from Twitter into the application.

Create a simple Android application that asks the user to authorise its use of the user’s Twitter identity and supported operations.

  1. Create an Android project with a simple layout.
  1. Declare in the application manifest following permissions:

    1. The Android Manifest is otherwise very similar to most basic Android applications. Some parts in the following manifest will be explained later on in this tutorial.
<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.gnuc.android.tutorials.ouath.twitter"
    android:versionCode="1"
    android:versionName="1.0"
    android:installLocation="auto">
    <uses-sdk android:minSdkVersion="8" />
    <application
        android:icon="@drawable/icon"
        android:label="@string/app_name">
        <activity
            android:name=".OAuthActivity"
            android:label="@string/app_name"
            android:theme="@android:style/Theme.Light.NoTitleBar"
            android:launchMode="singleInstance">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data
                    android:scheme="gnuc-tutorials-oauth"
                    android:host="twitter" />
            </intent-filter>
        </activity>
    </application>
    <uses-permission android:name="android.permission.INTERNET" />
</manifest></web-app>
  1. Create an activity class ‘OAuthActivity’ where we setup an action to redirect user to Twitter authentication end-point to ask for permission to be granted to access user data. The class OAuthActivity looks like the following. We will enhance the functionality of this class after we have defined the web-service.
package com.gnuc.android.tutorials.ouath.twitter;

import java.io.BufferedInputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;

import oauth.signpost.OAuthProvider;
import oauth.signpost.basic.DefaultOAuthProvider;
import oauth.signpost.commonshttp.CommonsHttpOAuthConsumer;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;

import org.apache.http.HttpResponse;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;

import com.gnuc.android.framework.Logger;
import com.gnuc.android.framework.Tutorial;
import com.gnuc.android.framework.Tutorial.Pref;

public class OAuthActivity extends Activity
{
    private static ProgressDialog    pd            = null;
    //
    String                                id            = null, name = null;
    Bitmap                                picture    = null;
    //
    // Twitter
    private static CommonsHttpOAuthConsumer    twCONSUMER            = null;
    private static OAuthProvider                    twPRODUCER            = null;
    private final static String                    twKEY                    = "XXXXXXXXXXXXXXXXXXXXXX"; // Fill in your Twitter Consumer key
    private final static String                    twSECRET                = " XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX "; // Fill in your Twitter Consumer secret
    private final static String                    twCALLBK                = " gnuc-tutorials-oauth://twitter";

    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        //
        Tutorial.cx = this;
        //
        Button     tw = (ImageButton) findViewById(R.id.twitter);
        tw.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                showProgressDialog("Contacting Twitter ...");
                twCONSUMER = new CommonsHttpOAuthConsumer(twKEY, twSECRET);
                twPRODUCER = new DefaultOAuthProvider("http://twitter.com/oauth/request_token", "http://twitter.com/oauth/access_token", "http://twitter.com/oauth/authorize");
                twPRODUCER.setOAuth10a(true);
                final String authUrl = twPRODUCER.retrieveRequestToken(twCONSUMER, twCALLBK);
                startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));
            }
        });        
        picture = BitmapFactory.decodeResource(Tutorial.cx.getResources(), R.drawable.twitter);
    }
}
  1. The layout for the application is simply a Button, EditText’s and an ImageView. All views are used to display some information extracted using the social web service.

Create and register a Twitter application on Twitter Developers

  1. You will need an API key to access Twitter API. To do that you will first have to create an application and register it with Twitter. It’s simple!
  2. Go to Twitter Developers, log in, and create a new application.
  3. Most of the entries are straightforward. You will only need read-only access for basic operations.
  4. Once you have created your application make note of the ‘Consumer key’ and ‘Consumer secret’. These are required to be updated in the class OAuthActivity.

Modify the Android application to handle the redirect from Twitter into the application.

  1. Once the user has authorised the application, Twitter will redirect the user to the specialised URI we have provided in the variable ‘twCALLBK’. The specialised URI looks like gnuc-tutorials-oauth://twitter and can be of your choice.
  2. The manifest file of your Android project is enhanced to capture URIs with URI scheme : android:scheme=”gnuc-tutorials-oauth and URI host : android:host=”twitter . Also note the new intent-filter added to the manifest for the application to be able to capture the URIs
  3. The class OAuthActivity is enhanced with the following methods to process the redirect from Twitter web-service and subsequently request authorisation against the Twitter end-point and finally request user’s information.
//---------------------------------------------------------------------------------------------------
// OAuthActivity.java
//---------------------------------------------------------------------------------------------------
@Override
protected void onNewIntent(Intent intent)
{
    super.onNewIntent(intent);
    Uri uri = intent.getData();
    if (null != uri)
    {
        Message msg = new Message();
        msg.what = 1;
        msg.obj = uri;
        OAUTH.sendMessage(msg);
    }
}

@Override
public void onResume()
{
    super.onResume();
    try
    {
        if (null != pd &amp;&amp; pd.isShowing())
            pd.hide();
    }
    catch (Exception e)
    {}
}

void twProcess()
{
    Tutorial.background(new Runnable()
    {
        @Override
        public void run()
        {
            try
            {
                //
                final HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
                final BasicHttpParams params = new BasicHttpParams();
                final SchemeRegistry schemeRegistry = new SchemeRegistry();
                schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
                final SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory();
                schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
                final ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
                //
                HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
                DefaultHttpClient CLIENT = new DefaultHttpClient(cm, params);
                //
                HttpGet get = new HttpGet("http://api.twitter.com/1/account/verify_credentials.json");
                get.setParams(params);
                twCONSUMER.sign(get);
                HttpResponse resp = CLIENT.execute(get);
                //
                showProgressDialog("Processing ...");
                //
                String respStr = EntityUtils.toString(resp.getEntity());
                int respCode = resp.getStatusLine().getStatusCode();
                if (respCode == HttpURLConnection.HTTP_OK)
                {
                    JSONObject me = new JSONObject(respStr);
                    id = me.getString("screen_name");
                    name = "@"+me.getString("screen_name");
                    String profile = me.getString("profile_image_url");
                    try
                    {
                        URLConnection cxn = new URL(profile).openConnection();
                        cxn.connect();
                        picture = BitmapFactory.decodeStream(new BufferedInputStream(cxn.getInputStream(), 20));
                    }
                    catch (Exception e)
                    {
                        Logger.e(e);
                    }
                    OAUTH.sendEmptyMessage(3);
                    return;
                }
                else
                    OAUTH.sendEmptyMessage(-1);
            }
            catch (Exception e)
            {
                OAUTH.sendEmptyMessage(-1);
                Logger.e(e);
            }
        }
    });
}

public Handler    OAUTH    = new Handler()
                            {
                                @Override
                                public void handleMessage(Message msg)
                                {
                                    try
                                    {
                                        OAUTH.removeMessages(msg.what);
                                        switch (msg.what)
                                        {
                                            case -1 :
                                            {
                                                if (null != pd)
                                                    pd.cancel();
                                                Toast.makeText(OAuthActivity.this, "Could not authenticate against Twitter. Please try another provider.", Toast.LENGTH_LONG).show();
                                                break;
                                            }
                                            case 1 :
                                            {
                                                Uri uri = (Uri) msg.obj;
                                                if (uri != null &amp;&amp; uri.toString().contains(twCALLBK))
                                                {
                                                    showProgressDialog("Reading response...");
                                                    String verifier = uri.getQueryParameter(oauth.signpost.OAuth.OAUTH_VERIFIER);
                                                    if (null == twCONSUMER || null == twPRODUCER)
                                                    {
                                                        twCONSUMER = new CommonsHttpOAuthConsumer(twKEY, twSECRET);
                                                        twPRODUCER = new DefaultOAuthProvider("http://twitter.com/oauth/request_token", "http://twitter.com/oauth/access_token", "http://twitter.com/oauth/authorize");
                                                        twPRODUCER.setOAuth10a(true);
                                                    }
                                                    try
                                                    {
                                                        twPRODUCER.retrieveAccessToken(twCONSUMER, verifier);
                                                        Pref.OAUTH_TW_TOKEN = twCONSUMER.getToken();
                                                        Pref.OAUTH_TW_TOKEN_SECRET = twCONSUMER.getTokenSecret();
                                                        Pref.write();
                                                        showProgressDialog("Processing response..");
                                                        twProcess();
                                                    }
                                                    catch (Exception e)
                                                    {
                                                        OAUTH.sendEmptyMessage(0);
                                                        Logger.e(e);
                                                    }
                                                }
                                                break;
                                            }
                                            case 2 :
                                            {
                                                showProgressDialog((String) msg.obj);
                                                break;
                                            }
                                            case 3 :
                                            {
                                                runOnUiThread(new Runnable()
                                                {
                                                    @Override
                                                    public void run()
                                                    {
                                                        findViewById(R.id.gplus).setVisibility(View.GONE);
                                                        LinearLayout ll = (LinearLayout) findViewById(R.id.gplus_profile);
                                                        ll.setVisibility(View.VISIBLE);
                                                        ImageView ph = (ImageView) ll.findViewById(R.id.gplus_photo);
                                                        ph.setImageBitmap(picture);
                                                        //
                                                        EditText et = (EditText) findViewById(R.id.gplus_id);
                                                        et.setText(id);
                                                        et.setFocusable(false);
                                                        //
                                                        et = (EditText) findViewById(R.id.gplus_nickname);
                                                        et.setText(name);
                                                        et.setFocusable(false);
                                                        //
                                                        pd.cancel();
                                                    }
                                                });
                                                break;
                                            }
                                        }
                                    }
                                    catch (Exception e)
                                    {}
                                }
                            };

void showProgressDialog(final String msg)
{
    runOnUiThread(new Runnable()
    {
        @Override
        public void run()
        {
            try
            {
                if (null != pd)
                    pd.cancel();
            }
            catch (Exception e)
            {}
            pd = new ProgressDialog(Tutorial.cx);
            pd.setMessage(msg);
            if (!pd.isShowing())
                pd.show();
        }
    });
}

//---------------------------------------------------------------------------------------------------
// Tutorial.java class is a utility class 
//---------------------------------------------------------------------------------------------------
package com.gnuc.android.framework;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;

public class Tutorial
{
    public static final String    TAG    = "GNUC-TUTORIAL";
    public static Context        cx        = null;
    
    //
    public static void background(final Runnable r)
    {
        new Thread()
        {
            @Override
            public void run()
            {
                r.run();
            }
        }.start();
    }
    
    public static class Pref
    {
        public static String        OAUTH_TW_TOKEN                        = "";
        public static String        OAUTH_TW_TOKEN_SECRET            = "";
    
        public static void read()
        {
            SharedPreferences p = cx.getSharedPreferences(TAG, Activity.MODE_PRIVATE);
            OAUTH_TW_TOKEN = p.getString("OAUTH_TW_TOKEN", OAUTH_TW_TOKEN);
            OAUTH_TW_TOKEN_SECRET = p.getString("OAUTH_TW_TOKEN_SECRET", OAUTH_TW_TOKEN_SECRET); 
        }
        
        public static void write()
        {
            SharedPreferences.Editor pe = cx.getSharedPreferences(TAG, Activity.MODE_PRIVATE).edit();
            pe.putString("OAUTH_TW_TOKEN", OAUTH_TW_TOKEN);
            pe.putString("OAUTH_TW_TOKEN_SECRET", OAUTH_TW_TOKEN_SECRET);
            //
            pe.commit();
        }
    }
  1. To understand more about OAuth and the Twitter web-service please read the following resources: https://dev.twitter.com/docs/auth/oauth/faq and https://dev.twitter.com/docs/auth

In this tutorial we learnt how to create an Android application that integrates Twitter within your application.

Posted in Android, Android Series, Web Services | Leave a comment

Google+ | Integrating social connectors within an Android App

The article is part of Android Series that aims to discuss the fundamentals of developing applications on the Android Platform
Integrating social connectors such as Google+, Facebook, Twitter etc. helps an Android developer personalise the user’s experience. Integrating social connectors also enables the user to recommend the usefulness of your app and in-turn helps promote your application through social advertisement. In this tutorial we build an application that integrates the Google Plus social network within your application.

Use case

An Android application asks a user to authorise its use of the users Google Plus identity.

Difficulty

Moderate to Advance

Pre-requisites

Android [Moderate], AppEngine [Basic]

Tools

Eclipse with Android Development Toolkit, Google Plugin for Eclipse with Google Project Hosting and App Engine, Restlet API for AppEngine.

Following are steps we will undertake to understand and implement the use-case.

  1. Create a simple Android application that asks the user to authorise its use of the users Google+ identity and supported operations.
  2. Create a web-service that will redirect to our application handle when called by Google API
  3. Register the web-service with Google APIs
  4. Modify the Android application to handle the redirect from the web-service into the application.

Create a simple Android application that asks the user to authorise its use of the users Google+ identity and supported operations.

  1. Create an Android project with a simple layout.
  1. Declare in the application manifest following permissions:

    1. The Android Manifest is otherwise very similar to most basic Android applications. Some parts in the following manifest will be explained later on in this tutorial.
<?xml version="1.0" encoding="utf-8"?>
<manifest
     xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.gnuc.android.tutorials.ouath.gplus"
     android:versionCode="1"
     android:versionName="1.0"
     android:installLocation="auto">
     <uses-sdk android:minSdkVersion="8" />
     <application
         android:icon="@drawable/icon"
         android:label="@string/app_name">
         <activity
             android:name=".OAuthActivity"
             android:label="@string/app_name"
             android:theme="@android:style/Theme.Light.NoTitleBar"
             android:launchMode="singleInstance">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
             <intent-filter>
                 <action android:name="android.intent.action.VIEW" />
                 <category android:name="android.intent.category.DEFAULT" />
                 <category android:name="android.intent.category.BROWSABLE" />
                 <data
                     android:scheme="gnuc-tutorials-oauth"
                     android:host="gplus" />
             </intent-filter>
         </activity>
     </application>
     <uses-permission android:name="android.permission.INTERNET" />
</manifest></web-app>
  1. Create an activity class ‘OAuthActivity’ where we setup an action to redirect user to Google Plus authentication end-point to ask for permission to be granted to access user data. The class OAuthActivity looks like the following. We will enhance the functionality of this class after we have defined the web-service.
package com.gnuc.android.tutorials.ouath.gplus;
 
import java.io.BufferedInputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
 
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
 
import org.apache.http.HttpResponse;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;
 
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;

import com.gnuc.android.framework.Logger;
import com.gnuc.android.framework.Tutorial;
import com.gnuc.android.framework.Tutorial.Pref;

public class OAuthActivity extends Activity
{
    private static ProgressDialog    pd            = null;
    //
    String                                id            = null, name = null;
    Bitmap                                picture    = null;
    //
    // Google
    private final static String    goID        = "XXXXXXXXXXXX.apps.googleusercontent.com"; // You will provide your Client ID  from the Google APIs Console.
    private final static String    goSECRET    = "XXXXXXXXXXXXXXXXXXXXXXXX"; // You will provide your Client secret from the Google APIs Console.
    private final static String    goRSPURL    = "https://gnuc-tutorials.appspot.com/app/oauth/gplus"; // You will provide the redirect  URI from the Google APIs Console.
    private final static String    goCALLBK    = "gnuc-tutorials-oauth://gplus"; // This is a user-defined url handle which will be called by the web-service. Will invoke the application automatically.
    private final static String    goSCOPE    = "https://www.googleapis.com/auth/plus.me"; // Read about scoping @ https://developers.google.com
    private final static String    goTOKEN    = "https://accounts.google.com/o/oauth2/token"; // Read more @ http://code.google.com/apis/accounts/docs/OAuth2.html
    private final static String    goACCESS    = "https://accounts.google.com/o/oauth2/auth"; // Read more @ http://code.google.com/apis/accounts/docs/OAuth2.html
    private final static String    goPLUS    = "https://www.googleapis.com/plus/v1/people/me";  // Read about end-point @ https://developers.google.com
    
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
        //
        Tutorial.cx = this;
        //
        Button go = (Button) findViewById(R.id.gplus);
        go.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                try
                {
                    showProgressDialog("Contacting Google ...");
                    //
                    final String authUrl = goACCESS + "?client_id=" + goID + "&amp;redirect_uri=" + goRSPURL + "&amp;scope=" + Uri.encode(goSCOPE) + "&amp;response_type=code";
                    startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(authUrl)));
                }
                catch (Exception e)
                {
                    Logger.e(e);
                }
            }
        });
        picture = BitmapFactory.decodeResource(Tutorial.cx.getResources(), R.drawable.google);
    }
}
  1. The layout for the application is simply a Button, EditText’s and an ImageView. All views are used to display some information extracted using the social web service.

Create a web-service that will redirect to our application handle when called by Google API

  1. The web-service we develop here is built on the Google AppEngine platform. The essence of implementation will remain same irrespective of platform or language.
  2. If you do not know how to create a RESTful web-service on AppEngine you should read about it first.
  3. For our use-case we need to define a single endpoint – https://gnuc-tutorials.appspot.com/app/oauth/gplus. This endpoint is configured to receive a GET request and check if the URL contains the parameter – ‘code’. If present will extract the value of the parameter and redirect the browser to a specialised handle which will be caught by the Android application described in the earlier section. The code to define the router for the end-point ‘app/oauth/’ is as follows:
package com.gnuc.appengine.tutorials.app.router;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URLEncoder;
import java.util.Map;

import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;

public class OAuthProvider extends ServerResource
{
    @Get
    public void oauthRedirect()
    {
        try
        {
            String provider = (String) getRequest().getAttributes().get("handler");
            if (provider.equalsIgnoreCase("GPLUS"))
            {
                Map<String, String> params = getQuery().getValuesMap();
                if (null != params &amp;&amp; params.isEmpty())
                    redirectPermanent("gnuc-tutorials-oauth://gplus?fail");
                else
                    redirectPermanent("gnuc-tutorials-oauth://gplus?oauth_code=" + URLEncoder.encode(params.get("code"), "UTF-8"));
            }
        }
        catch (Exception e)
        {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            redirectPermanent("gnuc-tutorials-oauth://social?fail=" + sw.toString());
        }
    }
} 

Register the web-service with Google APIs

  1. Once you have deployed your web-service you will need to authorise the same with Google APIs @ https://code.google.com/apis/console/
  2. Click on Services and set the status of Google+ API to ‘On’.
  3. Click on API Access
    1. Click on ‘Create Client ID’
    2. Application Type : Web application
    3. Click Create client ID.
    4. A new Client ID is created. Click on Edit settings.
    5. Re-edit Authorized Redirect URIs : https://gnuc-tutorials.appspot.com/app/oauth/gplus
    6. Re-edit Authorized JavaScript Origins : https://gnuc-tutorials.appspot.com
    7. Click Update.
  4. Please note that the web-service has an application ID : gnuc-tutorials. This will change for you.
  5. You will need to make note of Client ID and Client secret which need to be updated in the Android class ‘OAuthActivity’

Modify the Android application to handle the redirect from the web-service into the application.

  1. The web-service has been configured to redirect to a specialised URI after extracting the auth code. The specialised URI looks like gnuc-tutorials-oauth://gplus and can be of your choice.
  2. The manifest file of your Android project is enhanced to capture URIs with URI scheme : android:scheme=”gnuc-tutorials-oauth and URI host : android:host=”gplus . Also note the new intent-filter added to the manifest for the application to be able to capture the URIs
  3. The class OAuthActivity is enhanced with the following methods to process the web-service response and subsequently request authorisation against the Google+ end-point and finally request user’s information.
//---------------------------------------------------------------------------------------------------
// OAuthActivity.java
//---------------------------------------------------------------------------------------------------
@Override
protected void onNewIntent(Intent intent)
{
    super.onNewIntent(intent);
    Uri uri = intent.getData();
    if (null != uri)
    {
        Message msg = new Message();
        msg.what = 1;
        msg.obj = uri;
        OAUTH.sendMessage(msg);
    }
}

@Override
public void onResume()
{
    super.onResume();
    try
    {
        if (null != pd &amp;&amp; pd.isShowing())
            pd.hide();
    }
    catch (Exception e)
    {}
}

void goProcess()
{
    Tutorial.background(new Runnable()
    {
        @Override
        public void run()
        {
            try
            {
                //
                final HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
                final BasicHttpParams params = new BasicHttpParams();
                final SchemeRegistry schemeRegistry = new SchemeRegistry();
                schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
                final SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory();
                schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
                final ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
                //
                HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
                DefaultHttpClient CLIENT = new DefaultHttpClient(cm, params);
                //
                HttpPost req = new HttpPost(goTOKEN);
                //
                Pref.read();
                List<BasicNameValuePair> nameValuePairs = new ArrayList<BasicNameValuePair>();
                nameValuePairs.add(new BasicNameValuePair("code", Pref.OAUTH_GO_OAUTH_CODE));
                nameValuePairs.add(new BasicNameValuePair("client_id", goID));
                nameValuePairs.add(new BasicNameValuePair("client_secret", goSECRET));
                nameValuePairs.add(new BasicNameValuePair("redirect_uri", goRSPURL));
                nameValuePairs.add(new BasicNameValuePair("grant_type", "authorization_code"));
                req.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                //
                showProgressDialog("Processing ...");
                HttpResponse resp = CLIENT.execute(req);
                //
                String respStr = EntityUtils.toString(resp.getEntity());
                int respCode = resp.getStatusLine().getStatusCode();
                //
                if (respCode == HttpURLConnection.HTTP_OK)
                {
                    JSONObject auth = new JSONObject(respStr);
                    Pref.OAUTH_GO_TOKEN = auth.getString("access_token");
                    Pref.OAUTH_GO_REFRESH_TOKEN = auth.getString("refresh_token");
                    Pref.write();
                }
                else if (respCode == HttpURLConnection.HTTP_UNAUTHORIZED)
                {
                    req = new HttpPost(goTOKEN);
                    // POST DATA
                    nameValuePairs = new ArrayList<BasicNameValuePair>();
                    nameValuePairs.add(new BasicNameValuePair("client_id", goID));
                    nameValuePairs.add(new BasicNameValuePair("client_secret", goSECRET));
                    nameValuePairs.add(new BasicNameValuePair("refresh_token", Pref.OAUTH_GO_REFRESH_TOKEN));
                    nameValuePairs.add(new BasicNameValuePair("grant_type", "refresh_token"));
                    req.setEntity(new UrlEncodedFormEntity(nameValuePairs));
                    //
                    resp = CLIENT.execute(req);
                    //
                    respStr = EntityUtils.toString(resp.getEntity());
                    respCode = resp.getStatusLine().getStatusCode();
                    if (respCode == HttpURLConnection.HTTP_OK)
                    {
                        JSONObject auth = new JSONObject(respStr);
                        Pref.OAUTH_GO_TOKEN = auth.getString("access_token");
                        Pref.OAUTH_GO_REFRESH_TOKEN = auth.getString("refresh_token");
                        Pref.write();
                    }
                    else
                        throw new Exception("TOKEN RE respCode=" + respCode);
                }
                else
                    throw new Exception("TOKEN respCode=" + respCode);
                //
                HttpGet get = new HttpGet(goPLUS + "?access_token=" + Uri.encode(Pref.OAUTH_GO_TOKEN));
                req.setHeader("Accept", "application/json");
                resp = CLIENT.execute(get);
                //
                respStr = EntityUtils.toString(resp.getEntity());
                respCode = resp.getStatusLine().getStatusCode();
                //
                if (respCode == HttpURLConnection.HTTP_OK)
                {
                    JSONObject me = new JSONObject(respStr);
                    //
                    if (me.has("id"))
                        id = me.getString("id");
                    //
                    if (me.has("displayName"))
                        name = me.getString("displayName");
                    //
                    if (me.has("image"))
                    {
                        String profile = me.getJSONObject("image").getString("url");
                        try
                        {
                            URLConnection cxn = new URL(profile).openConnection();
                            cxn.connect();
                            picture = BitmapFactory.decodeStream(new BufferedInputStream(cxn.getInputStream(), 20));
                        }
                        catch (Exception e)
                        {
                            Logger.e(e);
                        }
                    }
                    OAUTH.sendEmptyMessage(3);
                    return;
                }
                else
                    throw new Exception("goPLUS respCode=" + respCode);
            }
            catch (Exception e)
            {
                OAUTH.sendEmptyMessage(-1);
                Logger.e(e);
            }
        }
    });
}

public Handler    OAUTH    = new Handler()
                            {
                                @Override
                                public void handleMessage(Message msg)
                                {
                                    try
                                    {
                                        OAUTH.removeMessages(msg.what);
                                        switch (msg.what)
                                        {
                                            case -1 :
                                            {
                                                if (null != pd)
                                                    pd.cancel();
                                                Toast.makeText(OAuthActivity.this, "Could not authenticate against Google Plus. Please try another provider.", Toast.LENGTH_LONG).show();
                                                break;
                                            }
                                            case 1 :
                                            {
                                                Uri uri = (Uri) msg.obj;
                                                if (uri != null &amp;&amp; uri.toString().contains(goCALLBK))
                                                {
                                                    showProgressDialog("Reading response...");
                                                    String oauth_code = URLDecoder.decode(uri.getQueryParameter("oauth_code"), "UTF-8");
                                                    Pref.read();
                                                    Pref.OAUTH_GO_OAUTH_CODE = oauth_code;
                                                    Pref.write();
                                                    showProgressDialog("Processing response..");
                                                    goProcess();
                                                }
                                                break;
                                            }
                                            case 2 :
                                            {
                                                showProgressDialog((String) msg.obj);
                                                break;
                                            }
                                            case 3 :
                                            {
                                                runOnUiThread(new Runnable()
                                                {
                                                    @Override
                                                    public void run()
                                                    {
                                                        findViewById(R.id.gplus).setVisibility(View.GONE);
                                                        LinearLayout ll = (LinearLayout) findViewById(R.id.gplus_profile);
                                                        ll.setVisibility(View.VISIBLE);
                                                        ImageView ph = (ImageView) ll.findViewById(R.id.gplus_photo);
                                                        ph.setImageBitmap(picture);
                                                        //
                                                        EditText et = (EditText) findViewById(R.id.gplus_id);
                                                        et.setText(id);
                                                        et.setFocusable(false);
                                                        //
                                                        et = (EditText) findViewById(R.id.gplus_nickname);
                                                        et.setText(name);
                                                        et.setFocusable(false);
                                                        //
                                                        pd.cancel();
                                                    }
                                                });
                                                break;
                                            }
                                        }
                                    }
                                    catch (Exception e)
                                    {}
                                }
                            };

void showProgressDialog(final String msg)
{
    runOnUiThread(new Runnable()
    {
        @Override
        public void run()
        {
            try
            {
                if (null != pd)
                    pd.cancel();
            }
            catch (Exception e)
            {}
            pd = new ProgressDialog(Tutorial.cx);
            pd.setMessage(msg);
            if (!pd.isShowing())
                pd.show();
        }
    });
}


//---------------------------------------------------------------------------------------------------
// Tutorial.java class is a utility class 
//---------------------------------------------------------------------------------------------------
package com.gnuc.android.framework;

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;

public class Tutorial
{
    public static final String    TAG    = "GNUC-TUTORIAL";
    public static Context        cx        = null;
    
    //
    public static void background(final Runnable r)
    {
        new Thread()
        {
            @Override
            public void run()
            {
                r.run();
            }
        }.start();
    }
    
    public static class Pref
    {
        public static String    OAUTH_GO_OAUTH_CODE        = "";
        public static String    OAUTH_GO_TOKEN                = "";
        public static String    OAUTH_GO_REFRESH_TOKEN    = "";
        
        public static void read()
        {
            SharedPreferences p = cx.getSharedPreferences(TAG, Activity.MODE_PRIVATE);
            OAUTH_GO_OAUTH_CODE = p.getString("OAUTH_GO_OAUTH_CODE", OAUTH_GO_OAUTH_CODE);
            OAUTH_GO_TOKEN = p.getString("OAUTH_GO_TOKEN", OAUTH_GO_TOKEN);
            OAUTH_GO_REFRESH_TOKEN = p.getString("OAUTH_GO_REFRESH_TOKEN", OAUTH_GO_REFRESH_TOKEN);
        }
        
        public static void write()
        {
            SharedPreferences.Editor pe = cx.getSharedPreferences(TAG, Activity.MODE_PRIVATE).edit();
            pe.putString("OAUTH_GO_OAUTH_CODE", OAUTH_GO_OAUTH_CODE);
            pe.putString("OAUTH_GO_TOKEN", OAUTH_GO_TOKEN);
            pe.putString("OAUTH_GO_REFRESH_TOKEN", OAUTH_GO_REFRESH_TOKEN);
            //
            pe.commit();
        }
    }
  1. To understand more about OAuth and the Google+ web-service please read the following resources:
    1. Google+ : https://developers.google.com
    2. Google OAuth : http://code.google.com/apis/accounts/docs/OAuth2.html

In this tutorial we learnt how to create an Android application that integrates the Google Plus social network within your application.

Posted in Android, Android Series, iPhone, Web Services, XML | Leave a comment

Creating a RESTful web-service on AppEngine to work with an Android client

The article is part of Android Series that aims to discuss the fundamentals of developing applications on the Android Platform
Building a RESTful web-service is a methodology to structure the server side components with a logical separation of functionality. RESTful web-services are not something entirely new but are just a way to build scalable and well structure server side entities that understand everything as a resource. REStful web-services can be built on many platforms and are not limited to a specific language. In this tutorial we build a simple RESTful web-service deployed onto Google AppEngine using the Restlet framework.

Use case

An AppEngine web-service which is implemented as a RESTful web-service using Restlet framework.

Difficulty

Moderate to Advance

Pre-requisites

Android [Moderate], AppEngine [Basic], Restlet [Basic]

Tools

Eclipse with Android Development Toolkit, Google Plugin for Eclipse with Google Project Hosting and App Engine, Restlet API for AppEngine.

Following are steps we will undertake to understand and implement the web-service.

  1. Define a Restlet application, create a route and describe the web-service with a deployment descriptor.
  2. Create a simple Android application that accesses the web-service.

Defining a Restlet application in the web-service deployment descriptor

  1. The first step is to create a new AppEngine project in Eclipse.
    1. Choose the menu File > New > Web Application Project
      1. Enter project name : HelloWorldWebService
      2. Enter package name : com.gnuc.appengine.tutotials.restful
      3. Check : Use Google AppEngine (at time of writing the version of AppEngine SDK is 1.5.4)
      4. Un-check ‘Generate project sample code’.
      5. Click ‘Finish’
      6. Your package structure in the Package Explorer should look similar to the screen grab to the right.
  2. The next step is to define a route and deploy the web-service to Google AppEngine server.
    1. You will now add the Restlet AppEngine libraries to your project
      1. Right click on the project folder and choose ‘Build Path’ > ‘Add Libraries’ > ‘Select User Libraries’ > Next > ‘User Libraries’ > ‘New’
      2. Enter ‘Restlet GAE’ as the library name and click OK
      3. ‘Restlet GAE’ should be added to the list of user libraries. Select ‘Restlet GAE’ and click ‘Add JARs’.
      4. Traverse to the folder you have placed all the Restlet AppEngine library files (JARs are located in the ‘lib’ folder). Choose the following jars
        1. org.restlet
        2. org.restlet.ext.servlet
      5. Click ‘Open’. The JARs should now be added to ‘Restlet GAE’. Click OK and then Finish.
      6. Restlet is now added to the build path. You will now have to copy all the JARs you selected above and paste them into the project folder > war > WEB-INF > lib folder.
    2. Create the following package structure within com.gnuc.appengine.tutotials.restful
      1. Package : com.gnuc.appengine.tutotials.restful.web
      2. Sub-package : com.gnuc.appengine.tutotials.restful.web.router
      3. Create a new class WebSwitch.java and place within com.gnuc.appengine.tutotials.restful.web
      4. Create a new class HelloWorldRouter.java and place within com.gnuc.appengine.tutotials.restful.web.router
      5. Your package structure in the Package Explorer should look similar to the screen grab to the right.
    3. HelloWorldRouter is a simple router that accepts GET requests and responds with a simple hello message.. The code is as follows
package com.gnuc.appengine.tutotials.restful.web.router;

import java.io.PrintWriter;
import java.io.StringWriter;

import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;

public class HelloWorldRouter extends ServerResource
{
    @Get
    public Representation helloWorld()
    {
        Representation response = null;
        try
        {
            String username = (String) getRequest().getAttributes().get("handle");
            if (null != username)
            {
                setStatus(Status.SUCCESS_OK);
                response = new StringRepresentation("Hi " + username.toLowerCase() + ", hello from the cloud.");
            }
            else
                throw new Exception("handle was null");
        }
        catch (Exception e)
        {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            setStatus(Status.SERVER_ERROR_INTERNAL);
            response = new StringRepresentation("ERROR : " + sw.toString());
        }
        return response;
    }
} 
  1. WebSwitch is the Restlet Application class where we define the different paths for our application. The code is as follows

package com.gnuc.appengine.tutotials.restful.web;
 
import org.restlet.Application;
import org.restlet.Restlet;
import org.restlet.routing.Router;

import com.gnuc.appengine.tutotials.restful.web.router.HelloWorldRouter;

public class WebSwitch extends Application
{
    @Override
    public Restlet createInboundRoot()
    {
        Router router = new Router(getContext());
        router.attach("/web/{handle}", HelloWorldRouter.class);
        return router;
    }
} 

  1. The last thing is to complete the web-service deployment descriptor file where we define the web-service route. The web.xml looks like

<?xml version="1.0" encoding="utf-8"?>
<web-app
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">
    <!-- Restlet Servlets -->
    <servlet>
        <servlet-name>WebSwitch</servlet-name>
        <servlet-class>org.restlet.ext.servlet.ServerServlet</servlet-class>
        <init-param>
            <param-name>org.restlet.application</param-name>
            <param-value>com.gnuc.appengine.tutotials.restful.web.WebSwitch</param-value>
        </init-param>
    </servlet>
    <!-- Restlet Servlet Mappings -->
    <servlet-mapping>
        <servlet-name>WebSwitch</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
    </welcome-file-list>
</web-app>

  1. To deploy the web-service click on the Google Plugin Button on the toolbar and select ‘Deploy to App Engine…’
  2. Click on ‘App Engine project settings’ hyperlink at the bottom of the ‘Deploy Project to Google App Engine’ dialog.
  3. In the new property dialog box that opens fill the following
    1. Application ID: an application ID of your choice.
    2. Version: your choice of version.
  4. Click OK. Click Deploy
  5. Deployment should take a few seconds.
  6. If you now try to access the web-service through your browser at the end-point : https://helloworld.gnuc-tutorials.appspot.com/web/gnuc
  7. The browser will display Hi gnuc, hello from the cloud. Note you will have different name for your application – we have used gnuc-tutorials

Create a simple Android application that accesses the web-service.

  1. Create an Android project with a simple layout.
  2. Create a simple HTTP client that sends a GET request to our new web-service. The code for a sample application is as follows:
package com.gnuc.android.tutorial.first;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;

public class HelloWorld extends Activity
{
    static final String    TAG        = "GNUC-TUTORIAL";
    //
    static final String    SERVER    = "http://helloworld.gnuc-tutorials.appspot.com";
    
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //
        background(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    DefaultHttpClient CLIENT = new DefaultHttpClient();
                    //
                    HttpResponse resp = CLIENT.execute(new HttpGet(SERVER + "/web/gnuc"));
                    final String respStr = EntityUtils.toString(resp.getEntity());
                    if (resp.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
                    {
                        runOnUiThread(new Runnable()
                        {
                            @Override
                            public void run()
                            {
                                Toast.makeText(HelloWorld.this, respStr, Toast.LENGTH_LONG).show();
                            }
                        });
                    }
                    else
                        throw new Exception(respStr);
                }
                catch (Exception e)
                {
                    Log.e(TAG, e.getMessage(), e);
                    runOnUiThread(new Runnable()
                    {
                        @Override
                        public void run()
                        {
                            Toast.makeText(HelloWorld.this, "ERROR", Toast.LENGTH_LONG).show();
                        }
                    });
                }
            }
        });
    }
    
    public static void background(final Runnable r)
    {
        new Thread()
        {
            @Override
            public void run()
            {
                r.run();
            }
        }.start();
    }
}

In this tutorial we learnt how to create a RESTful web-service deployed on Google AppEngine and communicate with it through an Android application.

Posted in Android, Android Series, Database, iPhone, IT Networking, Web Services, XML | 2 Comments

Authenticating against AppEngine using the Android AccountManager

The article is part of Android Series that aims to discuss the fundamentals of developing applications on the Android Platform
Since Android 2.0, a developer can program an application to request a user to authorise the use of a device account to conveniently perform actions on behalf of the user. What this means is, an application does not have to ask the user to enter their login credentials or for that matter create a new account. Applications can use an existing user account to request and use authentication tokens to perform actions. The AccountManager class provides access to the user’s online accounts on the device and provides an authentication token each time an application requests one for a specific service.

Use case

Application uses a user’s Google account to send sample data to an AppEngine web-service which is accessible only through an authenticated request.

Difficulty

Moderate to Advance

Pre-requisites

Android [Moderate], AppEngine [Moderate], Restlet [Basic]

Tools

Eclipse with Android Development Toolkit, Google Plugin for Eclipse with Google Project Hosting and App Engine, Restlet API for AppEngine.

In this tutorial you will be learning how to create an application on Android which is able to implement authentication using the AccountManager class and have it authenticate to use a web-service deployed on Google AppEngine.
Following are steps we will undertake to understand and implement the application.

  1. Create a class which registers and then requests a token from the AccountManager in Android
  2. Create a web-service which validates a request from the Android client.

Building a class that communicates with the AccountManager on Android.

  1. Before you start with the implementation you will need to declare the following permission in your Android manifest

    android.permission.USE_CREDENTIALS

  2. The first step is to request the AccountManager to provide a list of applicable accounts on the device based on a criteria
    1. Get the instance of AccountManager. The method requires the context of your application as an input.
    2. Using the instance retrieve the list of accounts by type/feature. In this example we will only be retrieving all Google accounts of the user.
    3. Populate a ListView with the retrieved accounts. (ListView is defined in the XML layout and not shown here.)
    4. When the user chooses a specific account we will ask the AccountManager to retrieve an auth token for us to use.

final Account[] accounts = AccountManager.get(ctx).getAccountsByType("com.google");// Get an instance and retrieve all google accounts.
final List<String> accountNames = new ArrayList<String>();
for (Account account : accounts)
    accountNames.add(account.name);
ListView accountList = (ListView) findViewById(R.id.st_account_list);// st_account_list is defined in an XML layout
accountList.setAdapter(new ArrayAdapter<String>(ctx, android.R.layout.simple_list_item_1, accountNames));
accountList.setOnItemClickListener(new OnItemClickListener()
{
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int pos, long id)
    {
        checkAccount(accounts[pos]);
    }
}); 

  1. Request the AccountManager to retrieve an auth token for an account.
    1. There are three convenience methods provided by the AccountManager class to retrieve an auth token. Usage of methods is based on application design.
    2. We will use two of the available methods for this use case. Once you are confident about how these methods function you can opt to use one.
    3. First time your application requests the auth token from the AccountManager we will use the following method

      getAuthToken (Account account, String authTokenType, Bundle options, Activity activity, AccountManagerCallback callback, Handler handler)

      1. This method takes a callback as argument among other arguments. The callback method is asynchronous, thus this method should not be initiated off the UI thread.
      2. The callback function receives a future instance that can retrieve the coveted auth token for us.
    4. Once an auth token is retrieved we can proceed with retrieving an auth cookie against our web-service. (It is advisable to refresh the auth token on first retrieval as an expired token could be returned. The method call ‘setAuthToken(account, true);’ with true passed as an argument indicates that the token be renewed before being used by the application).
    5. Following code snippets describes the process of requesting the auth token on a background thread.

//---------------------------------------------------------------------------------------------------
// AndroidClient.java
//---------------------------------------------------------------------------------------------------
/**
     * Method receives an account chosen by user and attempts to retrieve an auth token.
     * 
     * @param account
     *           is the account chosen from account list during setup.
     */
public void checkAccount(final Account account)
{
    Auth.background()
    {
        @Override
        public void run()
        {
            Auth.checkAccount(account, this, new CustomCallback()
            {
                @Override
                public void handle(int resultCode)
                {
                    if(resultCode==1)
                    {
                        // Success
                        // Auth token has been received and in future... calls to the method 
                        // setAuthToken will succeed.
                    }
                    else
                    {
                        // Fail
                        // User did not grant access to the application. Retry later.
                    }
                }
            });
        }
    });
}
//---------------------------------------------------------------------------------------------------
// Auth.java
//---------------------------------------------------------------------------------------------------
private static final String    baseUrl        = "https://thoth-server.appspot.com";
private static final String    loginUrl        = baseUrl + "/_ah/login";
private static final String    checkUrl        = baseUrl + "/app/hello";
private static String            authToken    = null;
private static Cookie            authCookie    = null;
public  static DefaultHttpClient client=null;

 /**
     * Method retrieves an auth token for an account. User is shown a popup to authorise the application.
     * 
     * @param account
     *           account chosen from account list during setup.
     * @param activity
     *             the activity currently active
     * @param checkCallback
     *             a callback implementation
     */
public static void checkAccount(final Account account, final Activity activity, final CustomCallback checkCallback)
{
    AccountManager am = AccountManager.get(ctx);
    AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>()
    {
        @Override
        public void run(AccountManagerFuture<Bundle> future)
        {
            try
            {
                setAuthToken(account, true);
                checkCallback.handle(0);
            }
            catch (Exception e)
            {
                checkCallback.handle(-1);
            }
        }
    };
    am.getAuthToken(account, "ah", null, activity, callback, null);
}
/**
     * Method retrieves an auth token for a previously authorised application.
     * 
     * @param account
     *           account chosen from account list during setup.
     * @param invalidate
     *             flag to indicate if token should be renewed
     */
public static void setAuthToken(Account account, boolean invalidate)
{
    AccountManager am = AccountManager.get(ctx);
    AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>()
    {
        @Override
        public void run(AccountManagerFuture<Bundle> future)
        {
            try
            {
                authToken = future.getResult().getString(AccountManager.KEY_AUTHTOKEN);
            }
            catch (OperationCanceledException e)
            {
                Logger.e(e);
            }
            catch (AuthenticatorException e)
            {
                Logger.e(e);
            }
            catch (IOException e)
            {
                Logger.e(e);
            }
            catch (Exception e)
            {
                Logger.e(e);
            }
        }
    };
    am.getAuthToken(account, "ah", false, callback, null);
    if (invalidate && authToken != null)
    {
        am.invalidateAuthToken(account.type, authToken);
        setAuthToken(account, false);
    }
}
 

  1. With the auth token in hand we can now exchange it against our web-service for an auth cookie. Following steps are performed during this process:
    1. Create a SSL client. (Optional : web-service is configured to only allow SSL)
    2. Send a GET request to login url exposed by the web-service. The GET request requires some information as follows
      1. End-point: Starts like https://thoth-server.appspot.com /_ah/login
      2. Redirect URL: like https://thoth-server.appspot.com /app/hello
      3. Auth Token we retrieved earlier encoded in UTF in the variable“auth”
    3. Our request will either return an HTTP 200 or 302. The response will also have the auth cookie set by the web-service.
    4. The SACSID cookie is set on the HttpClient – Auth.client. Auth.client is the object that will now be used for all communication with the web-service.
    5. The method hello shows how the HttpClient can be used to make subsequent request with the web-service.

//---------------------------------------------------------------------------------------------------
// Auth.java 
//---------------------------------------------------------------------------------------------------

 /**
     * Method retrieves an authenticated SACSID/ACSID cookie for an auth token retrieved earlier.
     */
public static void setAuthCookie()
{
    Auth.background()
    {
        @Override
        public void run()
        {
            try
            {
                // We create an SSL client to speak to our web-service
                // To avoid an SSL cert exceptions, we are creating a generic hostname verifier
                // as we intend to use our own web-service.
                //
                HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
                BasicHttpParams params = new BasicHttpParams();
                SchemeRegistry schemeRegistry = new SchemeRegistry();
                schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
                SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory();
                schemeRegistry.register(new Scheme("https", sslSocketFactory, 443));
                ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
                //
                HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
                DefaultHttpClient client = new DefaultHttpClient(cm, params);
                //
                String cookieUrl = loginUrl + "?continue=" + URLEncoder.encode(checkUrl, "UTF-8") + "&auth=" + URLEncoder.encode(authToken, "UTF-8");
                HttpGet req = new HttpGet(cookieUrl);
                client.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false);
                HttpResponse resp = client.execute(req);
                String respStr = EntityUtils.toString(resp.getEntity());
                int respCode = resp.getStatusLine().getStatusCode();
                if (respCode == HttpURLConnection.HTTP_OK || respCode == HttpURLConnection.HTTP_MOVED_TEMP)
                {
                    for (Cookie cookie : client.getCookieStore().getCookies())
                    {
                        if (cookie.getName().equalsIgnoreCase("SACSID")) // Since we are authentication on SSL we receive SACSID else we will receive ACSID
                        {
                            authCookie = cookie;
                            Auth.client = client;
                            break;
                        }
                    }
                }
                else
                    throw new Exception(respStr);
            }
            catch (Exception e)
            {
                Logger.e(e);
            }
        }
    });
}

 /**
     * Method makes a GET request to web-service with an authenticated client which has an 
     * authenticated SACSID/ACSID cookie set by an earlier auth request.
     */
public static void hello(final RequestCallback reqCallback)
{
    DefaultHttpClient    CLIENT    = Auth.client;
    Auth.background()
    {
        @Override
        public void run()
        {
            try
            {
                HttpResponse resp = CLIENT.execute(new HttpGet(checkUrl));
                String respStr = EntityUtils.toString(resp.getEntity());
                int respCode = resp.getStatusLine().getStatusCode();
                if (respCode == HttpURLConnection.HTTP_OK || respCode == HttpURLConnection.HTTP_MOVED_TEMP)
                {
                    if(null!=respStr && respStr.length()>0)
                        reqCallback.handle(1);
                    else
                        throw new Exception(respStr);
                }
                else
                    throw new Exception(respStr);
            }
            catch (Exception e)
            {
                Logger.e(e);
                reqCallback.handle(-1);
            }
        }
    });
} 

 This is the basic skeleton of using the AccountManager to retrieve an auth cookie in Android. The web-service we used in this step is described in the next section

Building a web-service on AppEngine to communicate with an Android client

  1. The web-service we develop here is built on the Google AppEngine platform. The essence of implementation will remain same irrespective of platform or language.
  2. If you do not know how to create a RESTful web-service on AppEngine you should read about it first.
  3. For our use-case we need to define a single endpoint – https://thoth-server.appspot.com /app/hello. This endpoint is configured to receive a GET request and check if the calling client has been authenticated by Google Account service. Following are steps we need to build the web-service
    1. We create a router to process GET requests.
    2. Extract cookies set on the request and check for existence of SACSID or ACSID cookies.
    3. Return a hash of the cookie value. (Sanity check)

import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;

 public class AppHello extends ServerResource
{
    @Get
    public Representation hello()
    {
        Representation resp = null;
        Request request = getRequest();
        for (Cookie cookie : request.getCookies())
        {
            if (cookie.getName().equalsIgnoreCase("SACSID") && !(cookie.getValue()).isEmpty())
            {
                setStatus(Status.SUCCESS_OK);
                resp = new StringRepresentation(MD5.getMD5HEX(cookie.getValue()));
                break;
            }
        }
        if (null == resp)
        {
            setStatus(Status.SERVER_ERROR_INTERNAL);
            resp = new StringRepresentation("Could not secure.");
        }
        return resp;
    }
}
 

 In this tutorial we learnt how to use the AccountManager class in Android to request for an auth token and retrieve an auth cookie with the same against a Google AppEngine deployed RESTful webservice.

Posted in Android, Android Series, Web Services | Leave a comment

Alphabet5 – Challenge yourself

This week we have released on the Android marketplace, our next Android application which is actually a game!!

‘Alphabet5′ is a multi-player, fast-paced letter finding game for your smart-phone. The game tingles your brain cells and aids in channelling quick response to identify your limits.

The inspiration for the games comes from a psychometric evaluation procedure used to identify how much and how quick you brain can respond to things which you so often take for granted.

The game is released in two flavours. The ‘lite’ version of the game is ad-supported.

Shortly we will be releasing a simpler version of the game for kids.

Support for the game is available through the Alphabet5 web-app @ https://alphabet-five.appspot.com

We look forward to your comments and feedback.

Posted in Android, Web Services | Leave a comment

Promoting your Newsletter

Recently one of our clients approached us with an idea to create a newsletter and a site to show-case financial market updates. The newsletter is such a gullible tool to grab reader attention if it is written well. We had never made something like this before and so really got us excited about the various areas we will need to concentrate on in bringing readership to this site.

Here are some pointers to promoting a successful newsletter

  1. Chalk the name, something that signifies the topic of your newsletter. Decide on how often you would be writing and publishing the newsletter, like daily, weekly, fortnightly or monthly.
  2. Have a format ready of where you will place the heading, the body, any advice or links to sites for more information.
  3. Now start writing your articles, have at least around 10 of them so that you can archive those on the newsletter site to attract your readers.
  4. Your content must have something unique, which keeps you apart from other similar newsletter sites.
  5. Once your site is up and running starts your promotion with your own networks like family, friends, co-workers or acquaintances.
  6. For the larger audience start by doing viral marketing on various forum websites, join similar newsletter sites, or have your link exchanged with them.
  7. There is also a novel way of getting your site to be noticed, create a Facebook page and share it with your followers on twitter. Share with your professional network on LinkedIn.
  8. The number of links coming to your site will make it a popular destination for spam messages too, so keep your site clean from them.
  9. Since you want to appear on Google, Yahoo or Bing searches, have a good content and keywords which users usually type on the search engines. This way you attract more people to your site and your Google page rank would be good.
  10. Your aim for the whole promotion is to attract people who are hungry for such newsletters and could benefit from its content, so keep the newsletter that way all the time. A good written newsletter with good content and quality advice (if any) needs to be maintained at high standards. Your subscribers are paying for the service, so let them realise that your newsletter is worth their time and money.
  11. Have a free version of your newsletter, which includes a summary of the daily or weekly news or information you are displaying. This will not only give your subscribers a gist of the news but also is a good tool to attract new members.

We hope that employing these techniques would help all newsletter aspiring souls to release their own newsletters and are successful with their endeavour.

Posted in Electronic Marketing | Tagged , , , , , , , , , , , , , , , , , , , , , , | Leave a comment

Thoth – Ultimate logging

Thoth is the ultimate logging application to log phone calls, messages and data activity on your handheld device.

Last week we released our first in-house Android application ‘Thoth – Call, SMS, MMS, Data logger’ on the Android marketplace.

The application addresses the need of a mobile user to track all phone activity. The application has multiple uses and a user can choose to use all or some of its features. The application is made available to a large set of Android devices supporting platform version above Android v1.6.

The application also features a full-fledged web-app deployed on App Engine that stores all logs and is only accessible through the users Google account. The web-app also provides various analytics based on logs to the user. Visit the Thoth web-app @ https://thoth-server.appspot.com

The free version of the app released on the market, boasts of some very interesting features

Log Phone Activity

Thoth includes deep integration with telephony API to track all call, messaging and data activity recording

  • contact, time, duration and type for calls.
  • contact, time, message body, type for SMSs and MMSs.
  • application, uploads, downloads for installed apps.
  • Uploads and downloads for available WiFi and Mobile interfaces.

Log Calls

 

Logs all call activity you undertake and store them securely on the Thoth website for analytics.

Log Messages

Logs all your SMS and MMS message activity and stores them securely on the Thoth website.

Log Data Usage

Logs all mobile (3G/EDGE) data activity and provides analytics.

Logs all WiFi data activity and provides analytics.

 

Thoth+ Connect

The free version of the app also includes the Thoth+ pack that includes logging of messages to you Google mail inbox and call activity to Google calendar

Thoth+ | Gmail

SMS and MMS messages seamlessly appear in you Gmail mailbox to backup forever :)

Thoth+ | Google Calendar

Call activity sync to your Google Calendar so that you do not lose that important number.

A paid version of the app with features such as in-call recording, message filtering, data counters and more analytics will soon be released.

Support for the application is available through the Thoth web-app @ https://thoth-server.appspot.com

We look forward to your comments and feedback.

Posted in Android, iPhone | Leave a comment

Graduates – This is real world

As a company we have come across so many graduates in India, fresh out of college looking for jobs, but no clue of what they really want to do. We see so many freshers out of colleges with graduate and post-graduate degrees asking for high pays, with zero experience and zero knowledge about the work to be done. In India it is very common to come across 60% of student population applying for jobs just for fun. Most of them take up a job to show their parents and friends that they have a job , but do not really enjoy working.
Cause:
Parents expect too much from them
Peer and Social pressure
Inquisitiveness to learn something new is nil

The fault lies in the student understanding of what working in a company is. For big companies doing campus recruitment, students are cheaper but their learning curve may not be that great. Whereas, students who join small companies may not get a good salary package but they are sure to learn 80% more in a small company rather than a bigger one.

Advice to freshers: go for a good experience quotient rather than for a salary package, you will be richer in knowledge in the short run, and wealthier in money in the long run. The key is to keep an open mind about various job opportunites. Open to learning new things, like honing communication skills – english written and verbal skills, interpersonal skills etc. Working in a small company gives one the much needed exposure to handle multiple tasks too and gives an added advantage of gaining rich experience.

Seriousness about working in a small company must be inculcated if one is applying for a job there. High salsry expectation being a fresher is too naive. Another company may hire you for a high pay but you will be subject to put in double time and effort than a smaller company. Learn and follow is what one must do to succeed in a small setup. Do not also hesitate to take up work which is out of your specified job profile, who will only learn something new. Take every new task as a challenge and remember that this is your first company and it is giving you an opportunity to work for them over other candidates, so make the most of it.

All the best to all those who are looking for new openings. For openings in our company please email us at jobs@gnuc.in.

Posted in Management | Tagged , , , , | Leave a comment

Protected: Word Tutorial useful for School Work


This post is password protected. To view it please enter your password below:

Posted in COMPUCAMP4U | Enter your password to view comments.

Community Learning : COMPUCAMP4U

Summer Computer Camp[Starts 16/05/2011]

CompuCamp4U-Banner

CompuCamp4U invites kids aged 7 years to 15 years to improve on their computer application skills and apply them to their everyday studies.

At CompuCamp4U, we give hands-on training to participants in various skills, which are useful for them to get ahead of others in their class.

Our training program is fun filled and is spread over 6 days.

Day 1 : Social Networking and Blogging

Day 2 : Furnishing note writing skills useful for School work

Day 3 : Multimedia and Animation

Day 4 : Ethical Hacking

Day 5 & Day 6 : A collective project

To register or inquire please go to the Facebook page HERE

Posted in Uncategorized | Leave a comment