vendredi 8 novembre 2013

WordPress Plugin : Page-In-Page

The Page In Page plugin has a very simple mission: Insert posts and pages within each other
with no stress.

It provides possibilities to use both widgets and shortcodes. If using a widget you are only able to
include pages within pages but if using the shortcode, you are able to able to insert posts/pages
within other posts/pages.

Installation

  1. Download the plugin from http://wordpress.org/plugins/page-in-page/
  2. Extract the zip file. You should find the a folder with name 'page-in-page’.
  3. Upload the 'page-in-page` folder to the `/wpcontent/plugins/` directory
  4. Activate the plugin through the 'Plugins' menu in WordPress Admin
  5. Read the usage instructions below

Usage


Using the widget


The settings in the widget include:

  • Title: Widget Title. This title will be shown as the page's title if 'Show page title' option is not selected.
  • Page: Select the page that will be included when widget is called.
  • Show page title: If checked (selected) then the page title will be shown and the 'Widget Title' ignored.
  • Show title as link: If checked (selected) the title will be displayed as a link to the page.
  • Show page content: If checked (selected) then the page content will be included in the output.
  • Show featured image: If checked (selected) then the featured image will be included in the output.
  • Show featured image as link : If checked (selected) then the featured image will be included and linked to page in the output.
  • Output Template: Insert an HTML template that will be used to display content of the widget. If not provided the default template will be used
    Slugs that can be used in your template are ${page_title}, ${page_content}, ${page_link}, ${page_image} . Each are self explanatory of what they will be replaced with.

  • The default output template is
    <div class="twl-page-in-page">
    <span class="twl-page-in-page-title">${page_title}</span>
    <div class="twl-page-in-page-content">
    <div class="twl-page-in-page-image"><img src="${page_image}" /></div>
    <div class="twl-page-in-page-text">${page_content}</div>
    </div>
    </div>

Using shortcode


With shortcodes, you can insert posts in posts, pages in pages, posts in pages and vice versa.
Settings that can be used in a shortcode are:
  • id : The ID of the page/post you want to insert
  • show_page_title: should the page title be displayed? (Can be 1 for true or 0 for false. Defaults to 1)
  • show_page_content: should the page title be displayed? (Can be 1 for true or 0 for false. Defaults to 1)
  • show_title_as_link: Can be 1 for true or 0 for false. Defaults to 0. If set to 1, the page title will be displayed as a link to the page/post
  • show_featured_image: Can be 1 for true or 0 for false. Defaults to 0. If set to 1, the page's featured image will be included
  • show_featured_image_as_ink: Can be 1 for true or 0 for false. Defaults to 0. If set to 1, the page's featured image will be included as a link

Note that if you are specifying a template in the shortcode, then the above settings will be ignored and the slugs you insert in your template will be replaced with appropriate content. See a template example and allowed slugs above.

To insert a shortcode you can do one of the following:
  • To insert without specifying a template you can simply use
    [twl_page_in id=123] OR [twl_page_in id=123 show_page_title=1].
  • To insert your shortcode specifying a template for page/post's title and content use the following. You can include other supported slugs mentioned above
    [twl_page_in id=123 show_page_title=1]
    <h3 class="my-awesome-title-class">${page_title}</h3>
    <div class="my-awesome-content-class">${page_content}</div>
    [/twl_page_in]

    The template specified in the [twl_page_in] tag will be used to display the page/post with the specified id when inserting it. The template is optional and if not specified then the default template will be used.
    IMPORTANT!!! If you specify a template, you MUST have the slugs you want to be shown else you might get unexpected results
    IMPORTANT!!! This template has to be defined when Editor is in 'Visual' mode and NOT in 'Text' mode (see screen shot). If you do not respect this you might have unexpected results because HTML tags might not be parsed properly. However if you have escaping with magic quotes off on your server then template should be defined when editor is in 'Text' mode.
  • To insert posts from your Facebook page, Go to Admin > Settings > Page In Page Plugin and insert your facebook application credentials. Next edit the page where you want the posts to appear and insert the short code [twl_page_in_fb]
  • To insert tweets from your twitter account, Go to Admin > Settings > Page In Page Plugin and insert your twitter application credentials. Next edit the page where you want the posts to appear and insert the short code [twl_page_in_tw].

lundi 21 octobre 2013

Android: Re-using AsyncTask class across multiple Activities.

First I will like to start by apologizing for not putting this up a long time ago after several email request. I have very little time to put these Tutorials together for public consumption and I prefer responding with short snippets via email. Anyway.. that aside.

This post assumes you have a basic understanding of Android Development precisely about Activities and AsyncTasks. You can visit respective links to learn more on the official android documentation.

I will try to explain how to use a single Async class across Activities that make asynchronous request to a web service.

Suppose you have a REST API that always responds with some JSON output (which we will get as a string) and you need to call this API in multiple (greater than two) Activities. It will be good to have a common AsyncTask class, where you only pass an entry-point URL and a set of parameters and it returns the response. If you however have only a single activity that does some asynchronous task, it will be good design to implement it's AsyncTask class as a private sub class. So, how can we go about implementing a single AsyncTask class to be used in multiple Activities?


  1. We will implement a sub class of the AsyncTask class which will define an interface that MUST be implemented in the calling Activity. This subclass will take as parameters the calling activity (type: Activity), method (POST or GET type: String) and a set of parameters (type:  List<namevaluepair>). Three constructors will be implemented to make the last two parameters optional.
  2. We will show a ProgressDialog while the request is being executed in the background.
  3. We demonstrate the use of this class by defining and example Activity.

A. The subclass: AsyncRequest.java

package com.sewoyebah.examples;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URLEncoder;
import java.util.List;

import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
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.impl.client.DefaultHttpClient;

import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;

public class AsyncRequest extends AsyncTask<String, Integer, String> {

 OnAsyncRequestComplete caller;
 Context context;
 String method = "GET";
 List<NameValuePair> parameters = null;
 ProgressDialog pDialog = null;

 // Three Constructors
 public AsyncRequest(Activity a, String m, List<NameValuePair> p) {
  caller = (OnAsyncRequestComplete) a;
  context = a;
  method = m;
  parameters = p;
 }

 public AsyncRequest(Activity a, String m) {
  caller = (OnAsyncRequestComplete) a;
  context = a;
  method = m;
 }

 public AsyncRequest(Activity a) {
  caller = (OnAsyncRequestComplete) a;
  context = a;
 }

 // Interface to be implemented by calling activity
 public interface OnAsyncRequestComplete {
  public void asyncResponse(String response);
 }

 public String doInBackground(String... urls) {
  // get url pointing to entry point of API
  String address = urls[0].toString();
  if (method == "POST") {
   return post(address);
  }

  if (method == "GET") {
   return get(address);
  }

  return null;
 }

 public void onPreExecute() {
  pDialog = new ProgressDialog(context);
  pDialog.setMessage("Loading data.."); // typically you will define such
            // strings in a remote file.
  pDialog.show();
 }

 public void onProgressUpdate(Integer... progress) {
  // you can implement some progressBar and update it in this record
  // setProgressPercent(progress[0]);
 }

 public void onPostExecute(String response) {
  if (pDialog != null && pDialog.isShowing()) {
   pDialog.dismiss();
  }
  caller.asyncResponse(response);
 }

 protected void onCancelled(String response) {
  if (pDialog != null && pDialog.isShowing()) {
   pDialog.dismiss();
  }
  caller.asyncResponse(response);
 }

 @SuppressWarnings("deprecation")
 private String get(String address) {
  try {

   if (parameters != null) {

    String query = "";
    String EQ = "="; String AMP = "&";
    for (NameValuePair param : parameters) {
     query += param.getName() + EQ + URLEncoder.encode(param.getValue()) + AMP;
    }

    if (query != "") {
     address += "?" + query;
    }
   }

   HttpClient client = new DefaultHttpClient();
   HttpGet get= new HttpGet(address);

   HttpResponse response = client.execute(get);
   return stringifyResponse(response);

  } catch (ClientProtocolException e) {
   // TODO Auto-generated catch block
  } catch (IOException e) {
   // TODO Auto-generated catch block
  }

  return null;
 }

 private String post(String address) {
  try {

   HttpClient client = new DefaultHttpClient();
   HttpPost post = new HttpPost(address);

   if (parameters != null) {
    post.setEntity(new UrlEncodedFormEntity(parameters));
   }

   HttpResponse response = client.execute(post);
   return stringifyResponse(response);

  } catch (ClientProtocolException e) {
   // TODO Auto-generated catch block
  } catch (IOException e) {
   // TODO Auto-generated catch block
  }

  return null;
 }

 private String stringifyResponse(HttpResponse response) {
  BufferedReader in;
  try {
   in = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));

   StringBuffer sb = new StringBuffer("");
   String line = "";
   while ((line = in.readLine()) != null) {
    sb.append(line);
   }
   in.close();

   return sb.toString();
  } catch (IllegalStateException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  } catch (IOException e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }

  return null;
 }
}

First we define the three constructors that our class should support, the first supports three parameters, the second two and the third one. Next we define the interface which the calling
Activity must implement and hence override the asyncResponse() method. Next we implement the required inherited methods. Depending on the method specified, we call the get() or post() private functions
which will return the server response that will be passed to the onPostExecute() method and back to our Activity via the implemented interface.

Please read the official Documentation on AsyncTask to have an understanding of the inherited methods. In summary onPreExecute() is called just before the request is sent, doInBackgroud() is what actually does the job and returns a value which a passed to onPostExecute() called after request is completed. If request was cancelled, onCancelled() is called instead of onPostExecute(). A typical example of a canceled request is when user rotates a device when request is not completed. If you didn't handle the activity life cycle properly then Activity will be redrawn and another request will be made (cancelling the previous).

We also use here a progressDialog to indicate to the user something  is being executed. It is initialized in the onPreExecute() method because we don't want to do this in each constructor of the class and besides we still have hold of the UI thread in the onPreExecute() method.

B. The Example Activity: PostsActivity.java

package com.sewoyebah.examples;

import java.util.ArrayList;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.Bundle;
import android.app.Activity;
import android.widget.TextView;

public class PostsActivity extends Activity implements
  AsyncRequest.OnAsyncRequestComplete {

 TextView titlesView;
 String apiURL = "http://www.example.com/apis/posts";
 ArrayList<NameValuePair> params;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_posts);

  // TODO Auto-generated method stub
  titlesView = (TextView) findViewById(R.id.post_titles);
  params = getParams();
  AsyncRequest getPosts = new AsyncRequest(this, "GET", params);
  getPosts.execute(apiURL);
 }

 // override method from AsyncRequest.OnAsyncRequestComplete interface
 // the response can contain other parameters specifying if the request was
 // successful or not and other things
 // in a real world application various checks will be done on the response
 @Override
 public void asyncResponse(String response) {

  try {
   // create a JSON array from the response string
   JSONArray objects = new JSONArray(response);
   // define a string to hold out titles (in a real word application you will be using a ListView and an Adapter to do such listing)
   String titles = "";
   String NL = "\n";
   String DOT = ". ";
   for (int i = 0; i < objects.length(); i++) {
    JSONObject object = (JSONObject) objects.getJSONObject(i);
    titles += object.getString("id") + DOT + object.getString("title") + NL;
   }
   titlesView.setText(titles);
  } catch (JSONException e) {
   e.printStackTrace();
  }
 }

 // here you specify and return a list of parameter/value pairs supported by
 // the API
 private ArrayList<NameValuePair> getParams() {
  // define and ArrayList whose elements are of type NameValuePair
  ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
  params.add(new BasicNameValuePair("start", "0"));
  params.add(new BasicNameValuePair("limit", "10"));
  params.add(new BasicNameValuePair("fields", "id,title"));
  return params;
 }

}

This is a pretty straight forward Android Activity. In this example we will assume our response is a JSON array. That is, an array of JSON Objects. For example:

 [{"id": 1, "title": "Title of post 1"}, {"id": 2, "title": "Title of post 2"}, {"id": 3, "title": "Title of post 3"}];

Observe that the class implements the AsyncRequest.OnAsyncRequestComplete interface of the AsyncRequest and hence must override the asyncResponse() method of this interface.

To execute the request in the onCreate() method, we define the set of parameters using the getParams() method, create an instance of the AsyncRequest class and call it's execute() method passing to it the entry point (URL) of your API. It is common to use and ArrayList of NameValuePairs as a paramter set.

The response will be received and parsed as a String by our AsyncRequest class and passed to the asyncResponse() interface method as a string.

In the asyncResponse(), we create a JSONArray from this string and read each object and display a list of titles. In a typical real world application, you will implement this using a ListView and an Adapter but this is out of the scope of this tutorial. Here we just concatenate the titles as a String and display in a TextView.


C. Another Example Activity: PostActivity.java

Another example of an activity could be one that gets the details of a post using the post ID. This will typically be launched as an Intent from the Listing Activity. In my next post I will try to explain the same concept using a ListView and an ArrayAdapter to display a list of posts and onClick opens the details of a post in another activity

package com.sewoyebah.examples;

import java.util.ArrayList;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.Bundle;
import android.app.Activity;
import android.widget.TextView;

public class PostActivity extends Activity implements
  AsyncRequest.OnAsyncRequestComplete {

 TextView postView;
 String apiURL = "http://www.example.com/apis/posts";
 ArrayList<NameValuePair> params;
 String postID = "75";

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_post);

  // TODO Auto-generated method stub
  postView = (TextView) findViewById(R.id.post_view);
  params = getParams();
  AsyncRequest getPosts = new AsyncRequest(this, "GET", params);
  getPosts.execute(apiURL);
 }

 // override method from AsyncRequest.OnAsyncRequestComplete interface
 @Override
 public void asyncResponse(String response) {

  try {
   // create a JSON array from the response string
   JSONObject postObject = new JSONObject(response);
   // define a string to hold out titles
   // (in a real word application you will be using a ListView and an
   // Adapter to do such listing)
   String post = "";
   String NL = "\n";
   post += postObject.getString("title") + NL + NL;
   post += postObject.getString("description");
   postView.setText(post);
  } catch (JSONException e) {
   e.printStackTrace();
  }
 }

 // here you specify and return a list of parameter/value pairs supported by
 // the API
 private ArrayList<NameValuePair> getParams() {
  // define and ArrayList whose elements are of type NameValuePair
  ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
  params.add(new BasicNameValuePair("id", postID));
  return params;
 }

}
In case you want to fully test code, bellow are the Layout xml files:

/res/layout/activity_posts.xml
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".PostsActivity" >

    <TextView
        android:id="@+id/post_titles"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>

/res/layout/activity_post.xml
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".PostActivity" >

    <TextView
        android:id="@+id/post_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />

</RelativeLayout>
So in summary after defining the AsyncRequest class this is what you do for each Activity that is to use it:

Class definition
public class MyActivity extends Activity implements AsyncRequest.OnAsyncRequestComplete

Define set of paramters:

ArrayList<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("id", "75"));
params.add(new BasicNameValuePair("attributes", "title,description"));

Start our async task

AsyncRequest request = new AsyncRequest(this, 'GET', params);
request.execute(apiURL);

And implement our asyncResponse() method which will be called after the async request is completed

public void asyncResponse(String response) { ... }

Sending multiple asynchronous requests in same activity

One will now ask: Is it possible to send multiple asynchronous requests from same activity using the AsyncRequest class? The answer is yes but you need to add a bit more to the above solution and keep in mind there is a limit to the number of threads you can run simultaneously based on the API version your app supports. See Android documentation for details.

First you assign a label to each request and pass that label to the AsyncRequest Class and back to the asyncResponse()  method. Your constructor could be like

public AsyncRequest(Activity a, String m, List<NameValuePair> p, String l) {
  caller = (OnAsyncRequestComplete) a;
  context = a;
  method = m;
  parameters = p;
  label = l;
 }

And your interface defined as

public interface OnAsyncRequestComplete {
 public void asyncResponse(String response, String label);
}

and when calling the interface after the request is complete in the postExecute() or isCancelled()  methods you do

caller.asyncResponse(response, label);

and finally back in the Activity you implement your asyncResponse() method as follows

public void asyncResponse(String response, String label) {

 swtich(label) {
  case "get_posts_request"
  // call some method to complete the request
  // you initialized your class with new AsyncRequest(this, "GET", params, "get_posts_request")
  completeGetPostRequest(response);
  break;
  
  case "some_other_label"
  // call some method to complete the request
  // you initialized your class with new AsyncRequest(this, "POST", params, "some_other_label")
  completeSomeOtherRequest(response);
  break;
 }
   
}


Hope this gives some insights..

samedi 5 janvier 2013

Populate an Android Spinner with JSON data from a RESTful web API

In the following tutorial I will explain how to populate and Android Spinner (almost equivalent to a java combo box) using JSON data fetched from a REST API. This tutorial DOES NOT explain how to set up and android app or components of an android app; it only explains how to populate an Android spinner. Hoping we are clear with what this does let's begin.

I will use JSON data from the following RESTful API http://www.cmcredit.com/apps/apis/map/

It is a country/region/city database I put together from various sources and you query by sending some NVP parameters. I will also explain how to do this in our android application. Just as a quick example calling the API with the NVP {call: countrylist} will do the get request: http://www.cmcredit.com/apps/apis/map/?call=countrylist and return a country listing. To get regions in a country you could call the api with the NVPs {call: countryregions, country_id: 42}. This API is used for demo purposes ONLY.

We will use data returned from http://www.cmcredit.com/apps/apis/map/?call=countrylist which is of the following format:
{
 "success":true,
 "message":"",
 "data":
  [
   {"country_id":"42","name":"cameroon","iso2":"CM","currency":"XAF"},
   {"country_id":"43","name":"canada","iso2":"CA","currency":"CAD"},
   {"country_id":"44","name":"cape verde","iso2":"CV","currency":"CVE"},
   {"country_id":"45","name":"cayman islands","iso2":"KY","currency":"KYD"},
   {"country_id":"46","name":"central african republic","iso2":"CF","currency":"XAF"},
   {"country_id":"47","name":"chad","iso2":"TD","currency":"XAF"}
  ]
}


Create the various Layouts
1. Activity layout: one TextView and one Spinner (res/layout/activity_spinnerdemo.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"
    android:paddingTop="30dp" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:paddingLeft="10dp"
        android:text="@string/list_country" >
    </TextView>

    <Spinner
        android:id="@+id/countryField"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:prompt="@string/select_country" >
    </Spinner>

</LinearLayout>


The TextView will simply display the text of the android:text attribute on the screen and the spinner will be populated by our Activity class.

2. The layout of each item in the spinner (res/layout/simple_spinner_item.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal" >

    <TextView
        android:id="@+id/item_value"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" >
    </TextView>

    <TextView
        android:id="@+id/item_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#FFFFFF" >
    </TextView>

</LinearLayout>


Define the Activity class
Secondly we define our activity class that will be launched when you start your application (if you set it as the main activity in the AndroidManifest.xml)

SpinnerDemo.java
package com.sewoyebah.examples;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;

import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.Spinner;
import android.widget.Toast;
import android.annotation.SuppressLint;
import android.app.Activity;

@SuppressLint("DefaultLocale")
public class SpinnerDemo extends Activity {
 // JSON Node names
 private static final String TAG_DATA = "data";
 private static final String TAG_ID_COUNTRY = "country_id";
 private static final String TAG_NAME = "name";
 private static final String TAG_ISO = "iso2";
 private static final String TAG_CURRENCY = "currency";
 private static final String MAP_API_URL = "http://www.cmcredit.com/apps/apis/map";
 private BackGroundTask bgt;

 // Fields
 Spinner countryField;

 ArrayList<Country> countryList = new ArrayList<Country>();

 @Override
 public void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_spinnerdemo);
  buildCountryDropDown();
 }

 public void buildCountryDropDown() {
  // Building post parameters, key and value pair
  List<NameValuePair> apiParams = new ArrayList<NameValuePair>(1);
  apiParams.add(new BasicNameValuePair("call", "countrylist"));

  bgt = new BackGroundTask(MAP_API_URL, "GET", apiParams);

  try {
   JSONObject countryJSON = bgt.execute().get();
   // Getting Array of countries
   JSONArray countries = countryJSON.getJSONArray(TAG_DATA);

   // looping through All countries
   for (int i = 0; i < countries.length(); i++) {

    JSONObject c = countries.getJSONObject(i);

    // Storing each json item in variable
	String id = c.getString(TAG_ID_COUNTRY);
	String name = c.getString(TAG_NAME);
	String iso = c.getString(TAG_ISO);
    String currency = c.getString(TAG_CURRENCY);

    // add Country
    countryList.add(new Country(id, name.toUpperCase(), iso, currency));
   }

   // bind adapter to spinner
   countryField = (Spinner) findViewById(R.id.countryField);
   CountryAdapter cAdapter = new CountryAdapter(this, android.R.layout.simple_spinner_item, countryList);
   countryField.setAdapter(cAdapter);
   
   countryField.setOnItemSelectedListener(new OnItemSelectedListener(){

    @Override
    public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
     Country selectedCountry = countryList.get(position);
     showToast(selectedCountry.getName() + " was selected!");
    }

    @Override
    public void onNothingSelected(AdapterView<?> parent) {}
    
   });

  } catch (JSONException e) {
   e.printStackTrace();
  } catch (InterruptedException e) {
   e.printStackTrace();
  } catch (ExecutionException e) {
   e.printStackTrace();
  }
 }

 public void showToast(String msg) {
  Toast.makeText(this, "Toast: " + msg, Toast.LENGTH_LONG).show();
 }
}



Code Explanation

First we define some strings that represent the keys of our JSON data (TAG_DATA to TAG_CURRENCY), then we define our API end point MAP_API_URL.

In Android development ,it is recommended not to make http requests on the same thread that displays the user interface (i.e requests are best made asynchronous and not as a blocking operation). This is why I defined a background class called BackGroundTask.java (Code is at the end of this article), that handles all such request. Android provides a class called AsyncTask which enables asynchronous requests so my BackgroundTask class will just be extending this class and overriding some core functions. You can read more about this from the Android documentation.

Define the Spinner countryField as in the layout and finally we define the ArrayList that will hold the list of countries returned from the the API. Each entry in the ArrayList is of type Country (the definition of Country.java class is also given at the end of this article)

The onCreate is called when your activity is started and in it we set the content view and call our buildCountryDropdown() method.

What happens in the buildCountryDropDown() method?

1. Set the parameters to be sent to the API by defining a NameValuePair list.

List apiParams = new ArrayList(1); 

apiParams.add(new BasicNameValuePair("call", "countrylist"));


2. Start the background task
bgt = new BackGroundTask(MAP_API_URL, "GET", apiParams);

Initiating our background class, we pass as parameters the API end point, the method to use for the request and the NVP parameters. 3. Get response from the background task

JSONObject countryJSON = bgt.execute().get();

The try..catch block that follows is pretty straight forward. From the JSON object shown above, you will notice that the necessary data itself is in a JSON array, which is why to get the data, we use

JSONArray countries = countryJSON.getJSONArray(TAG_DATA);


Each item in the countries JSONArray is a JSONObject so to get the entries of each item in the countries Array, we use

JSONObject c = countries.getJSONObject(i); 


where i is the current position of the iteration. And finally to get the value of each entry you use the getString() method of the JSONObject class. For example to get the id of a country, you use

String id = c.getString(TAG_ID_COUNTRY);


At the end of the for loop after getting the values of the entries in a country, you add the country to the countryList ArrayList defined in the beginning.


countryList.add(new Country(id, name, iso, currency));

(The code defining the country class is given at the end of this topic.)

The last and final thing that needs to be done to complete our demo is to bind the country list to the spinner. This is done using an ArrayAdapter and because we have a custom type Country we define our own custom adapter called CountryAdapter, that extends the ArrayAdapter class. If the list we wanted to bind to the spinner was a list of Strings, we need not define a custom adapter. we counld directly use the ArrayAdapter.

//get country spinner view from the layout
countryField = (Spinner) findViewById(R.id.countryField);
//define adapter to be used when displaying the country list
CountryAdapter cAdapter = new CountryAdapter(this, android.R.layout.simple_spinner_item, countryList);
//bind the adapter to the spinner
countryField.setAdapter(cAdapter);

  
//set a listener for selected items in the spinner  
countryField.setOnItemSelectedListener(new OnItemSelectedListener(){

 @Override
 public void onItemSelected(AdapterView parent, View view, int position, long id) {

  Country selectedCountry = countryList.get(position);
  showToast(selectedCountry.getName() + " was selected!");
 }
    
});


And that will be it. For detailed explanations on Android Classes used in this tutorial, you can visit the Android Developers site.

Other Classes Necessary for this tutorial:

Country.java

package com.sewoyebah.examples;

public class Country {
	private String id;
	private String name;
	private String iso2;
	private String currency;

	public Country(String i, String n, String iso, String curr) {
		id = i;
		name = n;
		iso2 = iso;
		currency = curr;
	}

	public String getId() {
		return id;
	}

	public String getName() {
		return name;
	}

	public String getISO2() {
		return iso2;
	}

	public String getCurency() {
		return currency;
	}

	public String toString() {
		return name;
	}
}



CountryAdapter.java

package com.sewoyebah.examples;

import java.util.ArrayList;

import android.app.Activity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

public class CountryAdapter extends ArrayAdapter<Country> {
	private Activity context;
	ArrayList<Country> data = null;

	public CountryAdapter(Activity context, int resource,
			ArrayList<Country> data) {
		super(context, resource, data);
		this.context = context;
		this.data = data;
	}

	@Override
	public View getView(int position, View convertView, ViewGroup parent) { 
		return super.getView(position, convertView, parent);
	}

	@Override
	public View getDropDownView(int position, View convertView, ViewGroup parent) { 
		View row = convertView;
		if (row == null) {
			LayoutInflater inflater = context.getLayoutInflater();
			row = inflater.inflate(R.layout.simple_spinner_item, parent, false);
		}

		Country item = data.get(position);

		if (item != null) { // Parse the data from each object and set it.
			TextView CountryId = (TextView) row.findViewById(R.id.item_id);
			TextView CountryName = (TextView) row.findViewById(R.id.item_value);
			if (CountryId != null) {
				CountryId.setText(item.getId());
			}
			if (CountryName != null) {
				CountryName.setText(item.getName());
			}

		}

		return row;
	}
}



BackGroundTask.java
package com.sewoyebah.examples;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
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.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONException;
import org.json.JSONObject;

import android.os.AsyncTask;
import android.util.Log;

public class BackGroundTask extends AsyncTask<String, String, JSONObject> {

	List<NameValuePair> postparams = new ArrayList<NameValuePair>();
	String URL = null;
	String method = null;
	static InputStream is = null;
	static JSONObject jObj = null;
	static String json = "";

	public BackGroundTask(String url, String method, List<NameValuePair> params) {
		this.URL = url;
		this.postparams = params;
		this.method = method;
	}

	@Override
	protected JSONObject doInBackground(String... params) {
		// TODO Auto-generated method stub
		// Making HTTP request
		try {
			// Making HTTP request
			// check for request method

			if (method.equals("POST")) {
				// request method is POST
				DefaultHttpClient httpClient = new DefaultHttpClient();
				HttpPost httpPost = new HttpPost(URL);
				httpPost.setEntity(new UrlEncodedFormEntity(postparams));

				HttpResponse httpResponse = httpClient.execute(httpPost);
				HttpEntity httpEntity = httpResponse.getEntity();
				is = httpEntity.getContent();

			} else if (method == "GET") {
				// request method is GET
				DefaultHttpClient httpClient = new DefaultHttpClient();
				String paramString = URLEncodedUtils
						.format(postparams, "utf-8");
				URL += "?" + paramString;
				HttpGet httpGet = new HttpGet(URL);

				HttpResponse httpResponse = httpClient.execute(httpGet);
				HttpEntity httpEntity = httpResponse.getEntity();
				is = httpEntity.getContent();
			}
			
			// read input stream returned by request into a string using StringBuilder
			BufferedReader reader = new BufferedReader(new InputStreamReader(is, "utf-8"), 8);
			StringBuilder sb = new StringBuilder();
			String line = null;
			while ((line = reader.readLine()) != null) {
				sb.append(line + "\n");
			}
			is.close();
			json = sb.toString();
			
			// create a JSONObject from the json string
			jObj = new JSONObject(json);

		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (JSONException e) {
			Log.e("JSON Parser", "Error parsing data " + e.toString());
		} catch (Exception e) {
			Log.e("Buffer Error", "Error converting result " + e.toString());
		}

		// return JSONObject (this is a class variable and null is returned if something went bad)
		return jObj;

	}
}



Ignore the closing tags at the end of the code snippets, the script formatting the code snippets just messes up.

lundi 5 novembre 2012

The Password Manager - PassMan

This might not be new but anyway, I had a problem and I created this application to solve my problem. I decided to put it up hoping it will help some other people. First and foremost it is free meaning you use at your own cost.

Problem
I have more than 25 accounts over the internet and each has a unique log-in and password. On my PC (mac & co. users already out of the equation :P) all the passwords are saved and I need not remember the user names and passwords. However when not on my pc and need to access a service online, I am required to log-in and most often I forget which log-in goes to which service. This is the problem I faced.

Solution
My solution to this was to have just one log-in detail which gives me access to all other log-in details - and hence PassMan. With PassMan you are able to securely save all your passwords in your mobile and retrieve them at anytime and on the fly. All you need is an internet connection on your mobile and a 'super' user that connects to PassMan.

When PassMan is first installed on your mobile, you are required to first create an account which is unique for each user. Two users can't have same account name and an account can't be duplicated even if you change your mobile phone. In case you loose your mobile phone or change your mobile phone, all you need to do is install PassMan on the new mobile and use same log-in details of the previous install.

This is the first version of this application and thus negative feedback is welcome. The servers responsible for the PassMan web service might be moved when the userbase becomes large. Users will however be informed if there will be any 'temporal no-service'. PassMan is currently avaliable ONLY for android users and versions of other platforms will be released only on demand. You can drop a short message at cyril.tata@hotmail.com.

Below is a simulation to give you an insight on how passman works. Start by clicking on "Create Phone Account". If you like it and you are on the android platform, get in touch for the apk file <cyril.tata@hotmail.com>. Because it is free, I did not put it on the market.

ENJOY!