Android 2.3 (Gingerbread) released

Yesterday Google fially released the long-anticipated Android 2.3 (Gingerbread).

here are some of the new features:
  1. API Level: 9.
  2. The Dalvik VM introduces a new concurrent garbage collector that produces a smoother and faster performance.
  3. Session Initiation Protocol (SIP) based VoIP API to build telephony applications.
  4. Near Field Communication (NFC) API.
  5. New Sensors: Gyroscope (for measuring orientation), barometer (for measuring atmospheric pressure), sensors for gravity and acceleration.
  6. Support for multiple cameras: the camera API can detect multiple cameras in the device and add new capabilites for shooting such as managing focus.
  7. Usage of third-party video drivers: improves the performance of OpenGL ES.
  8. Audio Effects: new audio effects such as bass boost, reverb and equalization.
  9. New Downlaod Manager: handles downloading files in the background.
  10. Strict Mode: helps developers to optimize their code by detecting disk or network usage that could degrade the performance of the application.
and here's the official release video:

Reactions: 

Android Content Providers

Remember when we created a sqlite database android application. We saw that the database file is stored in the file system directories of that application meaning that the database cannot be accessed from another application. You can apply the same thing on any resources within your application (Files, images, videos, …).
But there is a method to expose your data across multiple applications: Content Providers.
Content Providers expose an application’s data across all other applications, you can use content providers to store or retrieve data of one application from any other application.
In this post we’re going to see how to deal with the existing default content providers by retrieving and manipulating data through them.
Android default content providers:
There are many built-in content providers supplied by OS. They are defined in the android.provider package, they include:
·         Browser.
·         Calllog.
·         Live Folders.
·         Contacts Contract.
·         Media Store.
·         Settings

content providers basics:

the concept of content providers is pretty similar to the concept of ASP.NET Web Services they provide data encapsulation through exposing data by URis. Any content provider is invoked by a URi in the form of content://provider_name . for example the URi of the Contacts content provider that retrieves all contacts is in the following form content://contacts/people. If you want to retrieve a particular contact (by its ID) then it would be in this form: content://contacts/people/5.

You do not need to write the URis of the content providers manually as they are stored as constant values in their respective content provider classes.

The Uri of the Contacts phones content provider is defined in
ContactsContract.CommonDataKinds.Phone.CONTENT_URI
(content://com.android.contacts/data/phones)

The Uri of the browser Bookmarks content provider is defined in
Browser.BOOKMARKS_URI
(content://browser/bookmarks)

The Media store (Video) stored in external device (SD Card) is defined in
MediaStore.Video.Media.EXTERNAL_CONTENT_URI
(content://media/external/video/media) and so on.

content providers allow you to perform basic CRUD operations: Create,Read, Update and Delete on data.

Making Queries

to retrieve data from a content provider we run a sql-like query using ManagedQuery object. The ManagedQuery object returns a cursor holding the result set.

To retrieve a list of all contacts and display them in a ListView
We first define our activity xml layout:
<?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_width="wrap_content"
  android:layout_height="wrap_content"
  android:id="@+id/txt"
  />
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="@+id/list"
/>
</LinearLayout>

And define the layout of each row in the ListView:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:orientation="horizontal"
  >
  <TextView
  android:layout_width="100px"
  android:layout_height="wrap_content"
  android:id="@+id/txtName"
  android:layout_weight="1"
  />
  <TextView
  android:layout_width="100px"
  android:layout_height="wrap_content"
  android:id="@+id/txtNumber"
  android:layout_weight="1"
  />
</LinearLayout>

Remember to add the following permission to the manifest.xml file
<uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>

To retrieve the contacts and bind them to the listView:
String [] projection=new String[]{ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,ContactsContract.CommonDataKinds.Phone.NUMBER,ContactsContract.CommonDataKinds.Phone._ID};
        txt.setText(ContactsContract.PhoneLookup.CONTENT_FILTER_URI.toString());
       Uri contacts =  ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
        
        Cursor managedCursor = managedQuery(contacts,projection,null,null,null);
        //Cursor managedCursor =cr.query(contacts, projection, null, null, null); 
        ListAdapter sca=new SimpleCursorAdapter(this,R.layout.listrow,managedCursor,projection,to);
        list.setAdapter(sca);


the above code retrieves all the contacts in the following steps:
  1. We first define the projection of our query, we define the columns we want to retrieve in the result set.We define a String array containing the names of the columns we want to retreieve.The contacts column names are defined in ContactsContract.CommonDataKinds.Phone class.Note that we need to retrieve the _ID column as the cursor that retrieves the data expects such a column to be there.
  2. We specify the Uri of the content provider ContactsContract.CommonDataKinds.Phone.CONTENT_URI
  3. We retrieve the data by a cursor
    Cursor managedCursor = managedQuery(contacts,projection,null,null,null);The cursor is retrieved by executing a managedQuery which has the following parameters:
    1. The Uri of the content provider.
    2. A String Array of the columns to be retrieved (projection)
    3. Where clause.
    4. String array containing selection arguments values.
    5. String representing the order by clause, we can use it but here it will be null. If we want to sort the contacts by name it would be ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME +“ asc”
  4. Then we create a list adapeter using the cursor and bind the ListView to it.

The previous example retrieves all the contacts but what if we want to retrieve a certain contact by name:
There are two ways:
  1. Using the same code above but adding a where clause and selection arguments to the managed wuery so it becomes like this:
    Cursor managedCursor = managedQuery(contacts,projection,ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME+"=?",new String[]{"Jack"},null);
    This retrieves contact info of a person named Jack.

  2. The other method is to inject the query in the Uri, instead of using Uri
    contacts =  ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
    we use
    Uri contacts=Uri.withAppendedPath(ContactsContract.CommonDataKinds.Phone.CONTENT_FILTER_URI,Uri.encode("Jack"));
    This is equivalent to the following Uri content://com.android.contacts/data/phones/Jack

Inserting,updating and deleting:

to insert data using a content provider there are two methods

First:
Using the Insert() method of your activity’s content resolver object. Like this example t insert a new bookmark to the browser:
ContentValues cv=new ContentValues();
      cv.put(Browser.BookmarkColumns.TITLE, "End Gadget");
      cv.put(Browser.BookmarkColumns.URL, "http://www.engadget.com/");
      cv.put(Browser.BookmarkColumns.BOOKMARK,1);
      Uri u= getContentResolver().insert(Browser.BOOKMARKS_URI, cv);

We create a ContentValues object and add to it all the required fields, then we call getContentResolver().insert method which returns the Uri of the newly inserted item.
It would be in this example content://browser/bookmarks/17
We can use the generated Uri to update or delete the item later.

Second:
We can replace the getcontentresolver().insert() method with bulkInsert method if we want to insert multiple items at a time.
The bulkInsert(Uri url,ContentValues[] values) method returns the number of new items created.

Updating info using Content Providers:

To update data using content providers, we use getContnetResolver.Update() method:
This code updates the title of an existing browser bookmark:
ContentValues cv=new ContentValues();
cv.put(Browser.BookmarkColumns.TITLE, "End Gadget mod");
      //uriBook= getContentResolver().insert(Browser.BOOKMARKS_URI, cv);
      getContentResolver().update(Browser.BOOKMARKS_URI, cv, BookmarkColumns.TITLE+"=?", new String[]{"End Gadget"});

the Update method has the following parameters:
  • Content Providers Uri
  • ContentValues object having the new values
  • Where clause
  • String array of the where clause arguments values

Deleting info using Content Providers:

To delete info we use getContentResolver.Delete() method
To delete a bookmark:
getContentResolver().delete(Browser.BOOKMARKS_URI,BookmarkColumns.TITLE+"=?", new String[]{"End Gadget"});

the delete function has the following parameters:
  • Content Providers Uri
  • Where clause
  • String array of the where clause arguments values

Remember to add the following permissions to the manifest.xml to add and read browser bookmarks:
<uses-permission android:name="android.permission.WRITE_CONTACTS"></uses-permission>
<uses-permission android:name="com.android.browser.permission.WRITE_HISTORY_BOOKMARKS"></uses-permission>

Reactions: 

How to check if the phone is connected to the Internet

to check whether your phone is connected to the Internet, use the following code:
ConnectivityManager con=(ConnectivityManager)getSystemService(Activity.CONNECTIVITY_SERVICE);
        boolean wifi=con.getNetworkInfo(ConnectivityManager.TYPE_WIFI).isConnectedOrConnecting();
        boolean internet=con.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).isConnectedOrConnecting();

these lines check for internet connection whether it is through WiFi or Mobile Internet.

you need to add the following permission to the AndroidManifest.xml file
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Another method is what our freind Kevin mentioned in the comments, is to check if a certain website is reachable or not like this:
public static boolean isOnline() {
try {
InetAddress.getByName("google.ca").isReachable(3);
return true;
} catch (UnknownHostException e){
return false;
} catch (IOException e){
return false;
}
}

we check if a site is reachable within a certain timeout or not.

Reactions: 

Using SQLite Database with Android

Android default Database engine is Lite. SQLite is a lightweight transactional database engine that occupies small amout of disk storage and memory, so its a perfect choice for creating databases on many mobile operating systems such as Android, iOS.

Things to consider when dealing with SQLite:
  1. Data type integrity is not maintained in SQLite, you can put a value of a certain data type in a column of another dataype (put string in an integer and vice versa).
  2. Referential integrity is not maintained in SQLite, there is no FOREIGN KEY constraints or JOIN statements.
  3. SQLite Full Unicode support is optional and not installed by default.

In this tutorial we will create a simple database application to store employees data.

the DB has:
Tables:
  1. Employees
  2. Dept.
Views:
  1. ViewEmps: to display employees and their relative departments.


Creating SQLite Database

By default SQLite on Android does not have a management interface or an application to create and manage data bases from, so we're going to create the database ourselves by code.

First we will create a class that handles all the operations required to deal with the database such as creating the database, creating tables, inserting and deleting records and so on.

The first step is to create a class that inherits from SQLiteOpenHelper class. this class provides two methods to override to deal with the database:
  1. onCreate(SQLiteDatabase db): invoked when the database is created, this is where we can create tables and columns to them, create views or triggers.
  2. onUpgrade(SQLiteDatabse db, int oldVersion, int newVersion): invoked when we make a modification to the database such as altering, dropping , creating new tables.


our class will have the following members
public class DatabaseHelper extends SQLiteOpenHelper {

 static final String dbName="demoDB";
 static final String employeeTable="Employees";
 static final String colID="EmployeeID";
 static final String colName="EmployeeName";
 static final String colAge="Age";
 static final String colDept="Dept";
 
 static final String deptTable="Dept";
 static final String colDeptID="DeptID";
 static final String colDeptName="DeptName";
 
 static final String viewEmps="ViewEmps";

The Constructor:
public DatabaseHelper(Context context) {
  super(context, dbName, null,33); 
  }

The constructor of the super class has the following parameters:

Context con: the context attached to the database.
dataBaseName: the name of the database.
CursorFactory: some times we may use a class that extends the Cursor class to implement some extra validations or operations on the queries run on the database. In this case we pass an instance of CusrsorFactory to return a reference to our derived class to be used instead of the default cursor,
In this example we are going to use the standard Cursor Interface to retrieve results, so the CursorFactory parameter is going to be null.

Version: the version of the schema of the database.

The constructor creates a new blank database with the specified name and version.

Creating the database:

The first superclass method to override is onCreate(SQLiteDatabase db):
public void onCreate(SQLiteDatabase db) {
  // TODO Auto-generated method stub
  
  db.execSQL("CREATE TABLE "+deptTable+" ("+colDeptID+ " INTEGER PRIMARY KEY , "+
    colDeptName+ " TEXT)");
  
  db.execSQL("CREATE TABLE "+employeeTable+" ("+colID+" INTEGER PRIMARY KEY AUTOINCREMENT, "+
    colName+" TEXT, "+colAge+" Integer, "+colDept+" INTEGER NOT NULL ,FOREIGN KEY ("+colDept+") REFERENCES "+deptTable+" ("+colDeptID+"));");
  
  
  db.execSQL("CREATE TRIGGER fk_empdept_deptid " +
    " BEFORE INSERT "+
    " ON "+employeeTable+
    
    " FOR EACH ROW BEGIN"+
    " SELECT CASE WHEN ((SELECT "+colDeptID+" FROM "+deptTable+" WHERE "+colDeptID+"=new."+colDept+" ) IS NULL)"+
    " THEN RAISE (ABORT,'Foreign Key Violation') END;"+
    "  END;");
  
  db.execSQL("CREATE VIEW "+viewEmps+
    " AS SELECT "+employeeTable+"."+colID+" AS _id,"+
    " "+employeeTable+"."+colName+","+
    " "+employeeTable+"."+colAge+","+
    " "+deptTable+"."+colDeptName+""+
    " FROM "+employeeTable+" JOIN "+deptTable+
    " ON "+employeeTable+"."+colDept+" ="+deptTable+"."+colDeptID
    );
  //Inserts pre-defined departments
  InsertDepts(db);
  
 }


the method creates tables with columns,a view and a trigger.

The method is invoked when the database is created. So we create our table and specify the columns.

This method is invoked when the database does not exist on the disk, it’s executed only once on the same device at the first time the application is run on the device.

Upgrading the database:

some times we want to upgrade the database by changing the schema, add new tables or change column data types.
this is done by overriding onUpdate(SQLiteDatabase db,int old Version,int newVerison) method:

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  // TODO Auto-generated method stub
  
  db.execSQL("DROP TABLE IF EXISTS "+employeeTable);
  db.execSQL("DROP TABLE IF EXISTS "+deptTable);
  
  db.execSQL("DROP TRIGGER IF EXISTS dept_id_trigger");
  db.execSQL("DROP TRIGGER IF EXISTS dept_id_trigger22");
  db.execSQL("DROP TRIGGER IF EXISTS fk_empdept_deptid");
  db.execSQL("DROP VIEW IF EXISTS "+viewEmps);
  onCreate(db);
 }
 

This method is invoked when the version number specified in the constructor of the class changes.

when you want to append a change to your database you must change the version number in the constructor of the class:

so when you pass the constructor a version number of 2:
public DatabaseHelper(Context context) {
  super(context, dbName, null,2);
  
  // TODO Auto-generated constructor stub
 }
instead of 1:
super(context, dbName, null,2);
the application understands that you want to upgrade the database and onUpgrade method will be invoked

A typical implementation of this method is to drop the tables and create them again with the additional modifications.

Managing Foreign-Key Constraints:

we mentioned before that SQLite 3 by default does not support foreign key constraint, however we can force such a constraint using TRIGGERS:

we will create a trigger that ensures that when a new Employee is inserted his/her Dept value is present in the original Dept table.

the sql statement to create such a trigger would be like this:
CREATE TRIGGER fk_empdept_deptid Before INSERT ON Employees 
FOR EACH ROW BEGIN
    SELECT CASE WHEN ((SELECT DeptID FROM Dept WHERE DeptID =new.Dept ) IS NULL)
    THEN RAISE (ABORT,'Foreign Key Violation') END;
    END

in onCreate method we created this trigger like this:
db.execSQL("CREATE TRIGGER fk_empdept_deptid " +
    " BEFORE INSERT "+
    " ON "+employeeTable+
    
    " FOR EACH ROW BEGIN"+
    " SELECT CASE WHEN ((SELECT "+colDeptID+" FROM "+deptTable+" WHERE "+colDeptID+"=new."+colDept+" ) IS NULL)"+
    " THEN RAISE (ABORT,'Foreign Key Violation') END;"+
    "  END;");


Executing SQL statements:

now let's begin executing basic sql statements. you can execute any sql statement that is not a query whether it is insert, delete, update or anything using db.execSQL(String statement) method like when we did when creating the database tables:
db.execSQL("CREATE TABLE "+deptTable+" ("+colDeptID+ " INTEGER PRIMARY KEY , "+
    colDeptName+ " TEXT)");

Inserting records:

we insert records to the databse using the following code for example to insert records in the Dept table:
SQLiteDatabase db=this.getWritableDatabase();
 ContentValues cv=new ContentValues();
   cv.put(colDeptID, 1);
   cv.put(colDeptName, "Sales");
   db.insert(deptTable, colDeptID, cv);

   cv.put(colDeptID, 2);
   cv.put(colDeptName, "IT");
   db.insert(deptTable, colDeptID, cv);
                     db.close();

notice that we need to call this.getWritableDatabase() to open the connection with the database for reading/writing.
the ContentValues.put has two parameters: Column Name and the value to be inserted.

also it is a good practice to close the database after executing statements.

Updating values:

to execute an update statement we have two ways

  1. to execute db.execSQL
  2. to execute db.update method:
public int UpdateEmp(Employee emp)
  {
   SQLiteDatabase db=this.getWritableDatabase();
   ContentValues cv=new ContentValues();
   cv.put(colName, emp.getName());
   cv.put(colAge, emp.getAge());
   cv.put(colDept, emp.getDept());
   return db.update(employeeTable, cv, colID+"=?", new String []{String.valueOf(emp.getID())});
   
  }

the update method has the following parameters:

  1. String Table: the table to update a value in
  2. ContentValues cv: the content values object that has the new values
  3. String where clause: the WHERE clause to specify which record to update.
  4. String[] args: the arguments of the WHERE clause.
Deleteing rows:

as in update to execute a delete statement we have two ways

  1. to execute db.execSQL
  2. to execute db.delete method:
public void DeleteEmp(Employee emp)
  {
   SQLiteDatabase db=this.getWritableDatabase();
   db.delete(employeeTable,colID+"=?", new String [] {String.valueOf(emp.getID())});
   db.close();
  }

the delete method has the same parameters as the update method.

Executing queries:

to execute queries there are two methods:

  1. Execute db.rawQuery method.
  2. Execute db.query method.

to execute a raw query to retreive all departments
Cursor getAllDepts()
  {
   SQLiteDatabase db=this.getReadableDatabase();
   Cursor cur=db.rawQuery("SELECT "+colDeptID+" as _id, "+colDeptName+" from "+deptTable,new String [] {});
   
   return cur;
  }

the rawQuery method has two parameters:

  1. String query: the select statement.
  2. String[] selection args: the arguments if a WHERE clause is included in the select statement.

Notes:
  1. The result of a query is returned in Cursor object.
  2. In a select statement if the primary key column (the id column) of the table has a name other than _id then you have to use an alias in the form SELECT [Column Name] as _id
  3. cause the Cursor object always expects that the primary key column has the name _id or it will throw an exception .


another way to perform a query is to use a db.query method.

a query to select all employees in a certain department from a view would be like this:
public Cursor getEmpByDept(String Dept)
  {
   SQLiteDatabase db=this.getReadableDatabase();
   String [] columns=new String[]{"_id",colName,colAge,colDeptName};
   Cursor c=db.query(viewEmps, columns, colDeptName+"=?", new String[]{Dept}, null, null, null);
   return c;
  }

the db.query has the folowing parameters:
  1. String Table Name: the name of the table to run the query against.
  2. String [ ] columns: the projection of the query i.e the columns to retrieve.
  3. String WHERE clause: where clause, if none pass null.
  4. String [ ] selection args: the parameters of the WHERE clause.
  5. String Group by: a string specifying group by clause.
  6. String Having: a string specifying HAVING clause.
  7. String Order By by: a string Order By by clause.
Managing Cursors:

Result sets of queries are returned in Cursor objects.
there are some common methdos that you will use with cursors:
  1. boolean moveToNext(): moves the cursor by one record in the result set, returns false if moved past the last row in the result set.
  2. boolean moveToFirst(): moves the cursor to the first row in the result set, returns false if the result set is empty.
  3. boolean moveToPosition(int position): moves the cursor to a certain row index within the boolean result set, returns false if the position is un-reachable
  4. boolean moveToPrevious():moves the cursor to the preevious row in the result set, returns false if the cursor is past the first row.
  5. boolean moveToLast():moves the cursor to the lase row in the result set, returns false if the result set is empty.

there are also some useful methods to check the position of a cursor:
boolean isAfterLast(), isBeforeFirst, isFirst,isLast and isNull(columnIndex).


also if you have a result set of only one row and you need to retreive values of certain columns, you can do it like this:
public int GetDeptID(String Dept)
  {
   SQLiteDatabase db=this.getReadableDatabase();
   Cursor c=db.query(deptTable, new String[]{colDeptID+" as _id",colDeptName},colDeptName+"=?", new String[]{Dept}, null, null, null);
   //Cursor c=db.rawQuery("SELECT "+colDeptID+" as _id FROM "+deptTable+" WHERE "+colDeptName+"=?", new String []{Dept});
   c.moveToFirst();
   return c.getInt(c.getColumnIndex("_id"));
  
  }

we have Cursor.getColumnIndex(String ColumnName) to get the index of a column.

then to get the value of a certain column we have Cursor.getInt(int ColumnIndex) method.
also there are getShort,getString,getDouble, getBlob to return the value as a byte array.

it's a good practice to close() the cursor after using it.

Download a sample application on using database in Android from here

Reactions: 

Using Android SlidingDrawer

Remeber Android's old versions' (prior to 2.2) launcher screen where we had a sliding pane at the bottom that when dragged upwards displays the applications menu of the phone, that is called the SlidingDrawer control.


consider this layout:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">
  <SlidingDrawer
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:id="@+id/drawer"
  android:handle="@+id/handle"
  android:content="@+id/content"
  >
  <ImageView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:id="@+id/handle"
  android:src="@drawable/tray_handle_normal"
  />
  <LinearLayout
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:orientation="vertical"
  android:id="@+id/content"
  >
  <TextView
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="This is some text"
  android:id="@+id/txt"
  />
  <Button
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:text="Click Me"
  android:id="@+id/btn"
  android:onClick="ClickHandler"
  />
  </LinearLayout>
  
  </SlidingDrawer>
</FrameLayout>



when the SlidingDrawer is pressed it looks like this:

the SlidingDrawer is a container that when dragged or pressed shows/hides its contents.

As the SlidingDrawer displays one content at a time, it must be declared within FrameLayout

the SlidingDrawer has two key properties:
android:handle: specifies the id of the control that acts as the handle.
android:content: specifies the id of the view that acts as content of the SlidingDrawer, most times will be a container.

you can open/close the drawer from the code like this:
if(drawer.isOpened())
    {
     drawer.close();
     btnToggle.setText("Open");
    }
    else
    {
     drawer.open();
     btnToggle.setText("Close");
    }

you can open/close the drawer with animation using these methods instead
drawer.animateClose();
drawer.animateOpen();

or you can handle the open/close operations automatically using toggle method:
drawer.toggle();
drawer.animateToggle();

you can lock/unlock the SlidingDrawer to enable/disable dragging or clicking of the drawer using these methods:
drawer.lock();
drawer.unlock();

Responding to SlidingDrawer Events:

SlidingDrawer has three key callbacks:
  1. when the drawer is open, handled by implementing OnDrawerOpenListener.
  2. when the drawer is close, handled by implementing OnDrawerCloseListener.
  3. when the drawer is close, handled by implementing OnDrawerScroll
    Listener.


drawer.setOnDrawerOpenListener(new OnDrawerOpenListener() {
    
    @Override
    public void onDrawerOpened() {
     // TODO Auto-generated method stub
     TextView txtStatus=(TextView)findViewById(R.id.txtStatus);
     txtStatus.setText("Opened");
     ImageView view=(ImageView)drawer.getHandle();
     view.setImageResource(R.drawable.tray_handle_selected);
     
    }
   });
         
         
                  
         drawer.setOnDrawerCloseListener(new OnDrawerCloseListener() {
    
    @Override
    public void onDrawerClosed() {
     // TODO Auto-generated method stub
     TextView txtStatus=(TextView)findViewById(R.id.txtStatus);
     txtStatus.setText("Closed");
     ImageView view=(ImageView)drawer.getHandle();
     view.setImageResource(R.drawable.tray_handle_normal);
    }
   });
         
         drawer.setOnDrawerScrollListener(new OnDrawerScrollListener() {
    
    @Override
    public void onScrollStarted() {
     // TODO Auto-generated method stub
     TextView txtStatus=(TextView)findViewById(R.id.txtStatus);
     txtStatus.setText("Scroll start");
     
    }
    
    @Override
    public void onScrollEnded() {
     // TODO Auto-generated method stub
     TextView txtStatus=(TextView)findViewById(R.id.txtStatus);
     txtStatus.setText("Scroll end");
    }
   });

Notes:

Reactions: 

Using View Flipper in Android

Suppose you want to display a news bar in your activity. this news bar displays a single news item at a time then flips and shows next item and so on, then your choice would be Android's ViewFlipper.

ViewFlipper inherits from frame layout, so it displays a single view at a time.

consider this layout:
<?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_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
    <Button
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="Flip"
    android:id="@+id/btn"
    android:onClick="ClickHandler"
    />
    <ViewFlipper
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:id="@+id/flip"
    >
    <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Item1"
    />
    <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Item2"
    />
    <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Item3"
    />
    </ViewFlipper>
</LinearLayout>


just a ViewFlipper container that contains three text views

now we want to flip the views when the button is clicked
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        btn=(Button)findViewById(R.id.btn);
        flip=(ViewFlipper)findViewById(R.id.flip);
            
    }
    
    public void ClickHandler(View v)
    {
     
     flip.showNext();
     
    }

if we want to flip in reverese direction we could use
flip.showPrevious() instead

we can add animations to the child views when they appear or disappear:
@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        btn=(Button)findViewById(R.id.btn);
        flip=(ViewFlipper)findViewById(R.id.flip);
        //when a view is displayed
        flip.setInAnimation(this,android.R.anim.fade_in);
       //when a view disappears
     flip.setOutAnimation(this, android.R.anim.fade_out);     
    }

we can also set the ViewFlipper to flip views automatically when the button is clicked:
public void ClickHandler(View v)
    {
     
     
     //specify flipping interval
     flip.setFlipInterval(1000);
     flip.startFlipping();
    }

we can stop the flipping by calling flip.stopFlipping(); method.

or we can set the flipper to flip autommatically when the activity starts
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        btn=(Button)findViewById(R.id.btn);
        flip=(ViewFlipper)findViewById(R.id.flip);
        flip.setInAnimation(this,android.R.anim.fade_in);
     flip.setOutAnimation(this, android.R.anim.fade_out);
     flip.setFlipInterval(1000);
     flip.setAutoStart(true);
     
    }

Reactions: 

Currency Converter v1.0 released on Slide ME

Currency Converter v1.0 is released and is available at this location:


the application provides real time currency convertion for more than 100 currencies.

provides the conversion rate of two currencies and the conversion of an amount of money from one currency to another.

download it for free and tell me what you think.

Reactions: 

Using Alerts in Android

In a previuos post we saw how to display a popup message using Toasts. Toasts are just notification messages involving no interaction from the user.

another way to show interactive messages is to use Alerts. alerts act as MessageBox or JOptionPane in J2SE. they have buttons that can be used to take decisions.

Creating Alerts

let's check this example to create an alert and show it:
//declared as final to be able to reference it in inner class declartations of the handlers 
     final AlertDialog.Builder builder=new AlertDialog.Builder(this);
     builder.setTitle("Alert Dialog");
     builder.setMessage("This is the alert's body");
     builder.setIcon(android.R.drawable.ic_dialog_alert);
     
     builder.setPositiveButton("OK", new OnClickListener() {
   
   @Override
   public void onClick(DialogInterface dialog, int which) {
    TextView txt=(TextView)findViewById(R.id.txt);
    txt.setText("You clicked Ok");
   }
  });
     
     builder.setNegativeButton("Cancel", new OnClickListener() {
   
   @Override
   public void onClick(DialogInterface dialog, int which) {
    // TODO Auto-generated method stub
    TextView txt=(TextView)findViewById(R.id.txt);
    txt.setText("You clicked Cancel");
   }
  });
     
     builder.setNeutralButton("Do something", new OnClickListener() {
   
   @Override
   public void onClick(DialogInterface dialog, int which) {
    // TODO Auto-generated method stub
    TextView txt=(TextView)findViewById(R.id.txt);
    txt.setText("Neutral Button Clicked");
    AlertDialog ad=builder.create();
    ad.cancel();
   }
  });
     
     builder.setOnCancelListener(new OnCancelListener() {
   
   @Override
   public void onCancel(DialogInterface dialog) {
    // TODO Auto-generated method stub
    TextView txt=(TextView)findViewById(R.id.txt);
    txt.setText(txt.getText()+" the cancel listner invoked");
   }
  });
     
     
     
     builder.show();

the previous code displays the following Alert

the code may look bulky but it's very simple.
first we create an instance of AlertDialog.Builder. we use the builder object to construct the AlertDialog object.
we specify the title and the icon of the alert. then the text to display in the body of the message.
the AlertDialog can display up to three buttons:
positive button: represents the OK button.
Negative button: represents the cancel button.
Neutral button: represents a button to perform another functionality other than ok or cancel.

note that there are no restrictions on the use of the three buttons, they can perform the same functionality the difference is just in logical meaning. but the three buttons cause the Alert dialog to dismiss.

we then specify the text and the click handler of each button.
in the neatral button click handler we added the lines AlertDialog ad=builder.create(); and ad.cancel();. the firt line gets a reference to the current dialog created by the builder to provide additional functionality such as invoking cancel() method.

the cancel method raises the onCancel callbcak method.

we could have replaced the previous code with the following:
AlertDialog ad=builder.create();
     ad.setMessage(message);
     ad.setIcon(icon);
     ad.setMessage(message);
     ad.setButton(text, listener);
       .
       .
       .

Displaying Custom Views:

alerts can display complex views rather than simple text messages. create an xml layout file called alertview.xml like this:
<?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"
    android:id="@+id/toastView"
    android:background="#DAAA"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Hello alerts"
    android:textColor="#000"
    />
    
   <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:id="@+id/txtDate"
    android:textColor="#000"
    />
    <Button
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:id="@+id/btnAlert"
    android:text="Click"
    />
</LinearLayout>



to display this view as the alert view we do it like this:
View bodyView=getLayoutInflater().inflate(R.layout.alertview, (ViewGroup)findViewById(R.id.toastView));
     
     
     TextView txtDate=(TextView)bodyView.findViewById(R.id.txtDate);
     txtDate.setText(Calendar.getInstance().getTime().toLocaleString());
     Button btnAlert=(Button)bodyView.findViewById(R.id.btnAlert);
     btnAlert.setOnClickListener(new View.OnClickListener() {
   
   @Override
   public void onClick(View v) {
    // TODO Auto-generated method stub
    TextView txtDate=(TextView)bodyView.findViewById(R.id.txtDate);
       txtDate.setText(Calendar.getInstance().getTime().toLocaleString());
       TextView txt=(TextView)findViewById(R.id.txt);
    txt.setText(Calendar.getInstance().getTime().toLocaleString());
   }
  });
     builder.setView(bodyView);
       .
       .
       .

what is interesting in this approach is that the alert is fully interactive, by clicking the button you can change the value of any view in the alert or in the activity.

you can also set the title of hte alert to be a custom view via builder.setCustomTitle(View v) method in the same way described above.

Displaying an alert of items:

alerts can display a list of items from which the user selects from like this:
final String [] items=new String []{"Item 1","Item 2","Item 3","Item 4"};
     AlertDialog.Builder builder=new AlertDialog.Builder(this);
     builder.setTitle("Items alert");
     
     builder.setItems(items, new OnClickListener() {
   
   @Override
   public void onClick(DialogInterface dialog, int which) {
    // TODO Auto-generated method stub
    TextView txt=(TextView)findViewById(R.id.txt);
    txt.setText(items[which]);
   }
  });
     
     builder.show();
this will display an alert like this:

notice that we do not have to specify any buttons because when the user clicks on any item the alert will be dismissed.

if the list items are in an Adapter we can achieve the same result using builder.setAdapter(Adapter ad,OnClickListener listner) method:
final String [] items=new String []{"Item 1","Item 2","Item 3","Item 4"};
     ArrayAdapter arr=new ArrayAdapter(this, android.R.layout.select_dialog_item,items);
     
     AlertDialog.Builder builder=new AlertDialog.Builder(this);
     builder.setTitle("Adapter alert");
     
     builder.setAdapter(arr, new OnClickListener() {
   
   @Override
   public void onClick(DialogInterface dialog, int which) {
    // TODO Auto-generated method stub
    TextView txt=(TextView)findViewById(R.id.txt);
    txt.setText(items[which]);
   }
  });

or if the items are returned from a database in a cursor we can use
builder.setCursor(Cursor cursor, OnClickListener listner, String labelColumn)

Displaying alerts with items with choices:

we can add items to the alert with choices whether they are single choice (Radio buttons) or multiple choices (Check boxes).

to display single choice items:
final String [] items=new String []{"Item 1","Item 2","Item 3","Item 4"};
     AlertDialog.Builder builder=new AlertDialog.Builder(this);
     builder.setTitle("List alert");
     builder.setSingleChoiceItems(items, 0, new OnClickListener() {
   
   @Override
   public void onClick(DialogInterface dialog, int which) {
    // TODO Auto-generated method stub
    TextView txt=(TextView)findViewById(R.id.txt);
    txt.setText(items[which]);
   }
  });
     builder.setPositiveButton("OK", new OnClickListener() {
   
   @Override
   public void onClick(DialogInterface dialog, int which) {
    // TODO Auto-generated method stub
    
   }
  });
     builder.show();

the second parameter of setSingleChoiceItems is an integer specifying the index of the selected item

notice that we added a postive button that when clicked dismisses the alert cause unlike the regular items list the alert won't be dismissed when an item is selected.

the builder.setSingleChoiceItems method has other overloads that can accept an Adapter or a Cursor as parameters that hold the items to be displayed

to display multiple choice items:
final String [] items=new String []{"Item 1","Item 2","Item 3","Item 4"};
     AlertDialog.Builder builder=new AlertDialog.Builder(this);
     builder.setTitle("List alert");
     builder.setMultiChoiceItems(items, null, new OnMultiChoiceClickListener() {
   
   @Override
   public void onClick(DialogInterface dialog, int which, boolean isChecked) {
    // TODO Auto-generated method stub
    TextView txt=(TextView)findViewById(R.id.txt);
    txt.setText(txt.getText()+" "+items[which]);
   }
  });
     builder.setPositiveButton("OK", new OnClickListener() {
   
   @Override
   public void onClick(DialogInterface dialog, int which) {
    // TODO Auto-generated method stub
    
   }
  });
     builder.show();

the second parameter of setMultiChoiceItems is an array of boolean values specifying which items are set selected. if you want no items to be selected then set it to null, otherwise specify an array with the same length of the items with boolean values indicating which item is selected and which is not like this:
new boolean[] {true,false,...}

works in the fashion as single items choice except that the selection here is multiple.

download a demo applications on alerts from here

Reactions: 

Android popup messages using Toast

In Android you can display pop up messages that lasts for a certain duration and then disappears-using the Toast class.

Toast is a transient message that appears and disappears without any interaction from the user and with no notification to the program that it disappeared.

the Toast can display a simple text message or a complex view.

Displaying simple text:

to display a simple toast that displays a text message we use the following code:
Toast toast=Toast.makeText(this, "Hello toast", 2000);
     toast.setGravity(Gravity.TOP, -30, 50);
     toast.show();

we create the toast using the static Toast.makeText(Context con,String message, int duration) method to create a toast in the current context to display a text message for a duration specified in milli seconds or we can use the constant values Toast.LENGTH_SHORT to display for a short duration or Toast.LENGTH_LONG for longer duration.
The toast by default appears in the center of the screen, you can change the default position by specifying the Gravity and the X and Y offsets.
finally we call the Show() method to display the toast.

the previous toast will be like this:

Displaying complex views:


Toasts can also display complex views. this is done like this:

First: create a layout xml file in res/layout directory. the file must be named toast_layout.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"
    android:id="@+id/toastView"
    >
<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Hello toast"
    android:textColor="#000"
    />
    <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:id="@+id/txtDate"
    android:textColor="#000"
    />
   
    
</LinearLayout>

then from the code
Toast toast=new Toast(this);
     LayoutInflater inflater=this.getLayoutInflater();
     View toastView=inflater.inflate(R.layout.toast_layout, (ViewGroup)findViewById(R.id.toastView));
     TextView txtDate=(TextView)toastView.findViewById(R.id.txtDate);
     txtDate.setText("toast appeared at "+Calendar.getInstance().getTime().toLocaleString());
     toast.setGravity(Gravity.CENTER, 0, 0);
     toast.setView(toastView);
     toast.show();

the toast will be like this:
Notes:
  • In the toast_layout.xml width, if you put any buttons or any control that has a callback, it would appear disabled and the user cannot interact with it.
  • The toast can be created in two ways: by calling Toast.makeText method or by specifyinga view via setView method. when you want to display a simple text use the first one otherwise use the second. if you try to interchange or combie between the two methods an exception will be thrown.

Reactions: 

Using Themes and Styles in Android

In web design we have the concept of Styles and Themes. Styles like Cascading Style Sheets (CSS) define the values of the web controls attributes such as width, heigth, font color, background and so on. A style can be applied on several controls in several web pages.

Themes are used to group a set of styles to be applied on the whole web application. Themes (or sometimes skins) define the look of all control within the application.

Android introduces similar concepts by using Styles and Themes. A Style can be applied to views individually while a Theme is applied to a whole activity.

Styles:

Styles are defined as xml resources files in res/values directory of your project.

consider this definition of a TextView:
<TextView    android:layout_width="fill_parent"   
     android:layout_height="wrap_content"    
     android:textColor="#FFF"    
     android:typeface="monospace"    
     android:text="First Text View"
     android:background="#00F" 
     />


this defines a text view with width and height equal to wrap_content, white font color, font type "monospace" and blue back ground.

if we want to have the same results using a style: we first create a xml file (call it styles.xml) in res/values directory and it would be like this:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="BlueLabel">
<item name="android:layout_width">fill_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:typeface">monospace</item>
<item name="android:background">#00F</item>
<item name="android:textColor">#FFF</item>
</style>
</resources>

then redefine the TextView like this:
<TextView android:text="First Text View"
     style="@style/BlueLabel" / >


and you will receive the same results.
the attributes in the <item>tag can be any layout property.

Inheriting Styles:
Styles in Android has an interesting feature which is the ability to inherit styles in a fashion similar to that in CSS. consider this example:

we have a style for a button like this:
<style name="ButtonStyle">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textSize">15px</item>
<item name="android:typeface">serif</item>
</style>


the button will appear like this:

we can make this style inherit from BlueLabel defined previously by adding the parent attribute to the <style*gt; tag:
<style name="ButtonStyle" parent="BlueLabel">
then the button will be like this:
the button inherited the background color from the parent style.
another interesting feature in styles inheritance is the ability to inherit from the platform built-in styles defined in the android.R.style namespace. to know more about the platform styles check this link

or you can type in your editor (Eclipse) android.R.style and let the intelli-sense list you the complete list of platform styles, if you want to use them in your xml just replace the undrscores with a period like this:
Widget_Button becomes @android:style/Widget.Button.

In the previous button style example we will set the parent of the style to be @android:style/Widget.Button.Small
and the button will be like this:

Note: if you apply a style to a ViewGroup widget, it's child widgets will not inherit that style.

Using Themes

you can apply styles as themes on an activity level or application level.

if you apply a theme on an activity level then all widgets within that activity will inherit from that theme.
to do so, open the AndroidManifest.xml and go the <activity> tag and add the android:theme attribute:
<activity android:name=".StylesDemo"
                  android:label="@string/app_name" android:theme="@style/BlueLabel">


to apply a theme on the application level so that the style will be applied to all activities within your application, open the AndroidManifest.xml and go the <application> tag and add the android:theme attribute:
<application android:icon="@drawable/icon" android:label="@string/app_name" android:theme="@style/BlueLabel">

to set the theme of an activity programmatically call this line in the onCreate method
this.setTheme(R.style.BlueLabel);

Reactions: 

Android Error: Error generating final archive: Debug certificate expired on …

One day I opened eclipse to start a new android application, after creating the project and trying to run it I received the following error:

[2010-08-27 15:32:04 – (Project Name)] Error generating final archive: Debug certificate expired on 7/30/10 10:42 PM!

After searching I found this link which suggests the solution: http://www.androidian.de/?p=940.

The problem comes from the fact that Android required the applications to be signed even in the debug mode. So it uses a keystore file called debug.keystore to providde keys for signing applications in debug mode. This key store file has a validity period by default 365 days from its creation date.

The First Solution:


Navigate to the .android folder in your home directory “~/.android” (Linux,Mac OS) or c:\Documents and Settings\[User Name]\.android in windows XP or C:\Users\.android in windows Vista or Windows 7, and delete debug.keystore file. Then go to eclipse clean the project, this will create a new debug.keystore file with default validity period 365 days.

The Second Solution:


Create a new default.keystore file with custom validity period (say 1000 days).
  1. Navigate to the .android folder.
  2. Delete the old default.keystore file.
  3. We will use JDK Keytool.exe to generate the new key file. It is found in C:\Program Files\Java\jre6\bin in windows or inside the Java\jre6\bin folder in Mac OS or Linux.
  4. Open the terminal app in Mac OS or Linux or the command prompt and navigate to keytool.exe directory.
  5. Run the following command:
    keytool -genkey -keypass android -keystore debug.keystore -alias androiddebugkey -storepass android -validity 1000 -dname “CN=Android Debug,O=Android,C=US”
  6. This will generate a new default.keystore file with validity period 1000 days.
  7. Copy the generated file to the .android folder, go to eclipse and clean projects and it should work.
The above command has the following options:
  • genkey: generates a key pair.
  • keystore <Key Store Name>: the name of the key store file.
  • alias <alias name>: an alias for the key store. If the alias name is more than 8 characters the first 8 only are used.
  • storepass <password>: the password for the key.
  • validity <Validty Period>: the validity period for the key in days.
  • dname <name>: A Distinguished Name that describes who created the key. The value is used as the issuer and subject fields in the self-signed certificate.

Reactions: 

iPhone-Like Tab bar in Android

In a previous post we saw how to use the TabHost to create tabs in Android applications. Also we noticed that the Tabs in Android appear at the top of the activity.
but what if we want to give the tabs the look of the iPhone Tab Bar ?

this is possible by wrapping the TabWidget and the FrameLayout in a RelativeLayout container and adding android:layout_alignParentBottom="true" attribute to the TabWidget just like this:
<?xml version="1.0" encoding="utf-8"?>


    <TabHost android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@android:id/tabhost"
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <RelativeLayout
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <TabWidget
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@android:id/tabs"
    android:layout_alignParentBottom="true"
    />
     <FrameLayout
     android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@android:id/tabcontent"
     >
     
     </FrameLayout>
    </RelativeLayout>
    </TabHost>




Reactions: 

Tabbed Applications in Android

Some times we want to wrap multiple views in a single window and navigate throught them with a Tab Container. this can be done in Android using TabHost control

There are two ways to use a TabHost application in Android:
  1. Using the TabHost to navigate through multiple views within the same activity.
  2. Using the TabHost to navigate through Actual multiple Activities using intents.
we will explain both ways through this tutorial

Anatomy of Tabbed Application
An activity with a TabHost may look like this:


The Activity consists of:
  1. A TabHost: the root element of the layout.
  2. The TabHost wraps a TabWidget which represents the tab bar.
  3. The TabHost wraps a FrameLayout which wraps the contents of each tab.
There are some rules that we must stick to when using a Tabbed activity:
  1. If the activity is of type TabActivity [optional] then the TabHost must have the id @android:id/tabhost.
  2. The TabWidget must have the id @android:id/tabs.
  3. The FrameLayout must have the id @android:id/tabcontent.
no let's see an exaple to an activity with multiple tabs:
this is the layout
<?xml version="1.0" encoding="utf-8"?>


    <TabHost android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/tabHost"
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <TabWidget
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@android:id/tabs"
    />
     <FrameLayout
     android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@android:id/tabcontent"
     >
     <LinearLayout
     android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@+id/tab1"
    android:orientation="vertical"
    android:paddingTop="60px"
     >
     <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="100px" 
    android:text="This is tab1"
    android:id="@+id/txt1"
    />
    
    
     </LinearLayout>
     
     <LinearLayout
     android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/tab2"
    android:orientation="vertical"
    android:paddingTop="60px"
     >
     <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="100px" 
    android:text="This is tab 2"
    android:id="@+id/txt2"
    />
   
     </LinearLayout>
     
      <LinearLayout
     android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/tab3"
    android:orientation="vertical"
    android:paddingTop="60px"
     >
     <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="100px" 
    android:text="This is tab 3"
    android:id="@+id/txt3"
    />
   
     </LinearLayout>
     </FrameLayout>
    
    </TabHost>

then in the code of our activity
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        TabHost tabHost=(TabHost)findViewById(R.id.tabHost);
        tabHost.setup();
        
        TabSpec spec1=tabHost.newTabSpec("Tab 1");
        spec1.setContent(R.id.tab1);
        spec1.setIndicator("Tab 1");
        
        TabSpec spec2=tabHost.newTabSpec("Tab 2");
        spec2.setIndicator("Tab 2");
        spec2.setContent(R.id.tab2);
        
        TabSpec spec3=tabHost.newTabSpec("Tab 3");
        spec3.setIndicator("Tab 3");
        spec3.setContent(R.id.tab3);
        
        tabHost.addTab(spec1);
        tabHost.addTab(spec2);
        tabHost.addTab(spec3);
        
 }

is going to look like this:

  1. We create tabs using TabSpecs class.
  2. We set the title of each tab using TabSpecs.setIndicator() method.
  3. We set the content of each tab using TabSpecs.setContent() method.
  4. if you use TabActivity to as a base class to your activity, you do not need to call TabHost.Setup() method.
We can add an icon to the title of the tab like this:
TabSpec spec1=tabHost.newTabSpec("Tab 1");
        spec1.setContent(R.id.tab1);
        spec1.setIndicator("Tab 1",getResources().getDrawable(R.drawable.flash));
        
        
        TabSpec spec2=tabHost.newTabSpec("Tab 2");
        spec2.setIndicator("Tab 2",getResources().getDrawable(R.drawable.sun));
        spec2.setContent(R.id.tab2);
        
        TabSpec spec3=tabHost.newTabSpec("Tab 3");
        spec3.setIndicator("Tab 3",getResources().getDrawable(R.drawable.chart));
        spec3.setContent(R.id.tab3);

it will look like this:

we can also specify the indicator to be a view:
TabSpec spec1=tabHost.newTabSpec("Tab 1");
        spec1.setContent(R.id.tab1);
        TextView txt=new TextView(this);
        txt.setText("Tab 1");
        txt.setBackgroundColor(Color.RED);
        spec1.setIndicator(txt);



Setting the content of tabs:

we saw how to set the contents of tabs by specifying multiple layout resources to be displayed within the same activity.

what If we have multiple Activities in our application and we want to navigate between them using tabs ?
in this case we will have one activity as the root activity of the application. this activity will have the TabHost and will navigate to other activities using Intents.
Note: the root activity must inherit from TabActivity.

the root activity will have layout file like this:
<?xml version="1.0" encoding="utf-8"?>
    <TabHost android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@android:id/tabhost"
    xmlns:android="http://schemas.android.com/apk/res/android"
    >
    <TabWidget
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:id="@android:id/tabs"
    />
     <FrameLayout
     android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@android:id/tabcontent"
     >
     </FrameLayout>
    </TabHost>

the other activities will have a simple layout consisting of a TextView.

now to the code of the roor activity
public class TabDemo extends TabActivity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        TabHost tabHost=getTabHost();
        // no need to call TabHost.Setup()        
        
        //First Tab
        TabSpec spec1=tabHost.newTabSpec("Tab 1");
        spec1.setIndicator("Tab 1",getResources().getDrawable(R.drawable.sun));
        Intent in1=new Intent(this, Act1.class);
        spec1.setContent(in1);
        
        TabSpec spec2=tabHost.newTabSpec("Tab 2");
        spec2.setIndicator("Tab 2",getResources().getDrawable(R.drawable.chart));
        Intent in2=new Intent(this,Act2.class);
        spec2.setContent(in2);

        tabHost.addTab(spec2);
        tabHost.addTab(spec3);
    }
}

and the activity will look like this


Adding tabs at run-time:

we can add tabs to TabHost at run-time using TabSpec.setContent(TabContentFactory) method.

the TabContentFactory is an interface that requires the implementation of a callback method createTabContent(String tag) which returns the view to be added to the content of the tab.

so in the last example if we changed code that adds the content of the second tab to this:
TabSpec spec1=tabHost.newTabSpec("Tab 1");
        spec1.setIndicator("Tab 1",getResources().getDrawable(R.drawable.sun));

        spec1.setContent(new TabContentFactory() {
   
   @Override
   public View createTabContent(String tag) {
    // TODO Auto-generated method stub
    
    return (new AnalogClock(TabDemo.this));
   }
  });

the activity will look like this

Reactions: 

Android Simple Image Gallery

In this post we are going to use the gallery control t construct a simple image gallery.
the layout is like the previous post.

remeber that the Gallery control is populated by an adapter, so we will create a custom adapter that contains ImageViews to display the images.
our custom adapter must inherit from BaseAdapter class
package mina.android.GalleryDemo;

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

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;

public class ImageAdapter extends BaseAdapter {
 Context Con;
 //array to hold the values of image resources
 int [] Resources;
 List views;
 
 public ImageAdapter(Context con,int[] resources)
 {
  Con=con;
  Resources=resources;
  views=new ArrayList(resources.length);
 }
 
 @Override
 public int getCount() {
  // TODO Auto-generated method stub
  return Resources.length;
 }

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

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

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
  // TODO Auto-generated method stub
  ImageView img=new ImageView(Con);
  img.setImageResource(Resources[position]);
  views.add(img);
  
  return img;
 }

}


then in our activity onCreate Method:
int []res=new int[]{R.drawable.wc,R.drawable.wc2,R.drawable.wc3,R.drawable.wc4,R.drawable.wc5};
        ItemsInGallery=res.length;
        ImageAdapter imgAdapter=new ImageAdapter(this, res);
        gallery.setAdapter(imgAdapter);

and that was our simple Image gallery.
download the application from here

Reactions: 

Android Gallery Control

In Android the Gallery control is a selection control that displays items in a horizontal gallery. the items in the gallery appear beside each other. they can appear separated by a pre-defined space.

remember that there is a sample demo application for the gallery to download at the end of the post

we can use the gallery to display String items using a simple ArrayAdapter.
so let's see how to create a gallery that displays the word "Hello" in several languages:

the layout:
<?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_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Gallery Demo"
    />
    <Gallery
    android:id="@+id/gallery"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:spacing="100px"
    
    />
</LinearLayout>

and in the OnCreate method
@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        gallery=(Gallery)findViewById(R.id.gallery);
        //String array holding the values
        String [] text=new String[]{"Hello","Hi","Alloha","Bonjour","Hallo","¡Hola"};
        //Array adapter to display our values in the gallery control
        ArrayAdapter arr=new ArrayAdapter(this, android.R.layout.simple_gallery_item, text);
gallery.setAdapter(arr);
}

the gallery will be like this

we can increse the spacing between the items by increasing the value of android:spacing property.

we can display a scroll bar to indicate the position of the current selected item in the gallery like this:
<Gallery
    android:id="@+id/gallery"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:spacing="100px"
    android:scrollbars="horizontal"
    android:scrollbarFadeDuration="0"
    android:scrollX="100px"
    />




setting the android:scrollbarFadeDuration="0" makes the scroll bar always visible.

The android:scrollX property defines the initial scroll offset of the scroll bar which is the initial distance that the gallery is scrolled for.

Handling Gallery Events
since the gallery is a selction Control (a adapter view) so it can register a OnItemSelectedListener to handle the selection of items within the gallery.

final String [] text=new String[]{"Hello","Hi","Alloha","Bonjour","Hallo","¡Hola"};
gallery.setOnItemSelectedListener(new OnItemSelectedListener() {

   @Override
   public void onItemSelected(AdapterView parent, View view,
     int position, long id) {
    // TODO Auto-generated method stub
    TextView txt=(TextView)findViewById(R.id.txt);
    txt.setText(text[position].toString());
   }

   @Override
   public void onNothingSelected(AdapterView parent) {
    // TODO Auto-generated method stub
    
   }
  });


now the final step is to add two navigation buttons: Next and Previous to navigate throught the items in the gallery.
the layout is gonna be like this:
<?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_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="Gallery Demo"
    android:id="@+id/txt"
    />
    <Gallery
    android:id="@+id/gallery"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
    android:gravity="center_horizontal"
    android:spacing="100px"
    android:scrollbars="horizontal"
    android:scrollbarFadeDuration="0"
    android:scrollX="100px"
    />
    <LinearLayout
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:orientation="horizontal"
     android:layout_marginTop="5px"
     >    
     <Button 
     android:text="Previous"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:id="@+id/btnPrev"
     android:onClick="onClick"
      />
      <Button 
     android:text="Next"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
     android:id="@+id/btnNext"
     android:onClick="onClick"
      />

    </LinearLayout> 
    
</LinearLayout>


now in order to keep track of the index of the currently selected item we need to define two variables
//Variable to store the number of items in the gallery
 int ItemsInGallery=0;
 int CurrentIndex=0;

and the navigation buttons click handlers:
@Override
 public void onClick(View v) {
  // TODO Auto-generated method stub
  switch(v.getId())
  {
  case R.id.btnNext:
   //Increase the index
   CurrentIndex++;
   //if reached the end of the gallery, then start from the first item
   if(CurrentIndex>ItemsInGallery-1)
    CurrentIndex=0;
   gallery.setSelection(CurrentIndex,true);
   txt.setText(String.valueOf(CurrentIndex));
   break;
  case R.id.btnPrev:
   //Decrease the index
   CurrentIndex=CurrentIndex-1;
   //If reached the first item, then return to the last item in the gallery
   if(CurrentIndex<0)
    CurrentIndex=ItemsInGallery-1;
   gallery.setSelection(CurrentIndex,true);
   txt.setText(String.valueOf(CurrentIndex));
   break;
  }
 }
you can download a sample program from here

Reactions: 

How to rotate the Android Emulator ?

To rotate the Android Emulator, just disable the Num Lock key and and use the 7 and the 9 in the num pad to rotate the emulator and change its layout from portrait to landscape.

If you are working on a laptop you can do the same thing by pressing  Fn(Function)+7 or Fn+9.

Reactions: 

Android Intents: Part3: Intent Filters

Android components like activities can also serve implicit intents. but to do so they have to filter all implicit intents in order to serve only the intents they desire to serve. this is done using intent filters.

Suppose you want to create an activity that acts as the default dialer activity. You must associate an intent filter with this activity in order to that this activity serve the dial intents only.

Let's demonstrate a simple example which is creating an application with one activity that we want to make it a dialer activity.

Create a new android project, create an activity and name it Dialer.

In the AndroidManifest.xml file of this application add the following to the Dialer activity:
<intent-filter android:priority="100" >
            <action android:name="android.intent.action.DIAL"  />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="tel"/>
            </intent-filter>
to become:
<activity android:name=".Dialer"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter android:priority="100" >
            <action android:name="android.intent.action.DIAL"  />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:scheme="tel"/>
            </intent-filter>
        </activity>
Now what we have done is adding an intent filter to that activity. this intent filter has the following properties:
  1. Action: the type of implicit intents that this activity responds to. in our case it is the dial action. higher numbers represent higher priority.
  2. Priority: about the priority of that activity over other activities that respond to the same type of intents.
  3. Category: Implicit intents have built-in categories. in order that an implicit intent be captured by our activity, the implicit intent category must match our activity category.
  4. Data: adds data specification scheme to the intent filter.
So if any other application has the following module to launch the dialer:
Intent in=new Intent(Intent.ACTION_DIAL, Uri.parse("tel:000"));
     startActivity(in);
The user will see the following dialog offering him/her the choice between the default dialer and our custom dialer.

Reactions: 

Android Intents: Part 2: Passing data and returning results between activities

In a previous post we said that intents describe that an action to be performed. we saw how to launch phone activities like phone dialer with intents, and how we passed data (The phone number to dial) to the phone activity.
in this activity we're going to see how to use intents to launch several activities within the same application and how to pass data between them.

we will make an application with three activities: each activity has a button that when pressed navigates to the next activity in a round-robin fashion.
this is how each activity looks like:

each button will navigate to the next activity like this:
btn1.setOnClickListener(new OnClickListener() {
   
   public void onClick(View v) {
    // TODO Auto-generated method stub
   Intent intent=new Intent(IntentsDemo2.this,Activity2.class);
   startActivity(intent);
   }
  });

and the same for each button in the other activities.

we create the intent with a constructor that takes two parameters:
  1. Context: a reference to the current activity.
  2. Class: the type of the activity to be launched by the intent. 
Passing Results between Intents:

By default when you launch an activity using an intent you don't have a feedback on the whether the launched activity finished it's work or not.

we can launch an activity as a sub activity of a parent activity. this means that when the sub activity closes it triggers an event handler in the parent

consider the previous example, we want each activity to display the name of the  activity that was displayed before it.

so we launch the intent normally but we use the Intent.putExtra(String Name,String Value) method to pass any extra data needed.

in the first activity we launch the secondactivity like this:
Intent intent=new Intent(IntentsDemo2.this,Activity2.class);
   intent.putExtra("ComingFrom", "Acticity 1");
final int result=1;
   startActivityForResult(intent, result);

we did not use the startActivity method as we did before, instead we used startActivityForResult(Intent intent, int requestCode)
thich takes two parameters:
  1. The intent to start.
  2. Request code: which is an integer identifier that is used as a corelation id to identify which sub activity has finished it's work (will explain later) .
so the above code launches a sub activity and passes it an extra peice of information via Intent.putExtra method.

Receiving Extra data in sub activity
now the sub activity has been started with an intent from the parent with some extra data. to retreive this data in the sub activity we use the getIntent() method.

the getIntent() method returns a reference t the intent tha started the sub activity.
so in the sub activity we can call the method like this:
@Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main2);
         Intent sender=getIntent();
         String extraData=sender.getExtras().getString("ComingFrom");
}

this retreives the extra data added to the intent in the parent activity.

Handling sub activity results
now suppose that the parent activity wants to know what was the result returned from the sub activity or wants to get some data from the sub activity, this is handled by overriding the onActivityResult method in the parent activity.

now suppose that the sub activity wants to pass a string containg the word "Hello" to the parent activity.
in the sub activity there is a button that when pressed returns to the parent activity.
the button's click event handler can be like this
btn.setOnClickListener(new OnClickListener() {
    
    public void onClick(View v) {
     // TODO Auto-generated method stub
    Intent intent=new Intent();   
    intent.putExtra("ComingFrom", "Hello");
    setResult(RESULT_OK, intent);
    finish();
        }

here we used the intent.putExtra method to pass the extra data.

we also used the setResult(int result,Intent intent) method to set a result code to be sent to the caller parent activity.
the result code often has two predefined values Result_OK or Result_CANCELED. you can define any result value you want.

also we called finish() method that closes the activity and returrns to the caller activity.

when the finish() method is invoked in the sub activity, the onActivityResult callback method is invoked in the caller activity.

so when overriding the onActivityResult method in the caller activity we can get the data passed from the sub activity.

@Override
    public void onActivityResult(int requestCode,int resultCode,Intent data)
    {
     super.onActivityResult(requestCode, resultCode, data);
     
     String extraData=data.getStringExtra("ComingFrom"));
    }

so this was how intents can be used to pass data and return results between several activities within the same applications.
H9GYCEXU8DZF

Reactions: