Quantcast
Channel: TechieDreams
Viewing all articles
Browse latest Browse all 21

Android custom contacts picker with images, filtering & indexed scrolling.

$
0
0

This custom contact picker allows you to pick one or more contacts so that you can use them of any purposes like sending a mail, using their email Id’s or phone numbers etc.

Her am going to use a custom listview to load all the contacts form the Phone and the each item is provided with a check box to select.

Please go through the Custom list view post if you don’t know how to create. – http://techiedreams.com/android-simple-custom-list-views-with-examples/

The next we need to know is hoe to fetch the contacts from the Phone:

1. All the contacts in the phone are stored in data base organized by their types. We need to find our required URI to query through and get the desired results. One we have the URI we can query on that using content resolver we need to specify the required columns that need to loaded before querying which helps speeding up the query time.

Here is our cursor from which we will extracts all the contacts information:

Cursor cur = getContentResolver().query(Data.CONTENT_URI, new String[] { Data.CONTACT_ID, Data.MIMETYPE, Email.ADDRESS,
Contacts.DISPLAY_NAME, Phone.NUMBER }, null, null, Contacts.DISPLAY_NAME);

 

This is the out put we will get:
contcats_picker_all

First create a Simple POJO for Contact and it should implement Parcelable – Contact.java:

public class Contact implements Parcelable {

private String contactName;
private String contactNumber;
private Bitmap contactPhoto;
private Uri contactPhotoUri;
private String contactEmail;

boolean selected = false;

public Contact() {
;
}

public String getContactName() {
return contactName;
}

public String getContactNumber() {
return contactNumber;
}

public Bitmap getContactPhoto() {
return contactPhoto;
}

public Uri getContactPhotoUri() {
return contactPhotoUri;
}

public void setContactName(String contactName) {
this.contactName = contactName;
}

public void setContactNumber(String contactNumber) {
this.contactNumber = contactNumber;
}

public void setContactPhoto(Bitmap contactPhoto) {
this.contactPhoto = contactPhoto;

}

public void setContactPhotoUri(Uri contactPhotoUri) {
this.contactPhotoUri = contactPhotoUri;
}

public String getContactEmail() {
return contactEmail;
}

public void setContactEmail(String contactEmail) {
this.contactEmail = contactEmail;
}

public boolean isSelected() {
return selected;
}

public void setSelected(boolean selected) {
this.selected = selected;
}

@Override
public int describeContents() {
return 0;
}

@Override
public String toString() {
return contactName + " " + contactNumber + " ";
}

@Override
public void writeToParcel(Parcel dest, int flags) {

dest.writeString(contactName);
dest.writeString(contactNumber);
dest.writeString(contactPhotoUri.toString());
dest.writeString(contactEmail);

}

public Contact(Parcel source) {

contactName = source.readString();
contactNumber = source.readString();
contactPhotoUri = Uri.parse(source.readString());
contactEmail = source.readString();
}

public static final Parcelable.Creator<Contact> CREATOR = new Parcelable.Creator<Contact>() {

@Override
public Contact createFromParcel(Parcel source) {
return new Contact(source);
}

@Override
public Contact[] newArray(int size) {
return new Contact[size];
}

};

}

 

Next add these permissions and activity to your manifest. The final manifest file will look like this:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.td.contactpicker"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />

<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />

<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.td.contactpicker.ContactManager"
android:configChanges="orientation|screenSize"
android:label="@string/app_name"
android:screenOrientation="portrait"
android:theme="@style/AppTheme" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>

 

Now we have to create the main contact picker class. Lets name it as ‘ContactManager.java’. Here the final class will look like. It is self explained through comments:

public final class ContactManager extends Activity {

private static ArrayList<Contact> contacts = null;
private LinkedHashMap<String, Contact> allContacts = new LinkedHashMap<String, Contact>();
private ContactAdapter contactAdapter = null;
private ListView lv;
ImageView doneSelect;
RelativeLayout progressLayout;
EditText myFilter;

// Indexing fo the list
HashMap<String, Integer> alphaIndexer;
String[] sections;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// remove title
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.contact_manager);

// /////////// Custom progress Layout //////////////////////
progressLayout = (RelativeLayout) findViewById(R.id.progress_layout);

progressLayout.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
return true;
}
});
progressLayout.setVisibility(View.GONE); // by default progress view to GONE
// /////////////////////////////////////

// Init UI elements
lv = (ListView) findViewById(R.id.contactList);
doneSelect = (ImageView) findViewById(R.id.doneSelect);
myFilter = (EditText) findViewById(R.id.search_txt);

// Register handler for UI elements
doneSelect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Util.hideSoftKeyboard(ContactManager.this);
setSelctedcontacts();
}

});

// Add text listner to the edit text for filtering the List
myFilter.addTextChangedListener(new TextWatcher() {

@Override
public void afterTextChanged(Editable s) {
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
// call the filter with the current text on the editbox
contactAdapter.getFilter().filter(s.toString());
}
});

if (contacts == null) {
contacts = new ArrayList<Contact>();
// Asynchronously load all contacts
new AsyncLoadContacts().execute();
} else {
contactAdapter = new ContactAdapter(this, R.id.contactList, contacts);
lv.setAdapter(contactAdapter);

}

}

// set selected contacts on DONE button press
private void setSelctedcontacts() {

ArrayList<Contact> selectedList = new ArrayList<Contact>();

Intent intent = new Intent();

ArrayList<Contact> contactList = contactAdapter.originalList;
for (int i = 0; i < contactList.size(); i++) {
Contact contact = contactList.get(i);
if (contact.isSelected()) {
selectedList.add(contact);
}
if (selectedList.size() > 0) {
intent.putParcelableArrayListExtra("SELECTED_CONTACTS", selectedList);
setResult(RESULT_OK, intent);
} else {
setResult(RESULT_CANCELED, intent);
}
}
// Tip: Here you can finish this activity and on the Activty result of the calling activity you fetch the Selected contacts

}

// Also on back pressed set the selected list, if nothing selected set Intent result to canceled
@Override
public void onBackPressed() {

ArrayList<Contact> selectedList = new ArrayList<Contact>();

Intent intent = new Intent();

ArrayList<Contact> contactList = contactAdapter.originalList;
for (int i = 0; i < contactList.size(); i++) {
Contact contact = contactList.get(i);
if (contact.isSelected()) {
selectedList.add(contact);
}
if (selectedList.size() > 0) {
intent.putParcelableArrayListExtra("SELECTED_CONTACTS", selectedList);
setResult(RESULT_OK, intent);
} else {
setResult(RESULT_CANCELED, intent);
}
}

finish();

};

@SuppressLint("InlinedApi")
private void getContacts() {

ContentResolver cr = getContentResolver();

Cursor cur = cr.query(Data.CONTENT_URI, new String[] { Data.CONTACT_ID, Data.MIMETYPE, Email.ADDRESS,
Contacts.DISPLAY_NAME, Phone.NUMBER }, null, null, Contacts.DISPLAY_NAME);

Contact contact;

if (cur.getCount() > 0) {

while (cur.moveToNext()) {

String id = cur.getString(cur.getColumnIndex(Data.CONTACT_ID));

String mimeType = cur.getString(cur.getColumnIndex(Data.MIMETYPE));

if (allContacts.containsKey(id)) {
// update contact
contact = allContacts.get(id);
} else {
contact = new Contact();
allContacts.put(id, contact);
// set photoUri
contact.setContactPhotoUri(getContactPhotoUri(Long.parseLong(id)));
}

if (mimeType.equals(StructuredName.CONTENT_ITEM_TYPE))
// set name
contact.setContactName(cur.getString(cur.getColumnIndex(Contacts.DISPLAY_NAME)));

if (mimeType.equals(Phone.CONTENT_ITEM_TYPE))
// set phone munber
contact.setContactNumber(cur.getString(cur.getColumnIndex(Phone.NUMBER)));

if (mimeType.equals(Email.CONTENT_ITEM_TYPE))
// set email
contact.setContactEmail(cur.getString(cur.getColumnIndex(Email.ADDRESS)));

}
}

cur.close();
// get contacts from hashmap
contacts.clear();
contacts.addAll(allContacts.values());

// remove slef contact
for (Contact _contact : contacts) {

if (_contact.getContactName() == null && _contact.getContactNumber() == null
&& _contact.getContactEmail() == null) {
contacts.remove(_contact);
break;
}

}

contactAdapter = new ContactAdapter(this, R.id.contactList, contacts);
contactAdapter.notifyDataSetChanged();

}

// Get contact photo URI for contactId
public Uri getContactPhotoUri(long contactId) {
Uri photoUri = ContentUris.withAppendedId(Contacts.CONTENT_URI, contactId);
photoUri = Uri.withAppendedPath(photoUri, Contacts.Photo.CONTENT_DIRECTORY);
return photoUri;
}

private class AsyncLoadContacts extends AsyncTask<Void, Void, Void> {

@Override
protected void onPreExecute() {

progressLayout.setVisibility(View.VISIBLE);
}

@Override
protected Void doInBackground(Void... params) {

// Obtain contacts
getContacts();
return null;

}

@Override
protected void onPostExecute(Void result) {
super.onPostExecute(result);

// set contact adapter
lv.setAdapter(contactAdapter);

// set the progress to GONE
progressLayout.setVisibility(View.GONE);
}

}

// Contact adapter
public class ContactAdapter extends ArrayAdapter<Contact> implements SectionIndexer {

private ArrayList<Contact> contactList;
private ArrayList<Contact> originalList;
private ContactFilter filter;

public ContactAdapter(Context context, int textViewResourceId, ArrayList<Contact> items) {
super(context, textViewResourceId, items);

this.contactList = new ArrayList<Contact>();
this.originalList = new ArrayList<Contact>();

this.contactList.addAll(items);
this.originalList.addAll(items);

// indexing
alphaIndexer = new HashMap<String, Integer>();
int size = contactList.size();

for (int x = 0; x < size; x++) {
String s = contactList.get(x).getContactName();

// get the first letter of the store
String ch = s.substring(0, 1);
// convert to uppercase otherwise lowercase a -z will be sorted
// after upper A-Z
ch = ch.toUpperCase();

// HashMap will prevent duplicates
alphaIndexer.put(ch, x);
}

Set<String> sectionLetters = alphaIndexer.keySet();

// create a list from the set to sort
ArrayList<String> sectionList = new ArrayList<String>(sectionLetters);

Collections.sort(sectionList);

sections = new String[sectionList.size()];

sectionList.toArray(sections);
}

@Override
public Filter getFilter() {
if (filter == null) {
filter = new ContactFilter();
}
return filter;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;

if (view == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = vi.inflate(R.layout.contact_item, null);
}
final Contact contact = contactList.get(position);
if (contact != null) {
TextView name = (TextView) view.findViewById(R.id.name);
ImageView thumb = (ImageView) view.findViewById(R.id.thumb);
TextView number = (TextView) view.findViewById(R.id.number);
TextView email = (TextView) view.findViewById(R.id.email);

// labels
TextView numberLabel = (TextView) view.findViewById(R.id.numberLabel);
TextView emailLabel = (TextView) view.findViewById(R.id.emailLabel);

thumb.setImageURI(contact.getContactPhotoUri());

if (thumb.getDrawable() == null)
thumb.setImageResource(R.drawable.def_contact);

final CheckBox nameCheckBox = (CheckBox) view.findViewById(R.id.checkBox);

name.setText(contact.getContactName());

// set number label
if (contact.getContactNumber() == null)
numberLabel.setText("");
else
numberLabel.setText("P: ");

number.setText(contact.getContactNumber());

if (contact.getContactEmail() == null)
emailLabel.setText("");
else
emailLabel.setText("E: ");

email.setText(contact.getContactEmail());

nameCheckBox.setOnCheckedChangeListener(new OnCheckedChangeListener() {

@Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {

contact.setSelected(nameCheckBox.isChecked());
}
});

nameCheckBox.setChecked(contact.isSelected());
}

return view;
}

@Override
public int getPositionForSection(int section) {
return alphaIndexer.get(sections[section]);
}

@Override
public int getSectionForPosition(int position) {
return 0;
}

@Override
public Object[] getSections() {
return sections;
}

// Contacts filter
private class ContactFilter extends Filter {

@Override
protected FilterResults performFiltering(CharSequence constraint) {

constraint = constraint.toString().toLowerCase();
FilterResults result = new FilterResults();
if (constraint != null && constraint.toString().length() > 0) {
ArrayList<Contact> filteredItems = new ArrayList<Contact>();

for (int i = 0, l = originalList.size(); i < l; i++) {
Contact contact = originalList.get(i);
if (contact.toString().toLowerCase().contains(constraint))
filteredItems.add(contact);
}
result.count = filteredItems.size();
result.values = filteredItems;
} else {
synchronized (this) {
result.values = originalList;
result.count = originalList.size();
}
}
return result;
}

@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {

contactList = (ArrayList<Contact>) results.values;
notifyDataSetChanged();
clear();
for (int i = 0, l = contactList.size(); i < l; i++)
add(contactList.get(i));
notifyDataSetInvalidated();
}
}

}

}

 

Download Sources:

TD Contacts picker

Subscribe like and stay tuned!

The post Android custom contacts picker with images, filtering & indexed scrolling. appeared first on Techie Dreams.


Viewing all articles
Browse latest Browse all 21

Trending Articles