Android Tutorial - Core Class : Contact

 Contact Intent and Options Menu

  

package app.test;

import java.io.File;
import java.util.ArrayList;

import android.app.Activity;
import android.app.SearchManager;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.provider.Contacts;
import android.view.Menu;

public class Test extends Activity {

    private Intent browserIntent, phoneIntent, mapIntent, mailIntent, contactIntent, marketIntent, smsIntent;
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        contactIntent = new Intent();
        contactIntent.setAction(Intent.ACTION_PICK);
        contactIntent.setData(Contacts.People.CONTENT_URI);
        
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add("Browser").setIntent(browserIntent);
        menu.add("Phone").setIntent(phoneIntent);
        menu.add("Map").setIntent(mapIntent);
        menu.add("Mail").setIntent(Intent.createChooser(mailIntent, "Mail Client"));
        menu.add("SMS").setIntent(smsIntent);
        menu.add("Contacts").setIntent(contactIntent);
        menu.add("Market").setIntent(marketIntent);
        return true;
    }
}

Using Contact

  


package app.test;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.view.View;
import android.widget.AdapterView;
import android.widget.SimpleCursorAdapter;

public class Test extends ListActivity implements AdapterView.OnItemClickListener {
    Cursor mContacts;
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String[] projection = new String[] { ContactsContract.Contacts._ID,ContactsContract.Contacts.DISPLAY_NAME };
        mContacts = managedQuery(ContactsContract.Contacts.CONTENT_URI,projection, null, null, ContactsContract.Contacts.DISPLAY_NAME);
        SimpleCursorAdapter mAdapter = new SimpleCursorAdapter(this,
                android.R.layout.simple_list_item_1, mContacts,
                new String[] { ContactsContract.Contacts.DISPLAY_NAME },
                new int[] { android.R.id.text1 });
        setListAdapter(mAdapter);
        getListView().setOnItemClickListener(this);
    }
    @Override
    public void onItemClick(AdapterView<?> parent, View v, int position, long id) {
        if (mContacts.moveToPosition(position)) {
            int selectedId = mContacts.getInt(0); 
            Cursor email = getContentResolver().query(
                    ContactsContract.CommonDataKinds.Email.CONTENT_URI,
                    new String[] { ContactsContract.CommonDataKinds.Email.DATA },
                    ContactsContract.Data.CONTACT_ID + " = " + selectedId, null, null);
            Cursor phone = getContentResolver().query(
                    ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                    new String[] { ContactsContract.CommonDataKinds.Phone.NUMBER },
                    ContactsContract.Data.CONTACT_ID + " = " + selectedId, null, null);
            Cursor address = getContentResolver().query(
                    ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_URI,
                    new String[] { ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS },
                    ContactsContract.Data.CONTACT_ID + " = " + selectedId, null, null);

            StringBuilder sb = new StringBuilder();
            sb.append(email.getCount() + " Emails\n");
            if (email.moveToFirst()) {
                do {
                    sb.append("Email: " + email.getString(0));
                } while (email.moveToNext());
            }
            sb.append(phone.getCount() + " Phone Numbers\n");
            if (phone.moveToFirst()) {
                do {
                    sb.append("Phone: " + phone.getString(0));
                } while (phone.moveToNext());
            }
            sb.append(address.getCount() + " Addresses\n");
            if (address.moveToFirst()) {
                do {
                    sb.append("Address:\n" + address.getString(0));
                } while (address.moveToNext());
            }

            AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle(mContacts.getString(1)); 
            builder.setMessage(sb.toString());
            builder.setPositiveButton("OK", null);
            builder.create().show();
            
            email.close();
            phone.close();
            address.close();
        }
    }
}

Contact Intent

package com.commonsware.android.rotation.five;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.Contacts;
import android.view.View;
import android.widget.Button;
import android.util.Log;

public class RotationFiveDemo extends Activity {
  static final int PICK_REQUEST=1337;
  Button viewButton=null;
  Uri contact=null;
  
  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    
    Button btn=(Button)findViewById(R.id.pick);
    
    btn.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
        Intent i=new Intent(Intent.ACTION_PICK,
                            Contacts.CONTENT_URI);

        startActivityForResult(i, PICK_REQUEST);
      }
    });
    
    viewButton=(Button)findViewById(R.id.view);
    
    viewButton.setOnClickListener(new View.OnClickListener() {
      public void onClick(View view) {
        startActivity(new Intent(Intent.ACTION_VIEW, contact));
      }
    });
    
    restoreMe();
    
    viewButton.setEnabled(contact!=null);
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode,
                                    Intent data) {
    if (requestCode==PICK_REQUEST) {
      if (resultCode==RESULT_OK) {
        contact=data.getData();
        viewButton.setEnabled(true);
      }
    }
  }

  @Override
  public Object onRetainNonConfigurationInstance() {
    return(contact);
  }
  
  private void restoreMe() {
    contact=null;
    
    if (getLastNonConfigurationInstance()!=null) {
      contact=(Uri)getLastNonConfigurationInstance();
    }
  }
}


//res\layout\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"
  >
  <Button android:id="@+id/pick"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:layout_weight="1"
    android:text="Pick"
    android:enabled="true"
  />
  <Button android:id="@+id/view"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:layout_weight="1"
    android:text="View"
    android:enabled="false"
  />
</LinearLayout>



//res\layout-land\main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:orientation="horizontal"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  >
  <Button android:id="@+id/pick"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:layout_weight="1"
    android:text="Pick"
    android:enabled="true"
  />
  <Button android:id="@+id/view"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:layout_weight="1"
    android:text="View"
    android:enabled="false"
  />
</LinearLayout>

Manage Contacts

  

package app.test;

import android.app.ListActivity;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.util.Log;
import android.widget.SimpleCursorAdapter;

public class Test extends ListActivity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        //Uri allContacts = Uri.parse("content://contacts/people");
        //Uri allContacts = Uri.parse("content://contacts/people/1");        
        Uri allContacts = ContactsContract.Contacts.CONTENT_URI;
        //Uri allContacts = ContentUris.withAppendedId(ContactsContract.Contacts.CONTENT_URI, 1);
        String[] projection = new String[] 
            {ContactsContract.Contacts._ID, 
             ContactsContract.Contacts.DISPLAY_NAME,
             ContactsContract.Contacts.HAS_PHONE_NUMBER};
        
        Cursor c = managedQuery(
            allContacts, 
            projection, 
            ContactsContract.Contacts.DISPLAY_NAME + " LIKE ?", 
            new String[] {"%"} , 
            ContactsContract.Contacts.DISPLAY_NAME + " ASC");
        
        
        String[] columns = new String[] {ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME,};
        int[] views = new int[] {R.id.contactName, R.id.contactID};
        
        SimpleCursorAdapter adapter = 
            new SimpleCursorAdapter(this, R.layout.main, c, columns, views);
        this.setListAdapter(adapter);
        
        PrintContacts(c);  
    }    
    
    private void PrintContacts(Cursor c)
    {
        if (c.moveToFirst()) {
            do{
              String contactID = c.getString(c.getColumnIndex(ContactsContract.Contacts._ID));
              String contactDisplayName = c.getString(c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));  
                Log.v("Content Providers", contactID + ", " + contactDisplayName);
                int hasPhone = c.getInt(c.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
                if (hasPhone == 1) {
                    Cursor phoneCursor = getContentResolver().query(
                      ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, 
                      ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactID, null, null);                     
                    while (phoneCursor.moveToNext()) {
                      Log.v("Content Providers",
                            phoneCursor.getString(phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));                  
                    } 
                    phoneCursor.close();
                }
            } while (c.moveToNext());
        }
    }
}


//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"
    >
    <ListView 
        android:id="@+id/android:list" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:layout_weight="1" 
        android:stackFromBottom="false" 
        android:transcriptMode="normal" 
        /> 
    <TextView   
        android:id="@+id/contactName"
        android:textStyle="bold"   
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content" 
        /> 
    <TextView   
        android:id="@+id/contactID" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
       />   

</LinearLayout>

List Contact phones

  
package app.test;

import android.app.ListActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.Contacts.Phones;
import android.widget.ListAdapter;
import android.widget.SimpleCursorAdapter;

public class Test extends ListActivity {
    
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Cursor c = getContentResolver().query(Phones.CONTENT_URI, null, null, null, null);
        startManagingCursor(c); 
        ListAdapter adapter = new SimpleCursorAdapter(this,
                android.R.layout.simple_list_item_2, c, 
                        new String[] { Phones.NAME, Phones.NUMBER }, 
                        new int[] { android.R.id.text1, android.R.id.text2 });
        setListAdapter(adapter);
    }
    
}


//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_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/hello"
    />
</LinearLayout>

Contact list demo

  

package app.test;

import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Contacts.People;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

public class Test extends Activity {
  public static final int PICK_CONTACT = 1;
  @Override
  public void onCreate(Bundle icicle) {
    super.onCreate(icicle);
    setContentView(R.layout.main);
  
    Button button = (Button)findViewById(R.id.pick_contact_button);
    button.setOnClickListener(new OnClickListener() {
      public void onClick(View _view) {
        Intent intent = new Intent(Intent.ACTION_PICK, Uri.parse("content://contacts/"));
        startActivityForResult(intent, PICK_CONTACT);  
      }     
    });
  }
  
  @Override 
  public void onActivityResult(int reqCode, int resCode, Intent data) {
    super.onActivityResult(reqCode, resCode, data);
    
    switch(reqCode) {
      case (PICK_CONTACT) : {
        if (resCode == Activity.RESULT_OK) {
          Cursor c = managedQuery(data.getData(), null, null, null, null);
          c.moveToFirst();
          String name = c.getString(c.getColumnIndexOrThrow(People.NAME));
          TextView tv = (TextView)findViewById(R.id.selected_contact_textview);
          tv.setText(name);
        }
        break;
      }
    }
    
  }

}

//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:id="@+id/selected_contact_textview"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
  />
  <Button
    android:id="@+id/pick_contact_button"
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content"
    android:text="Pick Contact"
  />
</LinearLayout>

Contact Manager

package com.example.android.contactmanager;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorDescription;
import android.accounts.OnAccountsUpdateListener;
import android.app.Activity;
import android.content.ContentProviderOperation;
import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemSelectedListener;

import java.util.ArrayList;
import java.util.Iterator;

public final class ContactAdder extends Activity implements OnAccountsUpdateListener
{
    public static final String TAG = "ContactsAdder";
    public static final String ACCOUNT_NAME =
            "com.example.android.contactmanager.ContactsAdder.ACCOUNT_NAME";
    public static final String ACCOUNT_TYPE =
            "com.example.android.contactmanager.ContactsAdder.ACCOUNT_TYPE";

    private ArrayList<AccountData> mAccounts;
    private AccountAdapter mAccountAdapter;
    private Spinner mAccountSpinner;
    private EditText mContactEmailEditText;
    private ArrayList<Integer> mContactEmailTypes;
    private Spinner mContactEmailTypeSpinner;
    private EditText mContactNameEditText;
    private EditText mContactPhoneEditText;
    private ArrayList<Integer> mContactPhoneTypes;
    private Spinner mContactPhoneTypeSpinner;
    private Button mContactSaveButton;
    private AccountData mSelectedAccount;

    /**
     * Called when the activity is first created. Responsible for initializing the UI.
     */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        Log.v(TAG, "Activity State: onCreate()");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.contact_adder);

        // Obtain handles to UI objects
        mAccountSpinner = (Spinner) findViewById(R.id.accountSpinner);
        mContactNameEditText = (EditText) findViewById(R.id.contactNameEditText);
        mContactPhoneEditText = (EditText) findViewById(R.id.contactPhoneEditText);
        mContactEmailEditText = (EditText) findViewById(R.id.contactEmailEditText);
        mContactPhoneTypeSpinner = (Spinner) findViewById(R.id.contactPhoneTypeSpinner);
        mContactEmailTypeSpinner = (Spinner) findViewById(R.id.contactEmailTypeSpinner);
        mContactSaveButton = (Button) findViewById(R.id.contactSaveButton);

        // Prepare list of supported account types
        // Note: Other types are available in ContactsContract.CommonDataKinds
        //       Also, be aware that type IDs differ between Phone and Email, and MUST be computed
        //       separately.
        mContactPhoneTypes = new ArrayList<Integer>();
        mContactPhoneTypes.add(ContactsContract.CommonDataKinds.Phone.TYPE_HOME);
        mContactPhoneTypes.add(ContactsContract.CommonDataKinds.Phone.TYPE_WORK);
        mContactPhoneTypes.add(ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
        mContactPhoneTypes.add(ContactsContract.CommonDataKinds.Phone.TYPE_OTHER);
        mContactEmailTypes = new ArrayList<Integer>();
        mContactEmailTypes.add(ContactsContract.CommonDataKinds.Email.TYPE_HOME);
        mContactEmailTypes.add(ContactsContract.CommonDataKinds.Email.TYPE_WORK);
        mContactEmailTypes.add(ContactsContract.CommonDataKinds.Email.TYPE_MOBILE);
        mContactEmailTypes.add(ContactsContract.CommonDataKinds.Email.TYPE_OTHER);

        // Prepare model for account spinner
        mAccounts = new ArrayList<AccountData>();
        mAccountAdapter = new AccountAdapter(this, mAccounts);
        mAccountSpinner.setAdapter(mAccountAdapter);

        // Populate list of account types for phone
        ArrayAdapter<String> adapter;
        adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        Iterator<Integer> iter;
        iter = mContactPhoneTypes.iterator();
        while (iter.hasNext()) {
            adapter.add(ContactsContract.CommonDataKinds.Phone.getTypeLabel(
                    this.getResources(),
                    iter.next(),
                    getString(R.string.undefinedTypeLabel)).toString());
        }
        mContactPhoneTypeSpinner.setAdapter(adapter);
        mContactPhoneTypeSpinner.setPrompt(getString(R.string.selectLabel));

        // Populate list of account types for email
        adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        iter = mContactEmailTypes.iterator();
        while (iter.hasNext()) {
            adapter.add(ContactsContract.CommonDataKinds.Email.getTypeLabel(
                    this.getResources(),
                    iter.next(),
                    getString(R.string.undefinedTypeLabel)).toString());
        }
        mContactEmailTypeSpinner.setAdapter(adapter);
        mContactEmailTypeSpinner.setPrompt(getString(R.string.selectLabel));

        // Prepare the system account manager. On registering the listener below, we also ask for
        // an initial callback to pre-populate the account list.
        AccountManager.get(this).addOnAccountsUpdatedListener(this, null, true);

        // Register handlers for UI elements
        mAccountSpinner.setOnItemSelectedListener(new OnItemSelectedListener() {
            public void onItemSelected(AdapterView<?> parent, View view, int position, long i) {
                updateAccountSelection();
            }

            public void onNothingSelected(AdapterView<?> parent) {
                // We don't need to worry about nothing being selected, since Spinners don't allow
                // this.
            }
        });
        mContactSaveButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                onSaveButtonClicked();
            }
        });
    }

    /**
     * Actions for when the Save button is clicked. Creates a contact entry and terminates the
     * activity.
     */
    private void onSaveButtonClicked() {
        Log.v(TAG, "Save button clicked");
        createContactEntry();
        finish();
    }

    /**
     * Creates a contact entry from the current UI values in the account named by mSelectedAccount.
     */
    protected void createContactEntry() {
        // Get values from UI
        String name = mContactNameEditText.getText().toString();
        String phone = mContactPhoneEditText.getText().toString();
        String email = mContactEmailEditText.getText().toString();
        int phoneType = mContactPhoneTypes.get(
                mContactPhoneTypeSpinner.getSelectedItemPosition());
        int emailType = mContactEmailTypes.get(
                mContactEmailTypeSpinner.getSelectedItemPosition());;

        // Prepare contact creation request
        //
        // Note: We use RawContacts because this data must be associated with a particular account.
        //       The system will aggregate this with any other data for this contact and create a
        //       coresponding entry in the ContactsContract.Contacts provider for us.
        ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
        ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
                .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, mSelectedAccount.getType())
                .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, mSelectedAccount.getName())
                .build());
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name)
                .build());
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, phone)
                .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, phoneType)
                .build());
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, 0)
                .withValue(ContactsContract.Data.MIMETYPE,
                        ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)
                .withValue(ContactsContract.CommonDataKinds.Email.DATA, email)
                .withValue(ContactsContract.CommonDataKinds.Email.TYPE, emailType)
                .build());

        // Ask the Contact provider to create a new contact
        Log.i(TAG,"Selected account: " + mSelectedAccount.getName() + " (" +
                mSelectedAccount.getType() + ")");
        Log.i(TAG,"Creating contact: " + name);
        try {
            getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (Exception e) {
            // Display warning
            Context ctx = getApplicationContext();
            CharSequence txt = getString(R.string.contactCreationFailure);
            int duration = Toast.LENGTH_SHORT;
            Toast toast = Toast.makeText(ctx, txt, duration);
            toast.show();

            // Log exception
            Log.e(TAG, "Exceptoin encoutered while inserting contact: " + e);
        }
    }

    /**
     * Called when this activity is about to be destroyed by the system.
     */
    @Override
    public void onDestroy() {
        // Remove AccountManager callback
        AccountManager.get(this).removeOnAccountsUpdatedListener(this);
        super.onDestroy();
    }

    /**
     * Updates account list spinner when the list of Accounts on the system changes. Satisfies
     * OnAccountsUpdateListener implementation.
     */
    public void onAccountsUpdated(Account[] a) {
        Log.i(TAG, "Account list update detected");
        // Clear out any old data to prevent duplicates
        mAccounts.clear();

        // Get account data from system
        AuthenticatorDescription[] accountTypes = AccountManager.get(this).getAuthenticatorTypes();

        // Populate tables
        for (int i = 0; i < a.length; i++) {
            // The user may have multiple accounts with the same name, so we need to construct a
            // meaningful display name for each.
            String systemAccountType = a[i].type;
            AuthenticatorDescription ad = getAuthenticatorDescription(systemAccountType,
                    accountTypes);
            AccountData data = new AccountData(a[i].name, ad);
            mAccounts.add(data);
        }

        // Update the account spinner
        mAccountAdapter.notifyDataSetChanged();
    }

    /**
     * Obtain the AuthenticatorDescription for a given account type.
     * @param type The account type to locate.
     * @param dictionary An array of AuthenticatorDescriptions, as returned by AccountManager.
     * @return The description for the specified account type.
     */
    private static AuthenticatorDescription getAuthenticatorDescription(String type,
            AuthenticatorDescription[] dictionary) {
        for (int i = 0; i < dictionary.length; i++) {
            if (dictionary[i].type.equals(type)) {
                return dictionary[i];
            }
        }
        // No match found
        throw new RuntimeException("Unable to find matching authenticator");
    }

    /**
     * Update account selection. If NO_ACCOUNT is selected, then we prohibit inserting new contacts.
     */
    private void updateAccountSelection() {
        // Read current account selection
        mSelectedAccount = (AccountData) mAccountSpinner.getSelectedItem();
    }

    /**
     * A container class used to repreresent all known information about an account.
     */
    private class AccountData {
        private String mName;
        private String mType;
        private CharSequence mTypeLabel;
        private Drawable mIcon;

        /**
         * @param name The name of the account. This is usually the user's email address or
         *        username.
         * @param description The description for this account. This will be dictated by the
         *        type of account returned, and can be obtained from the system AccountManager.
         */
        public AccountData(String name, AuthenticatorDescription description) {
            mName = name;
            if (description != null) {
                mType = description.type;

                // The type string is stored in a resource, so we need to convert it into something
                // human readable.
                String packageName = description.packageName;
                PackageManager pm = getPackageManager();

                if (description.labelId != 0) {
                    mTypeLabel = pm.getText(packageName, description.labelId, null);
                    if (mTypeLabel == null) {
                        throw new IllegalArgumentException("LabelID provided, but label not found");
                    }
                } else {
                    mTypeLabel = "";
                }

                if (description.iconId != 0) {
                    mIcon = pm.getDrawable(packageName, description.iconId, null);
                    if (mIcon == null) {
                        throw new IllegalArgumentException("IconID provided, but drawable not " +
                                "found");
                    }
                } else {
                    mIcon = getResources().getDrawable(android.R.drawable.sym_def_app_icon);
                }
            }
        }

        public String getName() {
            return mName;
        }

        public String getType() {
            return mType;
        }

        public CharSequence getTypeLabel() {
            return mTypeLabel;
        }

        public Drawable getIcon() {
            return mIcon;
        }

        public String toString() {
            return mName;
        }
    }

    /**
     * Custom adapter used to display account icons and descriptions in the account spinner.
     */
    private class AccountAdapter extends ArrayAdapter<AccountData> {
        public AccountAdapter(Context context, ArrayList<AccountData> accountData) {
            super(context, android.R.layout.simple_spinner_item, accountData);
            setDropDownViewResource(R.layout.account_entry);
        }

        public View getDropDownView(int position, View convertView, ViewGroup parent) {
            // Inflate a view template
            if (convertView == null) {
                LayoutInflater layoutInflater = getLayoutInflater();
                convertView = layoutInflater.inflate(R.layout.account_entry, parent, false);
            }
            TextView firstAccountLine = (TextView) convertView.findViewById(R.id.firstAccountLine);
            TextView secondAccountLine = (TextView) convertView.findViewById(R.id.secondAccountLine);
            ImageView accountIcon = (ImageView) convertView.findViewById(R.id.accountIcon);

            // Populate template
            AccountData data = getItem(position);
            firstAccountLine.setText(data.getName());
            secondAccountLine.setText(data.getTypeLabel());
            Drawable icon = data.getIcon();
            if (icon == null) {
                icon = getResources().getDrawable(android.R.drawable.ic_menu_search);
            }
            accountIcon.setImageDrawable(icon);
            return convertView;
        }
    }
}



//src\com\example\android\contactmanager\ContactManager.java


package com.example.android.contactmanager;

import android.app.Activity;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.CompoundButton.OnCheckedChangeListener;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;

public final class ContactManager extends Activity
{

    public static final String TAG = "ContactManager";

    private Button mAddAccountButton;
    private ListView mContactList;
    private boolean mShowInvisible;
    private CheckBox mShowInvisibleControl;

    /**
     * Called when the activity is first created. Responsible for initializing the UI.
     */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        Log.v(TAG, "Activity State: onCreate()");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.contact_manager);

        // Obtain handles to UI objects
        mAddAccountButton = (Button) findViewById(R.id.addContactButton);
        mContactList = (ListView) findViewById(R.id.contactList);
        mShowInvisibleControl = (CheckBox) findViewById(R.id.showInvisible);

        // Initialize class properties
        mShowInvisible = false;
        mShowInvisibleControl.setChecked(mShowInvisible);

        // Register handler for UI elements
        mAddAccountButton.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                Log.d(TAG, "mAddAccountButton clicked");
                launchContactAdder();
            }
        });
        mShowInvisibleControl.setOnCheckedChangeListener(new OnCheckedChangeListener() {
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                Log.d(TAG, "mShowInvisibleControl changed: " + isChecked);
                mShowInvisible = isChecked;
                populateContactList();
            }
        });

        // Populate the contact list
        populateContactList();
    }

    /**
     * Populate the contact list based on account currently selected in the account spinner.
     */
    private void populateContactList() {
        // Build adapter with contact entries
        Cursor cursor = getContacts();
        String[] fields = new String[] {
                ContactsContract.Data.DISPLAY_NAME
        };
        SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.contact_entry, cursor,
                fields, new int[] {R.id.contactEntryText});
        mContactList.setAdapter(adapter);
    }

    /**
     * Obtains the contact list for the currently selected account.
     *
     * @return A cursor for for accessing the contact list.
     */
    private Cursor getContacts()
    {
        // Run query
        Uri uri = ContactsContract.Contacts.CONTENT_URI;
        String[] projection = new String[] {
                ContactsContract.Contacts._ID,
                ContactsContract.Contacts.DISPLAY_NAME
        };
        String selection = ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" +
                (mShowInvisible ? "0" : "1") + "'";
        String[] selectionArgs = null;
        String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";

        return managedQuery(uri, projection, selection, selectionArgs, sortOrder);
    }

    /**
     * Launches the ContactAdder activity to add a new contact to the selected accont.
     */
    protected void launchContactAdder() {
        Intent i = new Intent(this, ContactAdder.class);
        startActivity(i);
    }
}



//res\layout\account_entry.xml
<?xml version="1.0" encoding="utf-8"?>


<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="?android:attr/listPreferredItemHeight"
    android:padding="6dip">
    <ImageView
        android:id="@+id/accountIcon"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"
        android:layout_alignParentBottom="true"
        android:layout_marginRight="6dip" />
    <TextView
        android:id="@+id/secondAccountLine"
        android:layout_width="match_parent"
        android:layout_height="26dip"
        android:layout_toRightOf="@id/accountIcon"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:singleLine="true"
        android:ellipsize="marquee"
        android:textColor="@android:color/secondary_text_light" />
    <TextView
        android:id="@+id/firstAccountLine"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/accountIcon"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_above="@id/secondAccountLine"
        android:layout_alignWithParentIfMissing="true"
        android:gravity="center_vertical"
        android:textColor="@android:color/primary_text_light"/>
</RelativeLayout>



//res\layout\contact_adder.xml
<?xml version="1.0" encoding="utf-8"?>


<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent">
    <TableLayout android:layout_width="match_parent"
                 android:layout_height="match_parent">
        <TableRow>
            <TextView android:layout_width="wrap_content"
                      android:layout_height="wrap_content"
                      android:text="@string/targetAccountLabel"/>
        </TableRow>
        <TableRow>
            <Spinner android:layout_height="wrap_content"
                     android:layout_width="match_parent"
                     android:layout_weight="1"
                     android:id="@+id/accountSpinner"/>
        </TableRow>
        <TableRow>
            <TextView android:layout_width="wrap_content"
                      android:layout_height="wrap_content"
                      android:text="@string/contactNameLabel"/>
        </TableRow>
        <TableRow>
            <EditText android:id="@+id/contactNameEditText"
                      android:layout_height="wrap_content"
                      android:layout_width="wrap_content"
                      android:layout_weight="1"/>
        </TableRow>
        <TableRow>
            <TextView android:text="@string/contactPhoneLabel"
                      android:layout_width="wrap_content"
                      android:layout_height="wrap_content"/>
        </TableRow>
        <TableRow>
            <EditText android:id="@+id/contactPhoneEditText"
                      android:layout_height="wrap_content"
                      android:layout_width="wrap_content"
                      android:layout_weight="1"/>
            <Spinner android:id="@+id/contactPhoneTypeSpinner"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"/>
        </TableRow>
        <TableRow>
            <TextView android:text="@string/contactEmailLabel"
                      android:layout_width="wrap_content"
                      android:layout_height="wrap_content"/>
        </TableRow>
        <TableRow>
            <EditText android:id="@+id/contactEmailEditText"
                      android:layout_height="wrap_content"
                      android:layout_width="wrap_content"
                      android:layout_weight="1"/>
            <Spinner android:id="@+id/contactEmailTypeSpinner"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"/>
        </TableRow>
        <TableRow>
            <Button android:layout_height="wrap_content"
                    android:text="@string/save"
                    android:id="@+id/contactSaveButton"
                    android:layout_width="match_parent"
                    android:layout_weight="1"/>
        </TableRow>
    </TableLayout>
</ScrollView>



//res\layout\contact_entry.xml
<?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">
    <TextView android:text="@+id/contactEntryText"
              android:id="@+id/contactEntryText"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"/>
</LinearLayout>



//res\layout\contact_manager.xml
<?xml version="1.0" encoding="utf-8"?>


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="vertical"
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    <ListView android:layout_width="match_parent"
              android:id="@+id/contactList"
              android:layout_height="wrap_content"
              android:layout_weight="1"/>
    <CheckBox android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:id="@+id/showInvisible"
              android:text="@string/showInvisible"/>
    <Button android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/addContactButton"
            android:text="@string/addContactButtonLabel"/>
</LinearLayout>


//res\values\strings.xml
<?xml version="1.0" encoding="utf-8"?>


<resources>
    <string name="accountSpinnerLabel">Account</string>
    <string name="addContactButtonLabel">Add Contact</string>
    <string name="addContactTitle">Add Contact</string>
    <string name="allAccounts">All Accounts</string>
    <string name="app_name">Contact Manager</string>
    <string name="contactCreationFailure">Contact creation failed, check logs.</string>
    <string name="contactEmailLabel">Contact Email</string>
    <string name="contactNameLabel">Contact Name</string>
    <string name="contactPhoneLabel">Contact Phone</string>
    <string name="save">Save</string>
    <string name="selectAccountLabel">Select</string>
    <string name="selectLabel">Select label</string>
    <string name="showInvisible">Show Invisible Contacts (Only)</string>
    <string name="targetAccountLabel">Target Account</string>
    <string name="undefinedTypeLabel">(Undefined)</string>
</resources>
Contacts Demo
package app.test;


import android.app.ListActivity;
import android.content.Context;
import android.database.CharArrayBuffer;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract.Contacts;
import android.view.View;
import android.view.ViewGroup;
import android.widget.QuickContactBadge;
import android.widget.ResourceCursorAdapter;
import android.widget.TextView;

public class Test extends ListActivity {
    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
            Contacts._ID, // 0
            Contacts.DISPLAY_NAME, // 1
            Contacts.STARRED, // 2
            Contacts.TIMES_CONTACTED, // 3
            Contacts.CONTACT_PRESENCE, // 4
            Contacts.PHOTO_ID, // 5
            Contacts.LOOKUP_KEY, // 6
            Contacts.HAS_PHONE_NUMBER, // 7
    };

    static final int SUMMARY_ID_COLUMN_INDEX = 0;
    static final int SUMMARY_NAME_COLUMN_INDEX = 1;
    static final int SUMMARY_STARRED_COLUMN_INDEX = 2;
    static final int SUMMARY_TIMES_CONTACTED_COLUMN_INDEX = 3;
    static final int SUMMARY_PRESENCE_STATUS_COLUMN_INDEX = 4;
    static final int SUMMARY_PHOTO_ID_COLUMN_INDEX = 5;
    static final int SUMMARY_LOOKUP_KEY = 6;
    static final int SUMMARY_HAS_PHONE_COLUMN_INDEX = 7;


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
                + Contacts.HAS_PHONE_NUMBER + "=1) AND ("
                + Contacts.DISPLAY_NAME + " != '' ))";
        Cursor c =
                getContentResolver().query(Contacts.CONTENT_URI, CONTACTS_SUMMARY_PROJECTION, select,
                null, Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
        startManagingCursor(c);
        ContactListItemAdapter adapter = new ContactListItemAdapter(this, R.layout.main, c);
        setListAdapter(adapter);

    }

    private final class ContactListItemAdapter extends ResourceCursorAdapter {
        public ContactListItemAdapter(Context context, int layout, Cursor c) {
            super(context, layout, c);
        }

        @Override
        public void bindView(View view, Context context, Cursor cursor) {
            final ContactListItemCache cache = (ContactListItemCache) view.getTag();
            // Set the name
            cursor.copyStringToBuffer(SUMMARY_NAME_COLUMN_INDEX, cache.nameBuffer);
            int size = cache.nameBuffer.sizeCopied;
            cache.nameView.setText(cache.nameBuffer.data, 0, size);
            final long contactId = cursor.getLong(SUMMARY_ID_COLUMN_INDEX);
            final String lookupKey = cursor.getString(SUMMARY_LOOKUP_KEY);
            cache.photoView.assignContactUri(Contacts.getLookupUri(contactId, lookupKey));
        }

        @Override
        public View newView(Context context, Cursor cursor, ViewGroup parent) {
            View view = super.newView(context, cursor, parent);
            ContactListItemCache cache = new ContactListItemCache();
            cache.nameView = (TextView) view.findViewById(R.id.name);
            cache.photoView = (QuickContactBadge) view.findViewById(R.id.badge);
            view.setTag(cache);

            return view;
        }
    }

    final static class ContactListItemCache {
        public TextView nameView;
        public QuickContactBadge photoView;
        public CharArrayBuffer nameBuffer = new CharArrayBuffer(128);
    }
}
//main.xml

<?xml version="1.0" encoding="utf-8"?>


<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:paddingLeft="0dip"
    android:paddingRight="9dip"
    android:layout_height= "wrap_content"
    android:minHeight="48dip">

    <QuickContactBadge
        android:id="@+id/badge"
        android:layout_marginLeft="2dip"
        android:layout_marginRight="14dip"
        android:layout_marginTop="4dip"
        android:layout_marginBottom="3dip"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:layout_height= "wrap_content"
        android:layout_width= "wrap_content"
        android:src="@drawable/icon"
        style="?android:attr/quickContactBadgeStyleWindowSmall" />

    <TextView
        android:id="@+id/name"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:paddingLeft="2dip"
        android:layout_centerVertical="true"
        android:layout_toRightOf="@id/badge"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

</RelativeLayout>
Demonstrates launching the contacts app to pick a contact.
package app.test;


import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.SystemClock;
import android.os.Bundle;
import android.provider.BaseColumns;
import android.provider.ContactsContract;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;

import java.util.Calendar;

public class PickContact extends Activity {
    Toast mToast;
    ResultDisplayer mPendingResult;

    class ResultDisplayer implements OnClickListener {
        String mMsg;
        String mMimeType;
        
        ResultDisplayer(String msg, String mimeType) {
            mMsg = msg;
            mMimeType = mimeType;
        }
        
        public void onClick(View v) {
            Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
            intent.setType(mMimeType);
            mPendingResult = this;
            startActivityForResult(intent, 1);
        }
    }
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        // Watch for button clicks.
        ((Button)findViewById(R.id.pick_contact)).setOnClickListener(
                new ResultDisplayer("Selected contact",
                        ContactsContract.Contacts.CONTENT_ITEM_TYPE));
        ((Button)findViewById(R.id.pick_person)).setOnClickListener(
                new ResultDisplayer("Selected person",
                        "vnd.android.cursor.item/person"));
        ((Button)findViewById(R.id.pick_phone)).setOnClickListener(
                new ResultDisplayer("Selected phone",
                        ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE));
        ((Button)findViewById(R.id.pick_address)).setOnClickListener(
                new ResultDisplayer("Selected address",
                        ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE));
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (data != null) {
            Uri uri = data.getData();
            if (uri != null) {
                Cursor c = null;
                try {
                    c = getContentResolver().query(uri, new String[] { BaseColumns._ID },
                            null, null, null);
                    if (c != null && c.moveToFirst()) {
                        int id = c.getInt(0);
                        if (mToast != null) {
                            mToast.cancel();
                        }
                        String txt = mPendingResult.mMsg + ":\n" + uri + "\nid: " + id;
                        mToast = Toast.makeText(this, txt, Toast.LENGTH_LONG);
                        mToast.show();
                    }
                } finally {
                    if (c != null) {
                        c.close();
                    }
                }
            }
        }
    }
}

//main.xml

<?xml version="1.0" encoding="utf-8"?>


<!-- Demonstrates selecting various types of contact data. -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:padding="4dip"
    android:gravity="center_horizontal"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <TextView
        android:layout_width="match_parent" android:layout_height="wrap_content"
        android:layout_weight="0"
        android:paddingBottom="4dip"
        android:text="pick_contact_msg"/>
        
    <Button android:id="@+id/pick_contact"
        android:layout_width="wrap_content" android:layout_height="wrap_content" 
        android:text="pick_contact">
        <requestFocus />
    </Button>

    <Button android:id="@+id/pick_person"
        android:layout_width="wrap_content" android:layout_height="wrap_content" 
        android:text="pick_person">
    </Button>

    <Button android:id="@+id/pick_phone"
        android:layout_width="wrap_content" android:layout_height="wrap_content" 
        android:text="pick_phone">
    </Button>

    <Button android:id="@+id/pick_address"
        android:layout_width="wrap_content" android:layout_height="wrap_content" 
        android:text="pick_address">
    </Button>
</LinearLayout>