I wrote an app that needs to read the contacts from the user's phone. Since I've put it on the market, a few users have told me that my app cannot read their contact list (it pops up an error message saying it can't get the contact list).
For roughly 80% of the users, everything works fine, but others have this problem.
In my MainActivity, I call the method: GetContacts()
If that method returns no contacts, then I call: GetContacts2()
If the app still can't get the contacts, then it pops up the error message. Below are the two methods I'm using. Some of the phones, this doesn't work, are Droid X2 and HTC Incredible.
I'm also setting the required API level to 8 in my manifest, so that eliminates older phones. I also do not have log files from these users.
NOTE: I've removed extra code that simply puts the contacts in an array for simplicity's sake.
Any ideas on why these methods don't work on all phones?
Any help would be greatly appreciated!!
Mark
private void GetContacts()
{
try
{
Context context = getApplicationContext();
Cursor cursor = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
while (cursor.moveToNext())
{
contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
contactName = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
hasPhone = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
if (Integer.parseInt(hasPhone)==1)
{
Cursor phone = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ contactId,null, null);
while (phone.moveToNext())
{
phoneNo = phone.getString(phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
phoneType = phone.getString(phone.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
}
}
}
}
catch (Exception e)
{
}
}
private void GetContacts2()
{
try
{
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if (cur.getCount() > 0)
{
while (cur.moveToNext())
{
contactId = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
contactName = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0)
{
if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0)
{
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?", new String[]{contactId}, null);
while (pCur.moveToNext())
{
phoneNo = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
phoneType = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
}
pCur.close();
}
}
}
}
}
catch (Exception e)
{
}
}
I agree. Exceptions are definitely not meant to be tossed aside. They're exceptions; they indicate that something is seriously wrong and needs to be looked at. I recommend you at least log them, so that users that run into the problems can send you a LogCat. If you don't want your users to have to go through that trouble, write data to a file on the SD card (public), so that they can access it and send it to you.
//declaration
Cursor cursor;
int cNameIndex = 0;
int cNumIndex = 0;
String [] arrPosDrawn= null;
//oncreate
TelephonyManager telMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
int simState = telMgr.getSimState();
switch (simState) {
case TelephonyManager.SIM_STATE_ABSENT:
AlertDialog.Builder alert = new AlertDialog.Builder(
ContactList.this);
alert.setMessage("Please insert Sim card.")
.setTitle("Alert")
.setNeutralButton("OK",
new DialogInterface.OnClickListener() {
public void onClick(
DialogInterface dialog,
int which) {
// TODO Auto-generated method stub
}
}).show();
break;
case TelephonyManager.SIM_STATE_READY:
cursor = refreshContactsCursor();
//contacts.setAdapter(new EfficientAdapter(this));
break;
}
//function
public Cursor refreshContactsCursor()
{
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
startManagingCursor(cursor);
cursor.moveToFirst();
cNameIndex = cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME);
cNumIndex = cursor.getColumnIndex(ContactsContract.Data.DATA1);
arrPosDrawn = new String[cursor.getCount() - 1];
for (int j=0; j < arrPosDrawn.length; j++)
{
arrPosDrawn[j] = "";
}
return cursor;
}
Related
Below is the code I used to get all contacts from phone.
public static ArrayList<Recipient> getAllRecipient(Context context) {
ArrayList<Recipient> contacts = new ArrayList<>();
Cursor cursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
if (cursor != null) {
try {
final int displayNameIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
final int numberIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
final int typeIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE);
final int uriIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_THUMBNAIL_URI);
String displayName, number, uri;
while (cursor.moveToNext()) {
int type = cursor.getInt(typeIndex);
if (type == ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE) {
displayName = cursor.getString(displayNameIndex);
number = cursor.getString(numberIndex);
number = number.replaceAll("[^0-9+]+", "");//remove all special character and space, just keep digit number and "+"
uri = cursor.getString(uriIndex);
Recipient recipient = new Recipient(displayName, number, uri);
contacts.add(recipient);
}
}
} catch (Exception e) {
LogUtil.debug("can't get recipient: " + e.getMessage());
} finally {
cursor.close();
}
}
cursor.close();
return contacts;
}
I got feedback from many users , they can not get full contacts in their phones, show almost contacts but missed some contacts.
Is there any problem with above code ? Thanks.
Use this code
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, null);
while (phones.moveToNext())
{
String name=phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
}
phones.close();
Phone.CONTENT_URI includes all Phone entries of the device. If a contact does not have some phone you are not going to get any information about it.
If contacts is what you are after, you should query the ContactsContract.Contacts.CONTENT_URI.
Keep in mind that contacts and phone are two separate things for Android. Not all contacts have phone numbers and you would have to query the numbers separately.
That's my code , which give me all number of my android device like mobile numbers, whatsapp numbers and landline numbers. But i want only mobile number and landline numbers from android phone book into my application. How can i get only mobile number and landline number of every contact name?
private void addContactsInList() {
// TODO Auto-generated method stub
Cursor cursor = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, null, null, null);
try {
ContactsListClass.phoneList.clear();
} catch (Exception e) {
}
while (cursor.moveToNext()) {
String phoneName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phoneNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
int phoneId = cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
Contact cp = new Contact();
cp.setName(phoneName);
cp.setNumber(phoneNumber);
cp.setId(phoneId);
ContactsListClass.phoneList.add(cp);
// Log.e("add to list", "content" + phoneId +phoneName +phoneNumber);
}
cursor.close();
lv = new ListView(context);
lv.setLayoutParams(new LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT));
llContainer.addView(lv);
Collections.sort(ContactsListClass.phoneList, new Comparator<Contact>() {
#Override
public int compare(Contact lhs,
Contact rhs) {
return lhs.getName().compareTo(
rhs.getName());
}
});
contactAdapter = new ContactsAdapter(MainActivity.this,
ContactsListClass.phoneList);
lv.setAdapter(contactAdapter);
inside your while loop, put something like this:
while (phoneCursor.moveToNext()) {
phoneNumber = phoneCursor.getString(phoneCursor.getColumnIndex(NUMBER));
//String number = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
int type = phoneCursor.getInt(phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
switch (type) {
case ContactsContract.CommonDataKinds.Phone.TYPE_HOME:
// do something with the Home number here...
break;
case ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE:
output.append("\n Phone number:" + phoneNumber);
break;
case ContactsContract.CommonDataKinds.Phone.TYPE_WORK:
// do something with the Work number here...
break;
}
}
as seen in this answer
Uri personUri = ContentUris.withAppendedId(People.CONTENT_URI, personId);
Uri phonesUri = Uri.withAppendedPath(personUri, People.Phones.CONTENT_DIRECTORY);
String[] proj = new String[] {Phones._ID, Phones.TYPE, Phones.NUMBER, Phones.LABEL}
Cursor cursor = contentResolver.query(phonesUri, proj, null, null, null);
if(cursor != null && cursor.moveToFirst()){
do{
String number = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
int type = phoneCursor.getInt(phoneCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
switch (type) {
case ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE:
break;
}
}while(cursor.moveToNext());
}
Am trying to use the ContactsProvider with my AutoCompleteTextview using a method that fetches the data (name and phone number) and stores them in a list. As expected, this method will always take time to complete as am calling the method in the onCreateView method of my Fragment class.
This is the method:
...
ArrayList<String> phoneValues;
ArrayList<String> nameValues;
...
private void readContactData() {
try {
/*********** Reading Contacts Name And Number **********/
String phoneNumber = "";
ContentResolver contentResolver = getActivity()
.getContentResolver();
//Query to get contact name
Cursor cursor = contentResolver
.query(ContactsContract.Contacts.CONTENT_URI,
null,
null,
null,
null);
// If data data found in contacts
if (cursor.getCount() > 0) {
int k=0;
String name = "";
while (cursor.moveToNext())
{
String id = cursor
.getString(cursor
.getColumnIndex(ContactsContract.Contacts._ID));
name = cursor
.getString(cursor
.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
//Check contact have phone number
if (Integer
.parseInt(cursor
.getString(cursor
.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0)
{
//Create query to get phone number by contact id
Cursor pCur = contentResolver
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID
+ " = ?",
new String[] { id },
null);
int j=0;
while (pCur
.moveToNext())
{
// Sometimes get multiple data
if(j==0)
{
// Get Phone number
phoneNumber =""+pCur.getString(pCur
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
// Add contacts names to adapter
autocompleteAdapter.add(name);
// Add ArrayList names to adapter
phoneValues.add(phoneNumber.toString());
nameValues.add(name.toString());
j++;
k++;
}
} // End while loop
pCur.close();
} // End if
} // End while loop
} // End Cursor value check
cursor.close();
} catch (Exception e) {
Log.i("AutocompleteContacts","Exception : "+ e);
}
}
Am sure there is a better way to accomplish this, but this method works and the suggestions are presented when I type into the AutocompleteTextview. Am just worried about the time it takes. How can I accomplish this without populating an ArrayList?
I have looked at this question: Getting name and email from contact list is very slow and applied the suggestions in the answer to my code, but now nothing is suggested when I type.How can I improve the performance of my current code?
This is how i have implemented AutoCompleteTextView and it works fine for me ..
final AutoCompleteTextView act=(AutoCompleteTextView)findViewById(R.id.autoCompleteTextView1);
ArrayList<String> alContacts = new ArrayList<String>();
ArrayList<String> alNames= new ArrayList<String>();
ContentResolver cr = this.getContentResolver(); //Activity/Application android.content.Context
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if(cursor.moveToFirst())
{
do
{
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
if(Integer.parseInt(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0)
{
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",new String[]{ id }, null);
while (pCur.moveToNext())
{
String contactNumber = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
String contactName=pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
alNames.add(contactName);
alContacts.add(contactNumber);
break;
}
pCur.close();
}
} while (cursor.moveToNext()) ;
}
String[] array=new String[alNames.size()];
array=(String[]) alNames.toArray(array);
ArrayAdapter<String> myArr= new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,array);
act.setAdapter(myArr);
act.setThreshold(1);
I got rid of the slow response by placing the method inside an AsynTask.
public class AutocompleteAsyncTask extends AsyncTask<Void, Void, Void> {
public Void doInBackground(Void...params) {
try {
/*********** Reading Contacts Name And Number **********/
String phoneNumber = "";
ContentResolver contentResolver = getActivity()
.getContentResolver();
//Query to get contact name
Cursor cursor = contentResolver
.query(ContactsContract.Contacts.CONTENT_URI,
null,
null,
null,
null);
// If data data found in contacts
if (cursor.getCount() > 0) {
int k=0;
String name = "";
while (cursor.moveToNext())
{
//...Rest of the same code as above
and then calling this in my onCreateView():
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
new AutocompleteAsyncTask().execute();
return rootView;
}
Now the task of inflating my view and fetching the data are separated into two different threads.
The CursorLoader option mentioned by Eugen Pechanec is kinda the best option, so I'll update this answer with that option when I can.
a new app, I need to import all contacts with mobile phone,
I runs the code below in an AsyncTask class.
Its works fine, but very slow, on a device with 2000 contacts, the device freeze for few moments.
I know it can be done much faster since there are a lot of apps that use the contacts.
Any ideas?
public ArrayList<ContactInfo> getContacts() {
ArrayList<ContactInfo> arrayList = new ArrayList<ContactInfo>();
ContentResolver cr = GlobalData.instance().getContext().getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, Phone.DISPLAY_NAME + " ASC");
String id;
String name;
int counter = 0;
if (cur.getCount() > 0) {
int indexId= cur.getColumnIndex(ContactsContract.Contacts._ID);
int indexName = cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
int indexHasPhoneNum = cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER);
Log.d("getContacts", "Start");
while (cur.moveToNext()) {
id = cur.getString(indexId);
name = cur.getString(indexName);
if (Integer.parseInt(cur.getString(indexHasPhoneNum)) > 0) {
// Query phone here. Covered next
Cursor phones = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + id, null, null);
while (phones.moveToNext()) {
int type = phones.getInt(phones.getColumnIndex(Phone.TYPE));
if(type == Phone.TYPE_MOBILE){
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
arrayList.add(new ContactInfo(name, phoneNumber));
counter++;
}
}
phones.close();
}
}
Log.d("getContacts", "End (" + counter + ")" );
}
cur.close();
return arrayList;
After some search with other resources and some common sense, the answer to get all mobile phones in the device is to query the ContactsContract.CommonDataKinds.Phone.CONTENT_URI instead of the ContactsContract.Data.CONTENT_URI and ran the cursor on that.
I retrieve phonebook contacts to my application by using following code:
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Intent contactPickerIntent = new Intent(Intent.ACTION_PICK,
Contacts.CONTENT_URI);
startActivityForResult(contactPickerIntent, CONTACT_PICKER_RESULT);
}
But I want to select multiple contacts and upload those to a DB. Is this possible and if so how can I do this?
Well you could query the content provider directly inside your activity so the user can select multiple contact. This can be achieved using the contacts contract. For more information you can look at the api documentation or this tutorial blog post
try this code..
people = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
int position=0;
Cursor q=db.query(mProfile,new String[]{"person_name"},"person_name"+"!='"+null+"'",null,null, null, null);
people.moveToFirst();
int nameFieldColumnIndex = people.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
while(!people.isAfterLast()) {
Cursor o=db.query(mProfile,new String[]{"person_name"},"person_name"+"='"+people.getString(nameFieldColumnIndex)+"'",null,null, null, null);
if(!(o.getCount()>0))
{
mConname.add(position, people.getString(nameFieldColumnIndex));
try{
String contactId = people.getString(people.getColumnIndex(ContactsContract.Contacts._ID));
String hasPhone = people.getString(people.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
if ( hasPhone.equalsIgnoreCase("1"))
hasPhone = "true";
else
hasPhone = "false" ;
if (Boolean.parseBoolean(hasPhone))
{
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ contactId,null, null);
while (phones.moveToNext())
{
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
mConno.add(position,phoneNumber);
}
phones.close();
}
if(hasPhone=="false")
{ mConname.remove(position);
}
else
position++;
}
catch(Exception e)
{
}
}
people.moveToNext();
}
use the sqlite and store it