Search This Blog

Tuesday, June 26, 2012

Role of AIDL

In this post I am going to share the use of AIDL ( Android Interface Definition Language) with an example
AIDL can be implemented using parcels and also by normal java interfaces. So the below example will be a combination of both these ways, Please forgive me for my bad English.....
The main need of AIDL is to achieve RPC in android

The basic concept of RPCs in Android

 In Android a Service can export multiple remote interfaces. These remote Interfaces offer functionality which can be used from client.
In order to bind to a remote interface we need to define the following parameters
  • Intent service – this parameter is the intent which will be used to locate the service
  • ServiceConnection conn – the service connection manages the connection to the remote interface. The ServiceConnection class contains callbacks for an established connection and an unexpectedly closed connection:
    • public void onServiceConnected (ComponentName name, IBinder service)
    • public void onServiceDisconnected (ComponentName name)
    It is important to understand that the onServiceDisconnected method will only be called if the connection was closed unexpectedly and not if the connection was closed by the client. So while disconnecting from service it is must to nullify service instance
     
  • int flags – this parameter defines options which will be used during the bind process there are four possible parameters which can be combined (OR):
    • 0 – no options
    • BIND_AUTO_CREATE – this flag will automatically create the service if it is not yet running
    • BIND_DEBUG_UNBIND – this flag will result in additional debug output when errors occur during the unbinding of the service. This flag should only be used during debugging
    • BIND_NOT_FOREGROUND – this flag will limit the service process priority so that the service won’t run at the foreground process priority.

    A call to the bindService method will establish a connection to the service asynchronously and the callback within the ServiceConnection will be called once the remote interface was returned by the Service. This interface provides all methods of the remote service and it can be used by the client like a local object. This allows the client to easily call multiple methods in the service without the need of always rethinking about the fact that it is a remote service.
    The only point where additional attention is required is during the bind procedure because this is done asynchronously by the Android system. So after binding the Service you can’t just directly call remote methods but you have to wait for a callback which notifies your client that the connection was established.

    Fundamentals of Parcels and Parcelables

     In Android, Parcels are used to transmit messages. Unlike to the java serialization, the Parcels are implanted as high-performance containers for the Android inter process communication. By implementing the Parcelable interface you declare that it’s possible to transform (marshall) your class into a Parcel and back (demarshall). Because the Parcels are designed for performance you should always use Parcelables instead of using the java serialization (which would also be possible) when doing IPC in android. Even when you are communicating with Intents you can still use Parcels to pass data within the intent instead of serialized data which is most likely not as efficient as Parcels.

    Create Parcelable Interface

    Let us jump into some bit of code... Create a file named MyParcelableMessage.aidl and do the following code in it..
    /* The package where the aidl file is located */
    package com.test.aidlparcel;

    /* Declare our message as a class which implements the Parcelable interface */
    parcelable MyParcelableMessage;
    After defining .aidl file we define corresponding java class that is need to parceled to activity. So we need to implement our java class using Parcelable Interface, The android.os.Parcelable interface defines two methods which have to be implemented:
    int describeContents()   
    This method can be used to give additional hints on how to process the received parcel. I am not much aware of need of this method So just implementing it as follows
    /**
         * Method which will give additional hints how to process
         * the parcel. For example there could be multiple
         * implementations of an Interface which extends the Parcelable
         * Interface. When such a parcel is received you can use
         * this to determine which object you need to instantiate.
         */
        public int describeContents() {
            return 0;            // nothing special about our content
        }
     void writeToParcel(Parcel dest, int flags)

    This is the core method which is called when this object is to be marshalled to a parcel object. In this method all required data fields should be added to the “dest” Parcel so that it’s possible to restore the state of the object within the receiver during the demarshalling.
    /**
         * Method which will be called when this object should be
         * marshalled to a Parcelable object.
         * Add all required data fields to the parcel in this
         * method.
         */
        public void writeToParcel(Parcel outParcel, int flags) {
            outParcel.writeString(message);
            outParcel.writeInt(textSize);
            outParcel.writeInt(textColor);
            outParcel.writeInt(textTypeface.getStyle());
        }
     
    Furthermore it is necessary to provide a static CREATOR field in any implementation of the Parcelable interface. The type of this CREATOR must be of Parcelable.Creator<T>. This CREATOR will act as a factory to create objects during the demarshalling of the parcel. This interface defines two methods and T specifies object which is need to be parceled.
    /**
         * Factory for creating instances of the Parcelable class.
         */
        public static final Parcelable.Creator<MyParcelableMessage> CREATOR = new Parcelable.Creator<MyParcelableMessage>() {
           
            /**
             * This method will be called to instantiate a MyParcelableMessage
             * when a Parcel is received.
             * All data fields which where written during the writeToParcel
             * method should be read in the correct sequence during this method.
             */
            @Override
            public MyParcelableMessage createFromParcel(Parcel in) {
                String message = in.readString();
                int fontSize = in.readInt();
                int textColor = in.readInt();
                Typeface typeface = Typeface.defaultFromStyle(in.readInt());
                return new MyParcelableMessage(message, fontSize, textColor, typeface);
            }

            /**
             * Creates an array of our Parcelable object.
             */
            @Override
            public MyParcelableMessage[] newArray(int size) {
                return new MyParcelableMessage[size];
            }
        };

    Implementing Remote Interface

    As I mentioned above these example does RPC using Interfacing of Java objects and here I am going to define an another .adil file which transfers Parcelable object through java interface

    /* Import our Parcelable message */
    import com.test.aidlparcel.MyParcelableMessage;

    /* The name of the remote service */
    interface IRemoteParcelableMessageService {

        /* A simple Method which will return a message
         * The message object implements the Parcelable interface
         */
        MyParcelableMessage getMessage();

    }
    After creating this aidl file it will generate a java file in gen directory on your project folder. So we will use of the stub to add details to be parceled to main activity
    Create Java file and do the following
    import android.graphics.Typeface;
    import android.os.RemoteException;

    public class TimeParcelableMessageService extends IRemoteParcelableMessageService.Stub {
        private final static int MAX_FONT_SIZE_INCREASE = 40;
        private final static int MIN_FONT_SIZE = 10;
       
        private final AIDLParcelableMessageService service;

        public TimeParcelableMessageService(AIDLParcelableMessageService service) {
            this.service = service;
        }
       
        @Override
        public MyParcelableMessage getMessage() throws RemoteException {
            String message = service.getStringForRemoteService();
            int fontSize = (int)(Math.random()*MAX_FONT_SIZE_INCREASE) + MIN_FONT_SIZE;
            int textColor = (int)(Math.random()*Integer.MAX_VALUE);
          
            int randomTextStyleSelector = (int)(Math.random()*3);
            int textStyle;
            switch (randomTextStyleSelector) {
            case 0:
                textStyle = Typeface.BOLD;
                break;
            case 1:
                textStyle = Typeface.BOLD_ITALIC;
                break;
            case 2:
                textStyle = Typeface.ITALIC;
                break;
            default:
                textStyle = Typeface.NORMAL;
                break;
            }
          
            return new MyParcelableMessage(message, fontSize, textColor, Typeface.defaultFromStyle(textStyle));
        }

    }
    The above class will provide informations like Text to be displayed with its font size color and text style. In this class we get the message to be provided to parcelable class is obtained from another class that invokes during bind process.

    Implementing the Service

     Create a Java class as shown below
    import java.text.SimpleDateFormat;


    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.util.Log;

    public class AIDLParcelableMessageService extends Service {
        private static final String AIDL_INTENT_ACTION_BIND_MESSAGE_SERVICE = "aidl.intent.action.bindParcelableMessageService";
        private final static String LOG_TAG = AIDLParcelableMessageService.class.getCanonicalName();

        @Override
        public void onCreate() {
            super.onCreate();
            Log.d(LOG_TAG,"The AIDLParcelableMessageService was created.");
        }

        @Override
        public void onDestroy() {
            Log.d(LOG_TAG,"The AIDLParcelableMessageService was destroyed.");
            super.onDestroy();
        }


        @Override
        public IBinder onBind(Intent intent) {
            if(AIDL_INTENT_ACTION_BIND_MESSAGE_SERVICE.equals(intent.getAction())) {
                Log.d(LOG_TAG,"The AIDLParcelableMessageService was binded.");
                return new TimeParcelableMessageService(this);
            }
            return null;
        }

        String getStringForRemoteService() {
            return getString(R.string.time_message) + (new SimpleDateFormat(" hh:mm:ss").format(System.currentTimeMillis()));
        }

    }
    The above class handles service binding operation from remote client and provides the current system time to the parcleable interface.

    Implementing the Client

     Before Implementing client we define a remote class that implements ServiceConnection. The main objective of this class is that you won’t have to publish any code if third-party applications want to extend your own app.
    The following are the core methods of ServiceConnection Class

     The onServiceConnected Method

     The first is the onServiceConnected method. Retrieval of the remote interface is done by the .Stub.asInterface method which will cast the IBinder object to the remote interface.
    /* Called when a connection to the Service has been established,
         * with the IBinder of the communication channel to the Service. */
       
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            Log.d(LOG_TAG, "The service is now connected!");
            // Retrive Remote Interface
            this.service = IRemoteParcelableMessageService.Stub.asInterface(service);
            Log.d(LOG_TAG, "Querying the message...");
            try {
                /*
                 * This call is required because the connect is an asynchronous call
                 * so the activity has to be notified that the connection is now
                 * established and that the message was queried.
                 */
                parent.theMessageWasReceivedAsynchronously(this.service.getMessage());
            } catch (RemoteException e) {
                Log.e(LOG_TAG, "An error occured during the call.");
            }
        }

    The onServiceDisconnected Method

     The second core method is the onServiceDisconnected. When this callback is called something went wrong with the connection so we need to remove the remote interface from the field variable.
    //Called when a connection to the Service has been lost.

        @Override
        public void onServiceDisconnected(ComponentName name) {
            Log.d(LOG_TAG, "The connection to the service got disconnected unexpectedly!");
            service = null;
        }
    Now to connect and disconnect from the service we are not directly accessing the above defined methods and defining that with the following methods

    safelyConnectTheService Method

    This method encapsulates the bindService process for the Activity. It will avoid multiple bindService calls by checking if the connection is currently established. After that an Intent is generated with the appropriate action for the IRemoteMessageService remote interface. Furthermore the package and class name for the receiving service are set to our Service. This intent will be used in the bindService call which is executed on the Activity. The ServiceConnection parameter of this call is our own ServiceConnection – this. And because we want the Service to be created if it is currently not running we set the flag to Context.BIND_AUTO_CREATE.
    /**
         * Method to connect the Service.
         */
        public void safelyConnectTheService() {
            if(service == null) {
                Intent bindIntent = new Intent(AIDL_INTENT_ACTION_BIND_MESSAGE_SERVICE);
                bindIntent.setClassName(AIDL_MESSAGE_SERVICE_PACKAGE, AIDL_MESSAGE_SERVICE_PACKAGE + AIDL_MESSAGE_SERVICE_CLASS);
                parent.bindService(bindIntent, this, Context.BIND_AUTO_CREATE);
                Log.d(LOG_TAG, "The Service will be connected soon (asynchronus call)!");
            }
        }
    /**
         * Method to safely query the message from the remote service
         */
        public void safelyQueryMessage() {
            Log.d(LOG_TAG, "Trying to query the message from the Service.");
            if(service == null) {    // if the service is null the connection is not established.
                Log.d(LOG_TAG, "The service was not connected -> connecting.");
                safelyConnectTheService();
            } else {
                Log.d(LOG_TAG, "The Service is already connected -> querying the message.");
                try {
                    parent.theMessageWasReceivedAsynchronously(service.getMessage());
                } catch (RemoteException e) {
                    Log.e(LOG_TAG, "An error occured during the call.");
                }
            }

    safelyDisconnectTheService Method

     Because the onServiceDisconnected will only be called when something unexpected closed the connection I’ve added this method to the ServiceConnection. This method handles the unbinding for the Activity. First it checks whether a connection is currently established by checking if the remote interface is not null. Then it will remove the reference for the remote interface which will indicate that the connection is closed. Finally the unbindService method in the Activity can be called which will disconnect the Activity from the remote service.
    /**
         * Method to disconnect the Service.
         * This method is required because the onServiceDisconnected
         * is only called when the connection got closed unexpectedly
         * and not if the user requests to disconnect the service.
         */
        public void safelyDisconnectTheService() {
            if(service != null) {
                service = null;
                parent.unbindService(this);
                Log.d(LOG_TAG, "The connection to the service was closed.!");
            }
        }

    Implementing Client

     Because our RemoteMessageServiceServiceConnection class handles all aspects of the connection the activity is reduced to bare GUI code. Our GUI contains two buttons: one to update the message and another one to disconnect the remote service. The disconnect button is used to demonstrate that our ServiceConnection handles everything for us.
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.TextView;

    public class DisplayRemoteParcelableMessage extends Activity {
        private Button disconnectButton;
        private Button queryButton;
        private TextView messageTextView;
        private RemoteParcelableMessageServiceServiceConnection remoteServiceConnection;
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            remoteServiceConnection = new RemoteParcelableMessageServiceServiceConnection(this);
            disconnectButton = (Button)findViewById(R.id.disconnectButton);
            queryButton = (Button)findViewById(R.id.queryButton);
            messageTextView = (TextView)findViewById(R.id.parcelableMessageTextView);
          
            disconnectButton.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    remoteServiceConnection.safelyDisconnectTheService();
                }
            });
           
            queryButton.setOnClickListener(new OnClickListener() {
               
                @Override
                public void onClick(View v) {
                    remoteServiceConnection.safelyQueryMessage();
                }
            });
        }
       
        void theMessageWasReceivedAsynchronously(MyParcelableMessage message) {
            message.applyMessageToTextView(messageTextView);
        }
    }

    Summary

    The Android RPC mechanism is a powerful tool which can be used to realize inter process communication (IPC) in Android. In larger Apps the overhead which is required to define the remote interface and the service connection on the client-side will be much smaller than a permanent communication with intents and the code will be less error-prone.

     

Tuesday, November 1, 2011

SAX Parsing

SAX (Simple API for XML) is an event based sequential access parser API which provides mechanism for reading data from an XML document. This parser is used as alternative for DOM (Document Object Model) which operates on the document as a whole, where as SAX parsers operate on each piece of the XML document sequentially.

Here I am going to use this SAX Parser API to get some information from the server using Wi-fi Connectivity and displaying the value on Tablet/Phone powered by Android 2.x.

Design of Application

In this Application there is no much needed any sorts of decorations and here we use just a label to display the parsed value
 
  <?xml version="1.0" encoding="utf-8" ?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
  <TextView android:id="@+id/DisplayValue" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="" />
  </LinearLayout>
 
Main Activity
 
This class displays parsed value retrieved from URL and this class will throw exception if there is no net connectivity So add this module in this activity to check for internet connectivity
public boolean hasInternet(Context con) {
            NetworkInfo info = (NetworkInfo) ((ConnectivityManager) con
                    .getSystemService(CONNECTIVITY_SERVICE)).getActiveNetworkInfo();
            if (info == null || !info.isConnected())
                return false;
            return true;
        }


package com.parsesample.parser;

import java.net.URL;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.XMLReader;

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

public class ParsingXML extends Activity {
    /** Called when the activity is first created. */
    TextView parseValue;
   
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
               
        parseValue=new TextView(this);
        try {
           URL url = new URL("http://xxx.yyy.zzz.abc:qwe/yyy.xml");
            SAXParserFactory saxFactory=SAXParserFactory.newInstance();
            SAXParser parser=saxFactory.newSAXParser();
            XMLReader reader=parser.getXMLReader();
            XMLHandler handler=new XMLHandler();
            reader.setContentHandler(handler);
            reader.parse(new InputSource(url.openStream()));
            ParseDataSet dataSet=handler.getParsedData();
            parseValue.setText(dataSet.toString());
        } catch (Exception e) {
            //parseValue.setText("Error:  "+e.getMessage());
            Log.e("Exception Caught", e.getMessage());
        }
        setContentView(parseValue);
    }
}
 
Parser Class
 
This class handles parsing functionality of data from XML
 
/**
 *
 */
package com.parsesample.parser;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * @author venkat
 *
 */
public class XMLHandler extends DefaultHandler {

    protected boolean in_outertag = false;
    protected boolean in_innertag = false;
    protected boolean in_mytag = false;
    protected boolean version = false;

    private ParseDataSet dataSet = new ParseDataSet();

    public ParseDataSet getParsedData() {
        return this.dataSet;
    }

    @Override
    public void startDocument() throws SAXException {
        // TODO Auto-generated method stub
        this.dataSet = new ParseDataSet();
    }

    @Override
    public void endDocument() throws SAXException {
        // TODO Auto-generated method stub
        super.endDocument();
    }

    @Override
    public void startElement(String uri, String localName, String qName,
            Attributes attributes) throws SAXException {
        // TODO Auto-generated method stub
        if (localName.equals("outertag")) {
            this.in_outertag = true;
        } else if (localName.equals("innertag")) {
            this.in_innertag = true;
        } else if (localName.equals("mytag")) {
            this.in_mytag = true;
        } else if (localName.equals("currentversion")) {
            this.version=true;
        } else if (localName.equals("tagwithnumber")) {
            String atrValue = attributes.getValue("thenumber");
            Integer i = Integer.parseInt(atrValue);
            dataSet.setExtractedInt(i);
        }
        super.startElement(uri, localName, qName, attributes);
    }

    @Override
    public void endElement(String uri, String localName, String qName)
            throws SAXException {
        // TODO Auto-generated method stub
        if (localName.equals("outertag")) {
            this.in_outertag = false;
        } else if (localName.equals("innertag")) {
            this.in_innertag = false;
        } else if (localName.equals("mytag")) {
            this.in_mytag = false;
        } else if (localName.equals("currentversion")) {
            this.version=false;
        }
        super.endElement(uri, localName, qName);
    }

    @Override
    public void characters(char[] ch, int start, int length)
            throws SAXException {
        // TODO Auto-generated method stub
        if (this.in_mytag) {
            // dataSet.setExtractedString(new String(ch,start,length));
            dataSet.setExtractedString(new String(ch));
        } else if (this.version) {
            dataSet.setExtractedString(new String(ch));
        }
        super.characters(ch, start, length);
    }
}
 
Parser Data Set
 
This POJO handles parser value and returns to Handler class
 
package com.parsesample.parser;

import android.util.Log;

public class ParseDataSet {
   
    private String extractedString = null;
    private int extractedInt = 0;

    public String getExtractedString() {
            return extractedString;
    }
    public void setExtractedString(String extractedString) {
            this.extractedString = extractedString;
    }

    public int getExtractedInt() {
            return extractedInt;
    }
    public void setExtractedInt(int extractedInt) {
            this.extractedInt = extractedInt;
    }
  
    public String toString(){
            Log.d("Extracted String   ->>>>", this.extractedString);
           /* return "ExtractedString = " + this.extractedString
                            + "nExtractedInt = " + this.extractedInt;*/
            return this.extractedString;
    }

}










Wednesday, March 16, 2011

Database Demo

Here I am sharing code for using Database (SQLite) in android and I hope this post will be useful for newbees to learn android widgets.


Here I am going to use Expandable List view to populate Table Values to Activity.

This Sample is Developed in Android 2.3.3 SDK.


main.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >

<TextView android:layout_height="wrap_content"
android:id="@+id/Name"
android:layout_width="fill_parent"
android:text="Name">
</TextView>

<EditText android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:id="@+id/EmpName"
android:inputType="text|textCapCharacters|textCapWords|textCapSentences|textAutoCorrect|textAutoComplete">
</EditText>

<TextView android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:id="@+id/Age"
android:text="Age">
</TextView>

<EditText android:layout_height="wrap_content"
android:id="@+id/EmpAge"
android:inputType="number|numberSigned|numberDecimal"
android:layout_width="fill_parent">
</EditText>

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

<Button android:text="InsertValues"
android:id="@+id/AddDet"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10px">
</Button>

<Button android:layout_height="wrap_content"
android:layout_width="wrap_content"
android:layout_toRightOf="@+id/AddDet"
android:text="ViewDetails"
android:id="@+id/ViewDet">
</Button>

</RelativeLayout>


</LinearLayout>




Main Activity (SQLiteTest.java)

This activity gets details from user and popups an alert dialog for successfull/failure in DB insertion and toast for the value inserted in DB. When user taps view details button displays Expandable list view activity.


import android.app.Activity;
import android.app.AlertDialog;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

public class SQLiteTest extends Activity {
    /** Called when the activity is first created. */

    protected Button insertButton, viewButton;
    protected EditText nameText, ageText;
    DBHelper helper;
    Context mContext = this;
    String dispData;

   
    protected OnClickListener onClickListener = new OnClickListener() {

        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
            if (v.getId() == R.id.AddDet) {
                Toast.makeText(
                        getApplicationContext(),
                        "Name  " + nameText.getText().toString() + "Age "
                                + ageText.getText().toString(),
                        Toast.LENGTH_LONG).show();
                Employee emp=new Employee(nameText.getText().toString(), Integer.parseInt(ageText.getText().toString()));
                int status =helper.insertTable(emp);
                if (status != -1) {
                    AlertDialog.Builder alert = new AlertDialog.Builder(
                            mContext);
                    alert.setMessage("Table Values Inserted");
                    alert.setNeutralButton("OK",
                            new DialogInterface.OnClickListener() {

                       
                       
                                @Override
                                public void onClick(DialogInterface dialog,
                                        int which) {
                                    // TODO Auto-generated method stub
                                    dialog.cancel();
                                }
                            });
                    AlertDialog al = alert.create();
                    al.show();
                } else {
                    AlertDialog.Builder alert = new AlertDialog.Builder(
                            mContext);
                    alert.setMessage("Table Values not Inserted");
                    alert.setNeutralButton("OK",
                            new DialogInterface.OnClickListener() {

                                @Override
                                public void onClick(DialogInterface dialog,
                                        int which) {
                                    // TODO Auto-generated method stub
                                    dialog.cancel();
                                }
                            });
                    AlertDialog ad = alert.create();
                    ad.show();
                }   
            } else if (v.getId() == R.id.ViewDet) {
                Intent intent=new Intent(SQLiteTest.this,sample.class);
                startActivity(intent);
            }

        }
    };

    protected void notifyTrigger(CharSequence Title, CharSequence msg) {
        CharSequence sequence = Title;
        CharSequence message = msg;
        NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        Notification notification = new Notification(R.drawable.icon,
                "This is to Notify You", System.currentTimeMillis()) {
        };
        Intent notificationIntent = new Intent(this, SQLiteTest.class);
        PendingIntent pIntent = PendingIntent.getActivity(this, 0,
                notificationIntent, 0);
        notification.setLatestEventInfo(getApplicationContext(), sequence,
                message, pIntent);
        nm.notify(1, notification);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        helper = new DBHelper(getApplicationContext());
        // helper.createTable();
        insertButton = (Button) findViewById(R.id.AddDet);
        viewButton = (Button) findViewById(R.id.ViewDet);
        nameText = (EditText) findViewById(R.id.EmpName);
        ageText = (EditText) findViewById(R.id.EmpAge);
        insertButton.setOnClickListener(onClickListener);
        viewButton.setOnClickListener(onClickListener);

              
    }
}


DBConnection Class (DBHelper.java)

This class creates Database and tables and inserts the value from the user input taken from POJO


import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteFullException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class DBHelper extends SQLiteOpenHelper {

    private static final String dbName = "SampleDB";
    public final String tableName="TestTable";
    public final String attribValue1="Name";
    public final String attribValue2="age";
    SQLiteTest sqltest;
    String[] nameVal;
    int[] ageVal;
    int size;
    int i=0;
   
    public DBHelper(Context context) {
        super(context, dbName, null, 33);
        sqltest = new SQLiteTest();
        // TODO Auto-generated constructor stub
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // TODO Auto-generated method stub
        String sql="";
        try {
            //sql ="create table if not exists " + tableName + "(" +attribValue1 + "varchar" + attribValue2+ "int(3))";
            sql="CREATE TABLE "+tableName+"(Name TEXT,age INTEGER)";
            db.execSQL(sql);
        } catch(SQLiteFullException e) {
            e.getMessage();
            Log.d("Test", sql);   
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // TODO Auto-generated method stub

    }
   
    public void createTable() {
        SQLiteDatabase db=this.getWritableDatabase();
        String query = "create table if not exists " + tableName + "("+ attribValue1 + "varchar(20)" + attribValue2    + "int(3))";
        db.execSQL(query);
        db.close();
    }
   
    public int insertTable(Employee emp){
        SQLiteDatabase db=this.getWritableDatabase();
        ContentValues cv=new ContentValues();
        cv.put("Name",emp.getName());
        cv.put("age", emp.getAge());
        int status=(int) db.insert(tableName, null, cv);
        db.close();
        return status;   
    }
   
    public List viewTable() {
        //String result="";
        List arrList=new ArrayList ();
        try {
            SQLiteDatabase db=this.getWritableDatabase();
            String query="select * from " + tableName;
            Log.d("query message  ", query);
            Cursor c = db.rawQuery(query, null);
             size=c.getCount();
            nameVal=new String[size];
            ageVal=new int[size];
           
            int col1 = c.getColumnIndex("Name");
            int col2 = c.getColumnIndex("age");
           
            c.moveToFirst();
            if (c != null) {
                do {
                    nameVal[i]=c.getString(col1);
                    ageVal[i]=c.getInt(col2);
                   
                   
                    //arrList.add(ageVal[i]+"");
                    //result=result+nameVal+" "+ageVal+" ";
                    System.out.println("Name     :"+nameVal[i]);
                    System.out.println("Age      :"+ageVal[i]);
                    i++;
                } while (c.moveToNext());
                arrList.add(nameVal);
                arrList.add(ageVal);
            }
           
            db.close();
        }catch(SQLiteFullException exp) {
             exp.getMessage();
             Log.d("Exception Cause", exp.getMessage());
         }
       
        return arrList;
       
    }

}



POJO for DB(Employee.java)

A POJO is simply a Java object that does not implement any special interfaces which is used to design simple Business Domains.

public class Employee {
   
    int _age;
    String _name;
   
    public Employee(String Name,int Age)
    {
        this._name=Name;
        this._age=Age;
    }
   
    public String getName()
    {
        return this._name;
    }
   
    public int getAge()
    {
        return this._age;
    }
   
    public void setName(String Name)
    {
        this._name=Name;
    }
    public void setAge(int Age)
    {
        this._age=Age;
    }
   

}


Activity to populate table values in Expandable List View


This Activity disaplays Expandable Listview that displays populated table values.

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import android.app.ExpandableListActivity;
import android.os.Bundle;
import android.widget.ExpandableListAdapter;
import android.widget.SimpleExpandableListAdapter;

public class sample extends ExpandableListActivity {
    private static final String NAME = "NAME";
    DBHelper helper;
    List dispData;
    Iterator it;
   
    String[] data;
    String[] name;
    int[] age;
    private ExpandableListAdapter mAdapter;
   
      
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        helper = new DBHelper(getApplicationContext());
        dispData=helper.viewTable();

        name=new String[dispData.size()];
       
        name=(String[])dispData.get(0);
        age=(int[]) dispData.get(1);
        for(int i=0;i<name.length;i++)
        {
            System.out.println("New data :"+name[i]);
        }
       
       /* data=new String[dispData.size()];
        it=dispData.iterator();
        i=0;
        while(it.hasNext()) {
            String value=it.next().toString();
            data[i]=value;
            i++;
        }*/
      
           
        List<Map<String, String>> groupData = new ArrayList<Map<String, String>>();
        List<List<Map<String, String>>> childData = new ArrayList<List<Map<String, String>>>();
      
        for (int i = 0; i < name.length; i++) {
            Map<String, String> curGroupMap = new HashMap<String, String>();
            groupData.add(curGroupMap);
            curGroupMap.put(NAME,"" +name[i]);
        
            List<Map<String, String>> children = new ArrayList<Map<String, String>>();
         
                Map<String, String> curChildMap = new HashMap<String, String>();
                children.add(curChildMap);
                curChildMap.put(NAME,"" +age[i]);
                                 
            childData.add(children);
          
        }
       
        // Set up our adapter
        mAdapter = new SimpleExpandableListAdapter(
                this,
                groupData,
                android.R.layout.simple_expandable_list_item_1,
                new String[] { NAME },
                new int[] { android.R.id.text1 },
                childData,
                android.R.layout.simple_expandable_list_item_2,
                new String[] { NAME },
                new int[] { android.R.id.text1 }
                );
        setListAdapter(mAdapter);
    }
    }





Tuesday, November 16, 2010

Gallery Viewer

This is Android Code which I designed recently. Using Gallery View in android we can able to view photos and here is what I done. I developed this using Android 2.2 with eclipse Helios. 

Step 1: Designing XML
I am using a legacy linear layout which contains gallery to load images and image view to view images.
This is how main.xml looks:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:id="@+id/LinearLayout01"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical">
    <Gallery xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/examplegallery"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" />
    <ImageView android:id="@+id/ImageView01"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>

Step 2: Adding Gallery Theme
Add the following xml in your application in /res/values/ folder and name as attributes.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="GalleryTheme">
        <attr name="android:galleryItemBackground" />
    </declare-styleable>
</resources>

Step 3: Adding Images
Add Your Desired Images In /res/drawable folder which contains drawable-hdpi, drawable-mdpi and drawable-ldpi folders refer http://developer.android.com/guide/practices/ui_guidelines/icon_design.html for desinging the icons.

Step 4: The Final Code

Create Objects for Image View and Gallery
protected Gallery gallery;
protected ImageView imgView;

Create Image Array and Context
protected Context con=this;
    public Integer[] imageId={R.drawable.icon,R.drawable.sample_0,
            R.drawable.sample_1,R.drawable.sample_2,
            R.drawable.sample_3,R.drawable.sample_4,
            R.drawable.sample_5,R.drawable.sample_6,
            R.drawable.sample_7};

in Oncreate method of activity class initialize the view for galley and image view and set the source drivers (Adapters) for gallery and invoke the Onclick listener for the items in gallery 

public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
       
        gallery=(Gallery) findViewById(R.id.examplegallery);
        imgView=(ImageView) findViewById(R.id.ImageView01);
        gallery.setAdapter(new ImageAdapter(con));
        gallery.setOnItemClickListener(listener);
    }

Create a new class ImageAdpater for setting Image view which extends the BaseAdapter

public class ImageAdapter extends BaseAdapter {

        int galleryBackGround;
       
        public ImageAdapter(Context c) {
            con=c;
            TypedArray tArray=obtainStyledAttributes(R.styleable.GalleryTheme);
            galleryBackGround=tArray.getResourceId(R.styleable.GalleryTheme_android_galleryItemBackground,0);
            tArray.recycle();
        }
       
        @Override
        public int getCount() {
            // TODO Auto-generated method stub
            return imageId.length;
        }

        @Override
        public Object getItem(int position) {
            // TODO Auto-generated method stub
            return position;
        }

        @Override
        public long getItemId(int position) {
            // TODO Auto-generated method stub
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            // TODO Auto-generated method stub
            ImageView iv=new ImageView(con);
            iv.setImageResource(imageId[position]);
            iv.setLayoutParams(new Gallery.LayoutParams(77, 77));
            iv.setScaleType(ImageView.ScaleType.FIT_XY);
            iv.setBackgroundResource(galleryBackGround);
           
            return iv;
        }
       
    }

Then finally to view Image implement the OnItemClickListener as follows:

protected OnItemClickListener listener=new OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View v, int position,
                long id) {
            // TODO Auto-generated method stub
            Toast.makeText(getApplicationContext(), "You selected picture "+position, Toast.LENGTH_LONG).show();
            imgView.setScaleType(ImageView.ScaleType.FIT_XY);
            Log.d("Left padding ", ""+imgView.getPaddingLeft());
            Log.d("right padding ", ""+imgView.getPaddingRight());
            Log.d("top padding ", ""+imgView.getPaddingTop());
            Log.d("bottom padding ", ""+imgView.getPaddingBottom());
            imgView.setImageResource(imageId[position]);
            imgView.setPadding(30, 10, 30, 10);
        }
    };