Android Developers Blog: Preview of Google TV Add-on for the Android SDK

Android Developers Blog: Preview of Google TV Add-on for the Android SDK

Reactions: 

Official Google Blog: Supercharging Android: Google to Acquire Motorola Mobility

Official Google Blog: Supercharging Android: Google to Acquire Motorola Mobility

Reactions: 

Android Developing: Remove Auto focus from Edit Text

Android Developing: Remove Auto focus from Edit Text: "When start Android application, it always auto focus EditText box. Here we give explain how to remove auto focus from EditText. Add your..."

Reactions: 

Implementing Search activities

Most Android phones have a search button. this button is used to search contacts,applications or anything on the phone. We can make use of the search functionality in our apps.

In this post we're going to see how to implement search functionality to search for entries stored in a databaseand display them in a ListView.

Creating database:
our database has two tables: Countries and Names:
public class DBHelper extends SQLiteOpenHelper {

 public DBHelper(Context context) {
  super(context, "DemoDB", null, 1);
 }

 @Override
 public void onCreate(SQLiteDatabase db) {
  StringBuilder builder=new StringBuilder();
  // countries table
  builder.append("CREATE TABLE Countries ");
  builder.append("(_id INTEGER PRIMARY KEY AUTOINCREMENT,");
  builder.append("NAME TEXT) ");
  db.execSQL(builder.toString());
  // Names table
  // Virtual table for full text search
  builder.setLength(0);
  builder.append("CREATE VIRTUAL TABLE NAMES USING FTS3");
  builder.append("(");
  builder.append("name TEXT) ");  
  db.execSQL(builder.toString());
  builder=new StringBuilder();

  //dummy  data
  InsertData(db);

 }

  void InsertData(SQLiteDatabase db)
  {
   ContentValues cv=new ContentValues();
   cv.put("NAME","USA");
   db.insert("Countries", "NAME", cv);
   cv.put("NAME","UK");
   db.insert("Countries", "NAME", cv);
   cv.put("NAME","Spain");
   db.insert("Countries", "NAME", cv);
   cv.put("NAME","ITALY");
   db.insert("Countries", "NAME", cv);
   cv.put("NAME","Germany");
   db.insert("Countries", "NAME", cv);

    cv=new ContentValues();
    cv.put("name","John");
    db.insert("NAMES", "name", cv);
    cv.put("name","Jack");
    db.insert("NAMES", "name", cv);
    cv.put("name","Ann");
    db.insert("NAMES", "name", cv);
    cv.put("name","Adam");
    db.insert("NAMES", "name", cv);
    cv.put("name","Sarah");
    db.insert("NAMES", "name", cv);

  }

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

 }
}
notice that the Names table is a VIRTUAL table. we created it as virtual to make use of Full Text Search (FTS3) feature in SQLite. this feature makes queries faster than that in regular tables.
then we add two functions to retrieve all rows from both tables:
/**
  * Return all countries
  * @return
  */
 public ArrayListgetCountries(){
  ArrayList countries=new ArrayList();
  SQLiteDatabase db=this.getReadableDatabase();
  Cursor c=db.rawQuery("select * from Countries", null);
  while(c.moveToNext()){
   String country=c.getString(1);
   countries.add(country);
  }
  c.close();
  return countries;
 }
/**
  * Return all names
  * @return
  */

 public ArrayListgetNames(){
  ArrayList names=new ArrayList();
  Cursor c=this.getReadableDatabase().rawQuery("select * FROM Names", null);
  while(c.moveToNext()){
   String name=c.getString(0);
   names.add(name);
  }
  c.close();
  return names;
 }
and another two functions to retrieve data based on a search string:
/**
  * Return all countries based on a search string
  * @return
  */
 public ArrayListgetCountriesSearch(String query){
  ArrayList countries=new ArrayList();
  SQLiteDatabase db=this.getReadableDatabase();
  Cursor c=db.rawQuery("select * from Countries where NAME LIKE '%"+query+"%'", null);
  while(c.moveToNext()){
   String country=c.getString(1);
   countries.add(country);
  }
  c.close();
  return countries;
 }
/**
  * Return all names based on a search string
  * we use the MATCH keyword to make use of the full text search
  * @return
  */
 public ArrayListgetNamesSearch(String query){
  ArrayList names=new ArrayList();
  Cursor c=this.getReadableDatabase().rawQuery("select * FROM Names WHERE name MATCH '"+query+"'", null);
  while(c.moveToNext()){
   String name=c.getString(0);
   names.add(name);
  }
  c.close();
  return names;
 }

Implementing The activity:
then we will create our activity that has a list view 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"
    >
<ListView
android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/list"/>
</LinearLayout>

we load data from database like this:
public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        list=(ListView)findViewById(R.id.list);

            DBHelper helper=new DBHelper(this);
            ArrayList items=helper.getNames();
            ArrayAdapter adapter=new ArrayAdapter(this, android.R.layout.simple_list_item_1,items);
            list.setAdapter(adapter);
}

Handling the search dialog:
In order to handle the search dialog ourselves we need to create a xml file with search configurations such as the search dialog title, voice search capabilities, content provider for auto complete and so on. we create a file with the name searchable.xml in res/xmldirectory:
<?xml version="1.0" encoding="utf-8"?>
<searchable xmlns:android="http://schemas.android.com/apk/res/android"
    android:label="@string/app_name"
    android:hint="@string/hint"  >
</searchable>
the android:hint attribute denotes a string that acts as a water mark on the search text box.
then we need to add an Intent Filter in out app's AndroidManifest.xml file to our activity to handle the search dialog:
<activity android:name=".MainActivty"
                  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>
            <action android:name="android.intent.action.SEARCH" />
        </intent-filter>
        <meta-data android:name="android.app.searchable"
                   android:resource="@xml/searchable"/>
        </activity>

Understanding the Search process:

when you press the search button, type some text and click on search the activit's onSearchRequested() function is called, then an Intent with the action Intent.ACTION_SEARCH is created and you activity is re-created with this intent.

the search intent has you search string as a string extra with the name SearchManager.QUERY. also it can carry a bundle of other extras with the name SearchManager.APP_DATA.

what if the device doesn't have a Search button:
not all Android devices have a search button, so we can start the search dialog manually by calling the activity's onSearchRequested() from a button or a menu item:
@Override
     public boolean onCreateOptionsMenu(Menu menu) {
     menu.add("Search").setOnMenuItemClickListener(new OnMenuItemClickListener() {

   @Override
   public boolean onMenuItemClick(MenuItem item) {
                                //launch the search dialog
    onSearchRequested();
    return true;
   }
  });
     return true;
    }

Adding extras to the search dialog:
we can pass some extra data as a bundle with our search dialog or an initial search string by overriding the activity's onSearchRequested():
@Override
    public boolean onSearchRequested() {
     Bundle bundle=new Bundle();
  bundle.putString("extra", "exttra info");
  // search initial query
  startSearch("Country", false, bundle, false);
  return true;
    }

Handling the search query:

we said before that the search query is passed as a String extra when our activity is re-created. so we can handle the searcgh string in our onCreate() like this:
@Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        list=(ListView)findViewById(R.id.list);

        DBHelper helper=new DBHelper(this);
        Intent intent=getIntent();
        // if the activity is created from search
         if(intent.getAction().equals(Intent.ACTION_SEARCH)){
          // get search query
          String query=intent.getStringExtra(SearchManager.QUERY);
          ArrayList items=helper.getNamesSearch(query);
          //get extras, just for demonstration
          Bundle bundle=intent.getBundleExtra(SearchManager.APP_DATA);
             String info=bundle.getString("extra");
          Log.v("extra", info);
          //bind the list
                ArrayAdapter adapter=new ArrayAdapter(this, android.R.layout.simple_list_item_1,items);
                list.setAdapter(adapter);
         }
        //activity created normally
        else{
         ArrayList items=helper.getNames();
            ArrayAdapter adapter=new ArrayAdapter(this, android.R.layout.simple_list_item_1,items);
            list.setAdapter(adapter);
        }
        helper.close();
    }


we just extract the search string and any other extras and perform our search logic based on the search string.
and that's was all about implementing search

Reactions: 

In this post we will see how can a client application call the methods of a service defined in another application. this is achieved through Android Interface Definition Language (AIDL).

AIDL is a java like language that enables you to define an interface that both the application defining the service and the client application implement it.

the interface defines the functions that are needed to be called in the client application.

Defining the AIDL file:
AIDL syntax is similar to that of Java, we can use the following data types in AIDL:
  1. primitive data types: int, long, char, boolean,....
  2. String.
  3. CharSequence.
  4. List (ArrayList,Vector,...).

  1. the AIDL file is defined as follows:
    open a notepad file and paste the following code in it:
    package com.mina.servicedemo;
    
    // service interface
    interface IRemoteService {
        //sample method
        String sayHello(String message);
    }
    take care of the package name com.mina.servicedemo.
    we defined a methods sayHello(String message) that returns a string.
  2. save the file with the name IRemoteService and change it's extension to .aidl.
  3. copy the file to the src folder of your project.
  4. once you save and build the file, Android generates an interface java file with the name IRemoteService.java in the gen folder if the project.

Defining the Service:
now we want our service to expose this interface to client applications, so we return an implementation of the service in the onBind() method of our service:
package com.mina.servicedemo;

import com.mina.servicedemo.IRemoteService.Stub;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.widget.Toast;

public class DemoService extends Service {

 @Override
 public IBinder onBind(Intent arg0) {
  return mBinder;
 }

 // implementation of the aidl interface
 private final IRemoteService.Stub mBinder=new Stub() {

  @Override
  public String sayHello(String message) throws RemoteException {
   return "Hello "+message;

  }
 };

 }
}
the last thing to do in the service is to make its exported attribute in the AndroidManifest.xml file set to true like this:
<service android:name="DemoService" android:exported="true"></service>
our app structure can be like this:

Consuming the service at the client application:
now to our client application where we want to invoke methods from our service. the client application is a separate application with a different package name than that where the service is defined.

the client application needs a reference to the AIDL interface defined in the original applcation, this is done through the following steps:
  1. in the client applicatio create a package with the same package name of that the service is defined in: com.mina.servicedemo.
  2. copy the AIDL file in this package.
  3. save and build and a new file called IRemoteService.java is generated. your app structure should be like this:
and we invoke the servcice methods in our activity like this:
package com.mina.serviceclient;

import com.mina.servicedemo.IRemoteService;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class MainActivity extends Activity {

 IRemoteService mRemoteService;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Intent serviceIntent=new Intent();
        serviceIntent.setClassName("com.mina.servicedemo", "com.mina.servicedemo.DemoService");
        boolean ok=bindService(serviceIntent, mServiceConnection,Context.BIND_AUTO_CREATE);
        Log.v("ok", String.valueOf(ok));
    }

    private ServiceConnection mServiceConnection=new ServiceConnection() {

  @Override
  public void onServiceDisconnected(ComponentName name) {
   // TODO Auto-generated method stub

  }

  @Override
  public void onServiceConnected(ComponentName name, IBinder service) {
   // get instance of the aidl binder
   mRemoteService = IRemoteService.Stub.asInterface(service);
   try {
    String message=mRemoteService.sayHello("Mina");
    Log.v("message", message);
   } catch (RemoteException e) {
    Log.e("RemoteException", e.toString());
   }

  }
 };
}
and that's was all about calling remote services with AIDL.

Reactions: 

Official Google Blog: When patents attack Android

Official Google Blog: When patents attack Android

Reactions: