I am trying to fetch SMS's which start with TM-,ID-, AX-, AD- but I am getting sms's only which having number.
I am not able to receive any sms which will have text in address.
Here is my code :
Uri uriSms = Uri.parse("content://sms/inbox");
String[] projection = new String[]{"_id", "address", "date", "body", "person", "type"};
m_SMSCursor =context.getContentResolver().query(uriSms, projection, null,null,null);
if(m_SMSCursor.moveToFirst())
{
// Read each row from cursor and store it into the database
do {
// Extract fields from cursor
final String number = m_SMSCursor.getString(1);
final long date = m_SMSCursor.getLong(2);
final String body = m_SMSCursor.getString(3);
final String person = m_SMSCursor.getString(4);
final int type = m_SMSCursor.getInt(5);
try {
// Insert call log into database
long l;
new Thread(new Runnable() {
#Override
public void run() {
// create object for CallLogAdapter
SMSDataAdapter objSmsDataAdapter = new SMSDataAdapter(
context);
// open the database
objSmsDataAdapter = objSmsDataAdapter.Open();
try {
boolean isVMPresent = number.startsWith("VM-");
boolean isLMPresent = number.startsWith("LM-");
boolean isTMPresent = number.startsWith("TM-");
boolean isVKPresent = number.startsWith("VK-");
boolean isIXPresent = number.startsWith("IX-");
boolean isADPresent = number.startsWith("AD-");
boolean isAXPresent = number.startsWith("AX-");
boolean isBWPresent = number.startsWith("BW-");
boolean isIDPresent = number.startsWith("ID-");
boolean isIMPresent = number.startsWith("IM-");
Log.i(TAG, "Number1 : " + number + " body1 : " + body + " peron : " + person + " type : " + type);
if (isVMPresent || isLMPresent || isTMPresent || isVKPresent || isIXPresent || isADPresent || isAXPresent || isBWPresent || isIDPresent || isIMPresent) {
long lNumberOfEntry = objSmsDataAdapter.Insert(number, body, date, DATA_NOT_ANALYZED);
}
} catch (SQLException e1) {
} finally {
// Close the database
objSmsDataAdapter.Close();
}
}
}).start();
} catch (SQLException e) {
return FAILURE;
}
} while (m_SMSCursor.moveToNext());
}
But I am able to fetch all sms except which having text in address. I am able fetch sms's which having number in address.
Please give me hint or reference.
Use this method to get all data in a list first and then access the number by smsList.getNumber()
List<SMSData> smsList = new ArrayList<SMSData>();
Uri uri = Uri.parse("content://sms/inbox");
Cursor c= getContentResolver().query(uri, null, null ,null,null);
startManagingCursor(c);
// Read the sms data and store it in the list
if(c.moveToFirst()) {
for(int i=0; i < c.getCount(); i++) {
SMSData sms = new SMSData();
sms.setBody(c.getString(c.getColumnIndexOrThrow("body")).toString());
sms.setNumber(c.getString(c.getColumnIndexOrThrow("address")).toString());
smsList.add(sms);
c.moveToNext();
}
}
c.close();
SMSData:
public class SMSData {
// Number from witch the sms was send
private String number;
// SMS text body
private String body;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
Related
I am working with an Android application which shows the list of contacts in the phone like Whats-app. I am successful with getting the contacts to the Application database. When I try to update my DB when a contact is newly added/edited/deleted using Content Observer, I mainly face two problems
1. When Calls ,
String contactName = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
I am getting wrong name. eg:- I edited Samuel's Contact no but checking the above code getting David's name.
when I try to get contact number by using the code,
contactNumber = cur.getString(cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
I am getting error
E/CursorWindow: Failed to read row 0, column -1 from a CursorWindow which has 402 rows, 41 columns.
03-01 17:16:56.546 3660-3660/com.xxxxxxxxx.xxxxx W/System.err: java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
Please Anybody help me to find the solution.
Here is my Code
public class ContactObserver extends ContentObserver {
Intent i;
private static final String TAG = "ObserverReceiver";
private Context context;
BaseActivity mBaseActivity;
public ContactObserver(Handler handler, BaseActivity context) {
super(handler);
this.mBaseActivity = context;
this.context = context;
}
public ContactObserver() {
super(null);
}
#Override
public boolean deliverSelfNotifications() {
return true;
}
#Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
if (!selfChange) {
try {
ContentResolver cr = context.getContentResolver();
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
Log.d(TAG, "Observer has been started..");
// Contacts Cursor
final Cursor cur = context.getContentResolver().query(
ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
// Check which contact is added or updated
if (cur != null) {
while (cur.moveToNext()) {
// Get contact added/updated timestamp but CONTACT_LAST_UPDATED_TIMESTAMP
// Get new/updated contact detail here
final String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
final String contactName = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
String contactNumber = null;
if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) {
try {
contactNumber = cur.getString(cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
} catch (Exception e) {
e.printStackTrace();
}
}
String finalContactNumber = contactNumber;
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
List<Contacts> sContacts = ContactDatabase
.getDatabase(context)
.contactsDao()
.getBySystemid(id);
Log.i("Contacts1+", new Gson().toJson(sContacts));
if (sContacts.size() > 0) {
for (Contacts mContacts : sContacts) {
String phone = finalContactNumber;
if (phone == null) {
phone = mContacts.getPhone();
}
Log.i("Contacts1+", contactName + " : " + phone);
if (phone != null && phone.length() > 0) {
phone = phone.replace(" ", "");
}
while (String.valueOf(phone.charAt(0)).equals("0")) {
String num = "";
for (int i = 1; i < phone.length(); i++) {
num = num + phone.charAt(i);
}
phone = num;
}
if (phone.length() == 10) {
phone = getSharedPreference(AppConstants.SharedKey.COUNTRY_CODE) + phone;
}
if ((mContacts.getName() != contactName || mContacts.getPhone() != phone)) {
mContacts.setName(contactName);
if (!mContacts.getPhone().equalsIgnoreCase(phone)) {
mContacts.setPhone(phone);
mContacts.setIslisted("false");
}
if (mContacts.getPhone().equalsIgnoreCase(phone) || mContacts.getName().equalsIgnoreCase(contactName)) {
ContactDatabase.getDatabase(context)
.contactsDao()
.update(mContacts);
cur.close();
}
}
}
} else {
Contacts mContacts = new Contacts();
String contactNumber = null;
try {
contactNumber = cur.getString(cur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
if (contactNumber != null && contactNumber.length() > 0) {
contactNumber = contactNumber.replace(" ", "");
contactNumber = contactNumber.replace("-", "");
}
while (String.valueOf(contactNumber.charAt(0)).equals("0")) {
String num = "";
for (int i = 1; i < contactNumber.length(); i++) {
num = num + contactNumber.charAt(i);
}
contactNumber = num;
}
if (contactNumber.length() == 10) {
contactNumber = getSharedPreference(AppConstants.SharedKey.COUNTRY_CODE) + contactNumber;
}
String contactName = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
mContacts.setPhone(contactNumber);
mContacts.setName(contactName);
mContacts.setSystemid(id);
mContacts.setIslisted("false");
List<Contacts> cContacts = ContactDatabase
.getDatabase(context)
.contactsDao()
.getbyPhone(contactNumber);
if (cContacts.size() == 0) {
ContactDatabase.getDatabase(context)
.contactsDao()
.insert(mContacts);
}
} catch (Exception e) {
e.printStackTrace();
}
}
i = new Intent(context, ContactSynchService.class);
context.startService(i);
cur.close();
}
});
thread.start();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public String getSharedPreference(String key) {
SharedPreferences prefs = mBaseActivity.getSharedPreferences(AppConstants.SHARED_KEY, MODE_PRIVATE);
return prefs.getString(key, "DEFAULT");
}
}
I tried these links, but none of them could give a solution.
ContentObserver for contact update manually
ContentObserver not working in android
Android: ContentObserver not working in android 4.3
Any help will be appreciated. Thanks in Advance
I'd like to load messages from phone in my activity. I search for solution, but I can`t find any.
Use this :
private String SmsDetails(Application mContext) {
// TODO Auto-generated method stub
smsInbox = new ArrayList<Entry>();
final Uri SMS_Inbox = Uri.parse("content://sms/inbox");
String smsHistory = "";
try {
String sDirection = "1";
String sMessageType = "0";
String SMS_READ_COLUMN = "read";
String SORT_ORDER = " _id ASC";
int count = 0;
Cursor cursor;
int iLastIDRun = 0;
// "address = '+9180009'"
cursor = mContext.getContentResolver().query(
SMS_Inbox,
new String[] { "_id", "thread_id", "address", "person",
"date", "body" },
" _id > " + String.valueOf(iLastIDRun), null,
SORT_ORDER);
sMessageType = "1";
if (cursor != null) {
try {
if (cursor.moveToFirst()) {
do {
String address = cursor.getString(2);
long timestamp = cursor.getLong(4);
String sBody = cursor.getString(5);
if (address.startsWith("1")) {
address = address.substring(1);
}
//store the required details
} while (cursor.moveToNext());
}
} catch (Exception e) {
e.printStackTrace();
}
cursor.close();
}
doCheckSmsHistory();
} catch (Exception e) {
e.printStackTrace();
}
return smsHistory;
}
EDIT:A list of what I consider important contact details:
1.NAME
2.PHONE NUMBER
3.EMAIL ADDRESS
4.WEBSITE
5.PHYSICAL ADDRESS
I would prefer to do this using a pre-fetched contactId...using only one cursor to get all of the data specified.I,preferably would like to find the right query to do this:
I would like to get all of the important details of a Contact at once,I am using the following code to do this:
public void getAllDataByContactId(int contactId)
{
Log.d(TAG, "Seriously scared it might not work");
String phoneNo="Phone disconnected";
String email="Email could not be delivered";
String website="Website 404";
String address="Number 13,Dark Street,Area 51,Bermuda Trianlge";
String name="Clint Eastwood";
int hasPhoneNumber;
String selection=ContactsContract.Data.CONTACT_ID+"=?";
String[] selectionArgs={String.valueOf(contactId)};
Cursor c=context.getContentResolver().query(ContactsContract.Data.CONTENT_URI, null,selection, selectionArgs,ContactsContract.Data.TIMES_CONTACTED);
if(c!=null && c.getCount()>0)
{
while(c.moveToNext())
{
phoneNo=c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
Log.d(TAG, "Phone number: "+phoneNo);
email=c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS));
Log.d(TAG, "Email: "+email);
website=c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Website.URL));
Log.d(TAG, "Website :"+website);
address=c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.StructuredPostal.FORMATTED_ADDRESS));
name=c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME));
Log.d(TAG, "Name :"+name);
}
}
}
However,although this does not throw an error it shows many rows consisting of an empty string interspresed with the actual values.How do I write a query that cuts out the noise?
I have tried this and this gets me all the values:
String selection=ContactsContract.Data.CONTACT_ID+"=? AND "+ContactsContract.Data.MIMETYPE+"=? OR "+ContactsContract.Data.MIMETYPE+"=? OR "+ContactsContract.Data.MIMETYPE+"=? OR "+ContactsContract.Data.MIMETYPE+"=? OR "+ContactsContract.Data.MIMETYPE+"=?";
String[] selectionArgs={String.valueOf(contactId),ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE,ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE,ContactsContract.CommonDataKinds.StructuredPostal.CONTENT_ITEM_TYPE};
Too late to answer, but maybe it can help someone in the future.
My solution for this question with only one while cycle and query:
private void fetchContacts(ContentResolver contentResolver) {
if (contentResolver == null) return;
Cursor cursor = contentResolver.query(ContactsContract.Data.CONTENT_URI,
null, null, null, null);
if (cursor == null || cursor.getCount() <= 0) {
return;
}
String prevId = "";
String contactId = "";
PersonContact personContact = null;
while (cursor.moveToNext()) {
String company = "";
String columnName = cursor.getString(cursor.getColumnIndex("mimetype"));
if (columnName.equals(ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE)) {
company = cursor.getString(cursor.getColumnIndex("data1"));
}
String email = "";
if (columnName.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
email = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.DATA));
}
String phone = "";
if (columnName.equals(ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)) {
phone = cursor.getString(cursor.getColumnIndex("data1"));
}
String first = "";
String last = "";
if (columnName.equals(ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)) {
first = cursor.getString(cursor.getColumnIndex("data2"));
last = cursor.getString(cursor.getColumnIndex("data3"));
}
if (!prevId.equals(contactId)) {
if (!TextUtils.isEmpty(prevId)) {
addFilteredList(personContact);
allContacts.put(prevId, personContact);
}
prevId = contactId;
personContact = new PersonContact();
} else {
if (personContact != null) {
personContact.id = prevId;
if (TextUtils.isEmpty(personContact.company)) personContact.company = company;
if (TextUtils.isEmpty(personContact.firstName)) personContact.firstName = first;
if (TextUtils.isEmpty(personContact.lastName)) personContact.lastName = last;
if (!TextUtils.isEmpty(email) && personContact.emails.size() == 0) {
personContact.emails.add(email);
}
if (!TextUtils.isEmpty(phone) && personContact.phoneNumbers.size() == 0) {
personContact.phoneNumbers.add(phone);
}
}
}
contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
}
cursor.close();
}
As you can see, I used the prevId field, because cursor.moveToNext performs several times for one contact (once for first and last names, one for phone, etc.). After each iteration, I check the previous contact identifier with the current identifier and, if it is false, I update the fields in the personContact model.
May not be the best solution. But this is how I achieved it.
ArrayList<String> fnameList = new ArrayList<>();
ArrayList<String> lnameList = new ArrayList<>();
ArrayList<String> mnumList = new ArrayList<>();
ArrayList<String> hnumList = new ArrayList<>();
ArrayList<String> wnumList = new ArrayList<>();
ArrayList<String> mailList = new ArrayList<>();
final DynamoDBMapper dynamoDBMapper = AWSMobileClient.defaultMobileClient().getDynamoDBMapper();
final ContactsDO firstItem = new ContactsDO(); // Initialize the Notes Object
firstItem.setUserId(AWSMobileClient.defaultMobileClient().getIdentityManager().getCachedUserID());
String email = null;
Uri CONTENT_URI = ContactsContract.Contacts.CONTENT_URI;
String _ID = ContactsContract.Contacts._ID;
String HAS_PHONE_NUMBER = ContactsContract.Contacts.HAS_PHONE_NUMBER;
Uri EmailCONTENT_URI = ContactsContract.CommonDataKinds.Email.CONTENT_URI;
String EmailCONTACT_ID = ContactsContract.CommonDataKinds.Email.CONTACT_ID;
String DATA = ContactsContract.CommonDataKinds.Email.DATA;
StringBuffer output = new StringBuffer();
ContentResolver contentResolver = this.getContentResolver();
Cursor cursor = contentResolver.query(CONTENT_URI, null, null, null, null);
// Loop for every contact in the phone
if (cursor.getCount() > 0) {
while (cursor.moveToNext()) {
int hasPhoneNumber = Integer.parseInt(cursor.getString(cursor.getColumnIndex(HAS_PHONE_NUMBER)));
if (hasPhoneNumber > 0) {
String contact_id = cursor.getString(cursor.getColumnIndex(_ID));
// Query and loop for every phone number of the contact
Cursor pCur = contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
new String[]{contact_id}, ContactsContract.CommonDataKinds.Phone.NUMBER);
int flag = 0;
assert pCur != null;
while (pCur.moveToNext()) {
String mobileNum = pCur.getString(pCur.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER));
if (flag == 0) {
if(mobileNum!=null){
mnumList.add(mobileNum);}
} else if (flag == 1) {
if(mobileNum!=null){
hnumList.add(mobileNum);}
} else if (flag == 2) {
if(mobileNum!=null){
wnumList.add(mobileNum);}
}
flag++;
}
if(flag==1){
hnumList.add("");
wnumList.add("");
Log.e("Set","Both added");
}
if(flag==2){
wnumList.add("");
Log.e("Set","W added");
}
pCur.close();
}
}
}
cursor.close();
String MIME = ContactsContract.Data.MIMETYPE + "=?";
String[] params = new String[]{ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE};
final Cursor nameCur = contentResolver.query(
ContactsContract.Data.CONTENT_URI,
null,
MIME,
params,
ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME);
assert nameCur != null;
int i = 0;
while (nameCur.moveToNext()){
String fname = "";
String lname = "";
fname = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
lname = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
Log.e("In While","All the time");
if(fname!=null){
fnameList.add(fname);
Log.e("Put","Value Fname "+fname);}
if(lname!=null) {
lnameList.add(lname);
Log.e("Put","Value Lname "+lname);
}
if(fname==null){
fnameList.add(" ");
}
if(lname==null){
lnameList.add(" ");
}
i++;
}
nameCur.close();
Cursor cursorB = contentResolver.query(CONTENT_URI, null, null, null, null);
// Loop for every contact in the phone
if (cursorB.getCount() > 0) {
while (cursorB.moveToNext()) {
// Query and loop for every email of the contact
String[] paramEmail = new String[]{ContactsContract.CommonDataKinds.Email.CONTENT_TYPE};
Cursor emailCursor = contentResolver.query(EmailCONTENT_URI, null, ContactsContract.CommonDataKinds.Email.CONTACT_ID + " = ?", paramEmail, ContactsContract.CommonDataKinds.Email.DISPLAY_NAME);
int j=0;
while (emailCursor.moveToNext()) {
email = emailCursor.getString(emailCursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.ADDRESS));
mailList.add(email);
Log.e("Email",email);
j++;
}
if(j==0){
mailList.add("");
Log.e("Email","Dummy Added");
}
emailCursor.close();
output.append("\n");
}
}cursorB.close();
Cursor cursorD = contentResolver.query(CONTENT_URI, null, null, null, null);
// Loop for every contact in the phone
if (cursorD.getCount() > 0) {
while (cursorD.moveToNext()) {
String contact_id = cursorD.getString(cursorD.getColumnIndex(_ID));
//for url
String newNoteUrl = "";
String whereName3 = ContactsContract.Data.MIMETYPE + " = ?";
String[] whereNameParams3 = new String[]{ContactsContract.CommonDataKinds.Website.CONTENT_ITEM_TYPE};
ContentResolver contentResolverUrl = this.getContentResolver();
try {
Cursor cursorUrl = contentResolverUrl.query(ContactsContract.Data.CONTENT_URI, null, whereName3, new String[]{contact_id}, ContactsContract.CommonDataKinds.Website.URL);
while (cursorUrl.moveToNext()) {
newNoteUrl = cursorUrl.getString(cursorUrl.getColumnIndex(ContactsContract.CommonDataKinds.Website.URL));
Log.e("URL",newNoteUrl);
}
Log.e("URL","Not Getting");
output.append("\nurl " + newNoteUrl);
firstItem.setUrl(newNoteUrl);
cursorUrl.close();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}}cursorD.close();
Log.e("#######","##########################");
for(int m=0;m<fnameList.size();m++){
Log.e("Contact Val ",fnameList.get(m)+" , "+lnameList.get(m)+" , "+mnumList.get(m)+" , "+hnumList.get(m)+" , "+wnumList.get(m)+" , "+mailList.get(m));
ContactsDO item = new ContactsDO();
item.setUserId(AWSMobileClient.defaultMobileClient().getIdentityManager().getCachedUserID());
item.setFirstName(fnameList.get(m));
item.setLastName(lnameList.get(m));
item.setMobileNumber(mnumList.get(m));
item.setHomeNumber(hnumList.get(m));
item.setWorkNumber(wnumList.get(m));
item.setEmail(mailList.get(m));
try {
//saving to the database
dynamoDBMapper.save(item);
} catch (final AmazonClientException ex) {
Log.e(TAG, "Failed saving item : " + ex.getMessage(), ex);
}
}
In my project getting contacts is taking a long time to load.
What are ways to reduce the time of getting contacts
Assume there are 1000 contacts in my phone.
Right now it is taking more than 2 minutes to load all the contacts
How can I reduce the time to load contacts ?
Any Thoughts?
I referred to the the following link when programming the initial method.
http://www.coderzheaven.com/2011/06/13/get-all-details-from-contacts-in-android/
BETTER SOLUTION HERE.....
private static final String[] PROJECTION = new String[] {
ContactsContract.CommonDataKinds.Phone.CONTACT_ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER
};
.
.
.
ContentResolver cr = getContentResolver();
Cursor cursor = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, PROJECTION, null, null, null);
if (cursor != null) {
try {
final int nameIndex = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
final int numberIndex = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
String name, number;
while (cursor.moveToNext()) {
name = cursor.getString(nameIndex);
number = cursor.getString(numberIndex);
}
} finally {
cursor.close();
}
}
CHEERS...:)
Total time will depend upon what fields you are trying to access from the Contacts table.
Accessing less field means less looping , less processing and hence faster results.
Also to speed up your contacts fetch operation you can use the ContentProvideClient instead of calling query on ContentResolver every time. This will make you query the specific table rather than querying first for the required ContentProvider and then to table.
Create an instance of ContentProviderClient
ContentResolver cResolver=context.getContextResolver();
ContentProviderClient mCProviderClient = cResolver.acquireContentProviderClient(ContactsContract.Contacts.CONTENT_URI);
Then reuse this mCProviderClient to get Contacts(data from any ContentProvider) data on your call.
For example in following method, I am accessing only one field.
private ArrayList<String> fetchContactsCProviderClient()
{
ArrayList<String> mContactList = null;
try
{
Cursor mCursor = mCProviderClient.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if (mCursor != null && mCursor.getCount() > 0)
{
mContactList = new ArrayList<String>();
mCursor.moveToFirst();
while (!mCursor.isLast())
{
String displayName = mCursor.getString(mCursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));
mContactList.add(displayName);
mCursor.moveToNext();
}
if (mCursor.isLast())
{
String displayName = mCursor.getString(mCursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));
mContactList.add(displayName);
}
}
mCursor.close();
}
catch (RemoteException e)
{
e.printStackTrace();
mContactList = null;
}
catch (Exception e)
{
e.printStackTrace();
mContactList = null;
}
return mContactList;
}
Load Contact faster like other apps doing.
I have tested this code with multiple contacts its working fine and faster like other apps within 500 ms (within half second or less) I am able to load 1000+ contacts.
Total time will depend upon what fields you are trying to access from the Contacts table.
Mange your query according to your requirement do not access unwanted fields. Accessing less field means less looping , less processing and hence faster results.
Accessing right table in contact it also help to reduce contact loading time.
Query Optimization to load contact more faster use projection
String[] projection = {
ContactsContract.Data.MIMETYPE,
ContactsContract.Data.CONTACT_ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.PHOTO_URI,
ContactsContract.Contacts.STARRED,
ContactsContract.RawContacts.ACCOUNT_TYPE,
ContactsContract.CommonDataKinds.Contactables.DATA,
ContactsContract.CommonDataKinds.Contactables.TYPE
};
Selection and selection argument
String selection = ContactsContract.Data.MIMETYPE + " in (?, ?)" + " AND " /*+ ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" + 1 + "' AND "*/ +
ContactsContract.Data.HAS_PHONE_NUMBER + " = '" + 1 + "'";
String[] selectionArgs = {
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
};
To order contacts alphabetically use following code
try {
Collections.sort(listview_address, new Comparator<ContactBook>() {
#Override
public int compare(ContactBook lhs, ContactBook rhs) {
return lhs.name.toUpperCase().compareTo(rhs.name.toUpperCase());
}
});
} catch (Exception e) {
e.printStackTrace();
}
Following is complete source code
public void initeContacts() {
List<ContactBook> listview_address = new LinkedList<ContactBook>();
SparseArray<ContactBook> addressbook_array = null;
{
addressbook_array = new SparseArray<ContactBook>();
long start = System.currentTimeMillis();
String[] projection = {
ContactsContract.Data.MIMETYPE,
ContactsContract.Data.CONTACT_ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.Contacts.PHOTO_URI,
ContactsContract.Contacts.STARRED,
ContactsContract.RawContacts.ACCOUNT_TYPE,
ContactsContract.CommonDataKinds.Contactables.DATA,
ContactsContract.CommonDataKinds.Contactables.TYPE
};
String selection = ContactsContract.Data.MIMETYPE + " in (?, ?)" + " AND " /*+ ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" + 1 + "' AND "*/ +
ContactsContract.Data.HAS_PHONE_NUMBER + " = '" + 1 + "'";
String[] selectionArgs = {
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE,
};
String sortOrder = ContactsContract.Contacts.SORT_KEY_ALTERNATIVE;
Uri uri = null;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
uri = ContactsContract.CommonDataKinds.Contactables.CONTENT_URI;
} else {
uri = ContactsContract.Data.CONTENT_URI;
}
// we could also use Uri uri = ContactsContract.Data.CONTENT_URI;
// we could also use Uri uri = ContactsContract.Contact.CONTENT_URI;
Cursor cursor = getActivity().getContentResolver().query(uri, projection, selection, selectionArgs, sortOrder);
final int mimeTypeIdx = cursor.getColumnIndex(ContactsContract.Data.MIMETYPE);
final int idIdx = cursor.getColumnIndex(ContactsContract.Data.CONTACT_ID);
final int nameIdx = cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
final int dataIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Contactables.DATA);
final int photo = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Contactables.PHOTO_URI);
final int typeIdx = cursor.getColumnIndex(ContactsContract.CommonDataKinds.Contactables.TYPE);
final int account_type = cursor.getColumnIndex(ContactsContract.RawContacts.ACCOUNT_TYPE);
while (cursor.moveToNext()) {
int contact_id = cursor.getInt(idIdx);
String photo_uri = cursor.getString(photo);
String contact_name = cursor.getString(nameIdx);
String contact_acc_type = cursor.getString(account_type);
int contact_type = cursor.getInt(typeIdx);
String contact_data = cursor.getString(dataIdx);
ContactBook contactBook = addressbook_array.get(contact_id);
/* if (contactBook == null) {
//list contact add to avoid duplication
//load All contacts fro device
//to add contacts number with name add one extra veriable in ContactBook as number and pass contact_data this give number to you (contact_data is PHONE NUMBER)
contactBook = new ContactBook(contact_id, contact_name, getResources(), photo_uri, contact_acc_type, "phone number");
addressbook_array.put(contact_id, contactBook);
listview_address.add(contactBook);
}*/
String Contact_mimeType = cursor.getString(mimeTypeIdx);
//here am checking Contact_mimeType to get mobile number asociated with perticular contact and email adderess asociated
if (Contact_mimeType.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
if (contactBook != null) {
contactBook.addEmail(contact_type, contact_data);
}
} else {
if (contactBook == null) {
//list contact add to avoid duplication
//load All contacts fro device
//to add contacts number with name add one extra veriable in ContactBook as number and pass contact_data this give number to you (contact_data is PHONE NUMBER)
contactBook = new ContactBook(contact_id, contact_name, getResources(), photo_uri, contact_acc_type, "phone number");
addressbook_array.put(contact_id, contactBook);
listview_address.add(contactBook);
}
// contactBook.addPhone(contact_type, contact_data);
}
}
cursor.close();
try {
Collections.sort(listview_address, new Comparator<ContactBook>() {
#Override
public int compare(ContactBook lhs, ContactBook rhs) {
return lhs.name.toUpperCase().compareTo(rhs.name.toUpperCase());
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
You can use following code in above code that I have commented .It club the the single contact with its multiple number.To get all number associated with single contact use array in Object class.
if (contactBook == null) {
//irst contact add to avoid duplication
//load All contacts fro device
contactBook = new ContactBook(contact_id, contact_name, getResources(), photo_uri, contact_acc_type, "");
addressbook_array.put(contact_id, contactBook);
listview_address.add(contactBook);
}
String Contact_mimeType = cursor.getString(mimeTypeIdx);
//here am checking Contact_mimeType to get mobile number asociated with perticular contact and email adderess asociated
if (Contact_mimeType.equals(ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
contactBook.addEmail(contact_type, contact_data);
} else {
contactBook.addPhone(contact_type, contact_data);
}
Object class
public class ContactBook {
public int id;
public Resources res;
public String name;
public String photo;
public String contact_acc_type;
public SparseArray<String> emails;
public SparseArray<String> phones;
/* public LongSparseArray<String> emails;
public LongSparseArray<String> phones;*/
public String header = "";
public ContactBook(int id, String name, Resources res, String photo, String contact_acc_type, String header) {
this.id = id;
this.name = name;
this.res = res;
this.photo = photo;
this.contact_acc_type = contact_acc_type;
this.header = header;
}
#Override
public String toString() {
return toString(false);
}
public String toString(boolean rich) {
//testing method to check ddata
SpannableStringBuilder builder = new SpannableStringBuilder();
if (rich) {
builder.append("id: ").append(Long.toString(id))
.append(", name: ").append("\u001b[1m").append(name).append("\u001b[0m");
} else {
builder.append(name);
}
if (phones != null) {
builder.append("\n\tphones: ");
for (int i = 0; i < phones.size(); i++) {
int type = (int) phones.keyAt(i);
builder.append(ContactsContract.CommonDataKinds.Phone.getTypeLabel(res, type, ""))
.append(": ")
.append(phones.valueAt(i));
if (i + 1 < phones.size()) {
builder.append(", ");
}
}
}
if (emails != null) {
builder.append("\n\temails: ");
for (int i = 0; i < emails.size(); i++) {
int type = (int) emails.keyAt(i);
builder.append(ContactsContract.CommonDataKinds.Email.getTypeLabel(res, type, ""))
.append(": ")
.append(emails.valueAt(i));
if (i + 1 < emails.size()) {
builder.append(", ");
}
}
}
return builder.toString();
}
public void addEmail(int type, String address) {
//this is the array in object class where i am storing contact all emails of perticular contact (single)
if (emails == null) {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
emails = new SparseArray<String>();
emails.put(type, address);
/*} else {
//add emails to array below Jelly bean //use single array list
}*/
}
}
public void addPhone(int type, String number) {
//this is the array in object class where i am storing contact numbers of perticular contact
if (phones == null) {
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
phones = new SparseArray<String>();
phones.put(type, number);
/* } else {
//add emails to array below Jelly bean //use single array list
}*/
}
}}
For loading the contacts with mininum time the optimum solution is to use the concept of projection and selection argument while querying the cursor for contacts.
this can be done in following way
void getAllContacts() {
long startnow;
long endnow;
startnow = android.os.SystemClock.uptimeMillis();
ArrayList arrContacts = new ArrayList();
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER;
Cursor cursor = ctx.getContentResolver().query(uri, new String[]{ContactsContract.CommonDataKinds.Phone.NUMBER, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME, ContactsContract.CommonDataKinds.Phone._ID, ContactsContract.Contacts._ID}, selection, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");
cursor.moveToFirst();
while (cursor.isAfterLast() == false) {
String contactNumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
String contactName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
int phoneContactID = cursor.getInt(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID));
int contactID = cursor.getInt(cursor.getColumnIndex(ContactsContract.Contacts._ID));
Log.d("con ", "name " + contactName + " " + " PhoeContactID " + phoneContactID + " ContactID " + contactID)
cursor.moveToNext();
}
cursor.close();
cursor = null;
endnow = android.os.SystemClock.uptimeMillis();
Log.d("END", "TimeForContacts " + (endnow - startnow) + " ms");
}
With above method it took 400ms(less than second) to load contacts where as in normall way it was taking 10-12 sec.
For details imformation this post might help as i took help from it
http://www.blazin.in/2016/02/loading-contacts-fast-from-android.html
If your time increases with your data, then you are probably running a new query to fetch phones/emails for every contact. If you query for the phone/email field using ContactsContract.CommonDataKinds.Phone.NUMBER, then you will just retrieve 1 phone per contact.
The solution is to project the fields and join them by contact id.
Here is my solution in Kotlin (extracting id, name, all phones and emails):
val projection = arrayOf(
ContactsContract.Data.MIMETYPE,
ContactsContract.Data.CONTACT_ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Contactables.DATA
)
val selection = "${ContactsContract.Data.MIMETYPE} in (?, ?)"
val selectionArgs = arrayOf(
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
val contacts = applicationContext
.contentResolver
.query(ContactsContract.Data.CONTENT_URI, projection, selection, selectionArgs, null)
.run {
if (this == null) {
throw IllegalStateException("Cursor null")
}
val contactsById = mutableMapOf<String, LocalContact>()
val mimeTypeField = getColumnIndex(ContactsContract.Data.MIMETYPE)
val idField = getColumnIndex(ContactsContract.Data.CONTACT_ID)
val nameField = getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)
val dataField = getColumnIndex(ContactsContract.CommonDataKinds.Contactables.DATA)
while (moveToNext()) {
val mimeType = getString(mimeTypeField)
val id = getString(idField)
var contact = contactsById[id]
if (contact == null) {
val name = getString(nameField)
contact = LocalContact(id = id, fullName = name, phoneNumbers = listOf(), emailAddresses = listOf())
}
val data = getString(dataField)
when(getString(mimeTypeField)) {
ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE ->
contact = contact.copy(emailAddresses = contact.emailAddresses + data)
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE ->
contact = contact.copy(phoneNumbers = contact.phoneNumbers + data)
}
contactsById[id] = contact
}
close()
contactsById.values.toList()
}
And for reference, my LocalContact model:
data class LocalContact(
val id: String,
val fullName: String?,
val phoneNumbers: List<String>,
val emailAddresses: List<String>
)
I think this is a better solution:
public ContentValues getAllContacts() {
ContentValues contacts = new ContentValues();
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if (cur != null && cur.getCount() > 0) {
while (cur.moveToNext()) {
String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (cur.getInt(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[]{id}, null);
if (pCur != null) {
while (pCur.moveToNext()) {
String phoneNo = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
contacts.put(phoneNo, name);
}
pCur.close();
}
}
}
cur.close();
}
return contacts;
}
for use it you need to call this lines once:
ContentValues contacts = new ContentValues();
contacts = getAllContacts();
and when you want to get contact name by number, just use:
String number = "12345";
String name = (String) G.contacts.get(number);
this algorithm is a bit faster...
I try to retrieve the data each time the Android sends SMS.
Data form:
destination phone number
delivery time
SMS body
Anyone knows how?
Get sms in sent box.
public List<SmsRep> getOutboxSms()
{
if(null == context)
{
return new ArrayList<SmsRep>();
}
Uri uriSms = Uri.parse("content://sms/sent");
Cursor cursor = context.getContentResolver().query(uriSms, null,null,null,null);
List<SmsRep> outboxSms = cursor2SmsArray(cursor);
if(!cursor.isClosed())
{
cursor.close();
}
return outboxSms;
}
And the method to handle data in sent box:
public static List<SmsRep> cursor2SmsArray(Cursor cursor)
{
if(null == cursor || 0 == cursor.getCount())
{
return new ArrayList<SmsRep>();
}
List<SmsRep> messages = new ArrayList<SmsRep>();
try
{
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext())
{
SmsRep singleSms = new SmsRep();
singleSms.id = cursor.getInt(cursor.getColumnIndexOrThrow("_id"));
singleSms.address = cursor.getString(cursor.getColumnIndexOrThrow("address"));
singleSms.timestamp = cursor.getLong(cursor.getColumnIndexOrThrow("date")) / 1000; //### the sent time
singleSms.type = cursor.getInt(cursor.getColumnIndexOrThrow("type"));
singleSms.protocol = cursor.getInt(cursor.getColumnIndexOrThrow("protocol"));
/*
String smsSubject = cursor.getString(cursor.getColumnIndex("subject"));
byte[] subjByts = smsSubject.getBytes("UTF8");
singleSms.subject = new String(subjByts, "UTF8");
*/
String smsBody = cursor.getString(cursor.getColumnIndexOrThrow("body")); //### body
byte[] bodyBytes = smsBody.getBytes("UTF8");
singleSms.body = TextUtils.htmlEncode(new String(bodyBytes, "UTF8")); //escape,handle '='
singleSms.deviceId = deviceId;
//singleSms.body = cursor.getString(cursor.getColumnIndexOrThrow("body"));
messages.add(singleSms);
}
}
catch (Exception e)
{
Log.e(TAG, e.getMessage());
}
finally
{
cursor.close();
}
return messages;
}
Definition of SmsRep:
public class SmsRep
{
static String separator ;
public int id;
public String address;
public long timestamp;
public int type;
public int protocol;
public String subject;
public String body;
public String deviceId;
public SmsRep()
{
// do nothing in ctor
}
}
Is this what you want ?:)
There is nothing in the Android SDK for this, sorry.
We can get notified when you receive a SMS, but there is no way to get notified when a SMS is sent.
Uri uriSMS = Uri.parse("content://sms/sent");
Cursor cur = getActivity().getContentResolver().query(uriSMS , null, null, null, null);
Cursor messagesCursor = getActivity().getContentResolver().query(uriSMS , new String[]{"_id", "address", "body", "person", "date",}, null, null, null);
if(messagesCursor.getCount() > 0) {
try {
while (messagesCursor.moveToNext())
{
int x=messagesCursor.getInt(messagesCursor.getColumnIndex("_id"));
String address=messagesCursor.getString(messagesCursor.getColumnIndex("address"));
String body=messagesCursor.getString(messagesCursor.getColumnIndex("body"));
String person=messagesCursor.getString(messagesCursor.getColumnIndex("person"));
String date_=messagesCursor.getString(messagesCursor.getColumnIndex("date"));
}
}
catch(Exception ex)
{
}
}