QuickContact & ContactsContract

久しぶりの投稿です。今回は軽くQuickContactを使ってみたいと思います。QuickContactを表示するのは1行で出来てしまうのですが、必要とするContactのDataを取得するのに苦しめられましたので備忘録として書いておきたいと思います

QuickContactとは

こんな感じのものです。Widgetから起動したりすると便利です


実装の要点は下記です

  1. Manifest xmlにContactを読むためのpermissionを記載
  2. Contact._IDとContact.LOOKUP_KEYを取得
  3. ContactsContract.Contacts.getLookupUri()の引数にContact._IDとContact.LOOKUP_KEYを渡しlookUpUriを取得
  4. ContactsContract.QuickContact.showQuickContact()でQuickContactを表示
    • 第2引数にQuickContactのbubbleの先を表示するView(or Widgetの場合はViewのRect)を指定
    • 第3引数にlookupUriを指定

気づいた点をまとめます

  • ContactsContract.Contact._IDと同一なのはContactsContract.Data.CONTACT_ID。ContactsContract.Data._IDとは違う

んで実装

  • Manifest xml一部
    <!-- Manifest xmlにContactを読むためのpermissionを記載 -->
    <uses-permission android:name="android.permission.READ_CONTACTS"/>
  • Activity
package com.android.practice;

import android.app.ListActivity;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
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.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;

public class ContactListActivity extends ListActivity{
	
	private static final String TAG = "ContactListActivity";

	private BaseAdapter mAdapter;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
	}
	
	@Override
	protected void onStart() {
		super.onStart();
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		mAdapter = new MyContactsAdapter(this);
		setListAdapter(mAdapter);
		ListView listView = getListView();
		listView.setOnItemClickListener(new OnItemClickListener(){
			public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
				//lookUpUriを取得する
				Uri lookupUri = ((MyContactsAdapter)mAdapter).getLookupUri(position);
				//ContactsContract.QuickContact.showQuickContact()でQuickContactを表示
				//第2引数にQuickContactのbubbleの先を表示するView(or Widgetの場合はViewのRect)を指定
				//第3引数にlookupUriを指定
				ContactsContract.QuickContact.showQuickContact(getApplicationContext(), view, lookupUri, ContactsContract.QuickContact.MODE_LARGE, null);
			}
		});
	}

	@Override
	protected void onPause() {
		super.onPause();
		((MyContactsAdapter)mAdapter).finish();
	}

	@Override
	protected void onStop() {
		// TODO Auto-generated method stub
		super.onStop();
	}

	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
	}
	
	public static class MyContactsAdapter extends BaseAdapter{
		
		private static final String NO_NAME = "No name set";
		private static final String NO_NUMBER = "No number set";
		
		private Context mContext;
		private Cursor mCursor;
		
		public MyContactsAdapter(Context context){
			mContext = context;
			//Contact情報を取得するためにContacts._IDを取得
			//lookUpUriを取得するためにContacts.LOOKUP_KEYをcolumnを取得
			mCursor = mContext.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, 
					new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.LOOKUP_KEY}, null, null, null);
		}
		
		public Uri getLookupUri(int position){
			Uri result = null;
			if(mCursor.moveToPosition(position)){
				//Contact._IDとContact.LOOKUP_KEYを取得
				long id = mCursor.getLong(mCursor.getColumnIndex(ContactsContract.Contacts._ID));
				String lookUpKey = mCursor.getString(mCursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
				//ContactsContract.Contacts.getLookupUri()の引数にContact._IDとContact.LOOKUP_KEYを渡しlookUpUriを取得
				result = ContactsContract.Contacts.getLookupUri(id, lookUpKey);

			}
			return result;
		}

		public int getCount() {
			Log.d(TAG, "Count: " + mCursor.getCount());
			return mCursor.getCount();
		}

		public Object getItem(int position) {
			return getContactInfo(position);
		}

		public long getItemId(int position) {
			return position;
		}

		public View getView(int position, View convertView, ViewGroup parent) {
			View view = null;
			ViewHolder holder = null;
			if(convertView == null){
				view = ((LayoutInflater)mContext.getSystemService(LAYOUT_INFLATER_SERVICE)).inflate(R.layout.contact_row, null);
				holder = new ViewHolder();
				holder.mPhoto = (ImageView)view.findViewById(R.id.photo);
				holder.mDisplayName = (TextView)view.findViewById(R.id.display_name);
				holder.mNumber = (TextView)view.findViewById(R.id.number);
				view.setTag(holder);
			}else{
				view = convertView;
				holder = (ViewHolder)view.getTag();
			}
			
			ContactInfo info = getContactInfo(position);
			holder.mPhoto.setImageBitmap(info.mPhoto);
			holder.mDisplayName.setText(info.mDisplayName);
			holder.mNumber.setText(info.mNumber);
			
			return view;
		}
		
		public void finish(){
			if(mCursor != null){
				//Cursor objectをclose。必ずcloseする必要がある
				mCursor.close();
			}
		}
		
		private ContactInfo getContactInfo(int position){
			ContactInfo result = null;
			if(mCursor.moveToPosition(position)){
				long id = mCursor.getLong(mCursor.getColumnIndex(ContactsContract.Contacts._ID));
				result = new ContactInfo();
				//Contact._IDをもとにPhotoを取得
				result.mPhoto = getContactPhoto(id);
				//Contact._IDをもとにDisplay nameを取得
				result.mDisplayName = getDisplayName(id);
				//Contact._IDをもとにPhone numberを取得
				result.mNumber = getNumber(id);
				Log.d(TAG, "getContactInfo: mDisplayName: " + result.mDisplayName + " mNumber: " + result.mNumber);
			}
			return result;
		}
		
		private Bitmap getContactPhoto(long id){
			Bitmap result = null;
			Cursor cursor = null;
			try{
				//Contact._IDと同一なのはContactsContract.Data.CONTACT_ID。ContactsContract.Data._IDとは違う
				cursor = mContext.getContentResolver().query(ContactsContract.Data.CONTENT_URI, 
						new String[]{ContactsContract.CommonDataKinds.Photo.PHOTO}, 
						"ContactsContract.Data.CONTACT_ID = ?", new String[]{String.valueOf(id)}, null);
				
				if(cursor != null && cursor.getCount() != 0 && cursor.moveToFirst()){
					Log.d(TAG, "getContactPhoto: count: " + cursor.getCount() + " id: " + id);
					//Photoのdataを取得
					byte[] data = cursor.getBlob(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Photo.PHOTO));
					if(data != null){
						//byte arrayからbitmapを作成
						result = BitmapFactory.decodeByteArray(data, 0, data.length, null);
					}
				}

				if(result == null){
					result = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.icon);
				}
			}finally{
				if(cursor != null){
					cursor.close();
				}
			}
			return result;
		}
		
		private String getDisplayName(long id){
			String result = null;
			Cursor cursor = null;
			try{
				//ContactsContract.Contact._IDと同一なのはContactsContract.Data.CONTACT_ID。ContactsContract.Data._IDとは違う				
				cursor = mContext.getContentResolver().query(ContactsContract.Data.CONTENT_URI, 
						new String[]{ContactsContract.Data.DISPLAY_NAME}, 
						"ContactsContract.Data.CONTACT_ID = ?", new String[]{String.valueOf(id)}, null);
				if(cursor != null && cursor.getCount() != 0 && cursor.moveToFirst()){
					Log.d(TAG, "getDisplayName: count: " + cursor.getCount() + " id: " + id);
					result = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME));
				}
				if(result == null){
					result = NO_NAME;
				}
			}finally{
				if(cursor != null){
					cursor.close();
				}
			}
			return result;
		}
		
		private String getNumber(long id){
			String result = null;
			Cursor cursor = null;
			try{
				//ContactsContract.Contact._IDと同一なのはContactsContract.Data.CONTACT_ID。ContactsContract.Data._IDとは違う
				cursor = mContext.getContentResolver().query(ContactsContract.Data.CONTENT_URI, 
						new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER}, 
						"ContactsContract.Data.CONTACT_ID = ?", new String[]{String.valueOf(id)}, null);
				if(cursor != null && cursor.getCount() != 0 && cursor.moveToFirst()){
					Log.d(TAG, "getNumber count: " + cursor.getCount() + " id: " + id);
					result = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
				}
				if(result == null){
					result = NO_NUMBER;
				}
			}finally{
				if(cursor != null){
					cursor.close();
				}
			}
			return result;
		}
	}
	
	public static class ViewHolder{
		public ImageView mPhoto;
		public TextView mDisplayName;
		public TextView mNumber;
	}
	
	public static class ContactInfo{
		public Bitmap mPhoto;
		public String mDisplayName;
		public String mNumber;
	}
}

下記に参考にしたsiteをリンクしておきます。

ContactsContract.QuickContact
ContactsContract
ContactsContract.Data
ContactsContract.PhoneLookup

  • Other

stackoverflow-widgetでQuickContactを表示する方法
Working with Android Contacts