I am exporting logs using csv file in android.I am getting only call logs but not getting sms logs.Here is the code
while (curLog.moveToNext()) {
String callName = curLog
.getString(curLog
.getColumnIndex(android.provider.CallLog.Calls.CACHED_NAME));
if (callName == null)
callName="Unknown";
String callNumber = curLog.getString(curLog
.getColumnIndex(android.provider.CallLog.Calls.NUMBER));
String callDate = curLog.getString(curLog
.getColumnIndex(android.provider.CallLog.Calls.DATE));
String callType = curLog.getString(curLog
.getColumnIndex(android.provider.CallLog.Calls.TYPE));
String duration = curLog.getString(curLog
.getColumnIndex(android.provider.CallLog.Calls.DURATION));
data.add(new String[] {callName,callNumber,callDate,callType,duration});
}
Please suggest how to fix it.....
This is my way of getting the SMS. It can get body, content, date of the current message as well as check if it is incoming or outgoing. In addition, it can get the contact name that matches the phone number by another method.
First of all, add permission to AndroidManifest.xml file.
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.app.myapp" >
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
...
</manifest>
Secondly, implement SMS Observer class to get the information you need
public class SMSObserver extends ContentObserver {
private Context context;
private static final String TAG = "SMSObserver";
private static final Uri SMS_URI = Telephony.Sms.CONTENT_URI; //get uri depending on different devices
public SMSObserver(Handler handler, Context context) {
super(handler);
this.context = context;
}
#Override
public boolean deliverSelfNotifications() {
return true;
}
//this onChange method will be fired up when you send or receive message
#Override
public void onChange(boolean selfChange) {
Cursor cursor = context.getContentResolver().query(SMS_URI, null, null, null, Telephony.Sms.DATE + " DESC");
String phNumber = null;
//make sure there is a message being operating
if (cursor != null && cursor.moveToFirst()) {
try {
//the meanings of those variables are quite straight forward
String type = cursor.getString(cursor.getColumnIndex(Telephony.Sms.TYPE));
String content = cursor.getString(cursor.getColumnIndex(Telephony.Sms.BODY));
String date = cursor.getString(cursor.getColumnIndex(Telephony.Sms.DATE));
Date SMSDate = new Date(Long.valueOf(date));
phNumber = cursor.getString(cursor.getColumnIndex(Telephony.Sms.ADDRESS)); //this is phone number rather than address
String contact = getContactDisplayNameByNumber(phNumber); //call the metod that convert phone number to contact name in your contacts
int typeCode = Integer.parseInt(type);
String direction = "";
//get the right direction
switch (typeCode) {
case Telephony.Sms.MESSAGE_TYPE_INBOX:
direction = "INCOMING";
break;
case Telephony.Sms.MESSAGE_TYPE_OUTBOX:
direction = "OUTGOING";
break;
case Telephony.Sms.MESSAGE_TYPE_SENT:
direction = "SENT";
break;
default:
direction = "UNKNOWN";
Log.e(TAG, typeCode + " is unknown");
break;
}
} catch (CursorIndexOutOfBoundsException e) {
Log.e(TAG, "SMSHelper: outgoingSMS", e);
} finally {
cursor.close();
}
}
Toast.makeText(context, "\nName: " + contact + "\nPhone Number:--- " + phNumber + " \nContent:--- "
+ content + " \nCall Date:--- " + SMSDate
+ " Direction: " + direction, Toast.LENGTH_LONG).show();
Log.i(TAG, "\nName: " + contact + "\nPhone Number:--- " + phNumber + " \nContent:--- "
+ content + " \nCall Date:--- " + SMSDate
+ " Direction: " + direction + "\n----------------------------------");
super.onChange(selfChange);
}
/**
* http://stackoverflow.com/questions/3712112/search-contact-by-phone-number
* Look up phone number
*
* #param number phone number
* #return the name matched with the phone number
*/
private String getContactDisplayNameByNumber(String number) {
Uri uri = Uri.withAppendedPath(ContactsContract.PhoneLookup.CONTENT_FILTER_URI, Uri.encode(number));
String name = "<Not in contact list>";
ContentResolver contentResolver = context.getContentResolver();
Cursor contactLookup = contentResolver.query(uri, new String[]{BaseColumns._ID, ContactsContract.PhoneLookup.DISPLAY_NAME}, null, null, null);
try {
if (contactLookup != null && contactLookup.getCount() > 0) {
contactLookup.moveToFirst();
name = contactLookup.getString(contactLookup.getColumnIndex(ContactsContract.Data.DISPLAY_NAME));
//String contactId = contactLookup.getString(contactLookup.getColumnIndex(BaseColumns._ID));
Log.i(TAG, "Found number in contacts: " + number + " = " + name);
} else {
Log.e(TAG, "Cursor is null or empty " + number + " not found in contacts");
}
} finally {
if (contactLookup != null) {
contactLookup.close();
}
}
return name;
}
}
If the device is on running Android 6.0 (API level 23) and the
app's target SdkVersion is 23 or higher, the SMS permission will be
considered as dangerous permission. Therefore you must get the right
permission beforehand .
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED
&&ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED) {
//grant permission
ActivityCompat.requestPermissions( this,
new String[]{Manifest.permission.READ_CONTACTS,Manifest.permission.READ_SMS},
10);
return;
}
Lastly, instantiate the SMSObserver class in the HomeActivity class or any
other Activity classes.
//sms log
smsObserver = new SMSObserver(new Handler(), getApplicationContext());
getContentResolver().registerContentObserver(Telephony.Sms.CONTENT_URI, true, smsObserver);
Related
I need to get the meeting's owner name from the CalendarProvider.
I've found these two rows:
CalendarContract.Events.ORGANIZER,
CalendarContract.Events.OWNER_ACCOUNT
But they return only creator's email.
How can I fetch the creator's name?
Try below code for getting Events details.
For more details you can check google android calendar docs
https://developer.android.com/guide/topics/providers/calendar-provider
// add below permission in your app manifest file and also ask these two permission at run time
<uses-permission android:name="android.permission.WRITE_CALENDAR"/>
<uses-permission android:name="android.permission.READ_CALENDAR"/>
// add below method in your activity
public void getOrganizerName() {
Cursor cur = null;
ContentResolver cr =getContentResolver();
Uri uri=CalendarContract.Events.CONTENT_URI;
String[] eventmProjection =
{CalendarContract.Calendars._ID,
CalendarContract.Events.DTSTART,
CalendarContract.Events.DTEND,
CalendarContract.Events.TITLE,
CalendarContract.Events.EVENT_LOCATION,
CalendarContract.Events.ORGANIZER,
CalendarContract.Events._ID,
CalendarContract.Events.DESCRIPTION,
CalendarContract.Events.DURATION,
CalendarContract.Events.SYNC_DATA1,
CalendarContract.Events.DIRTY,
CalendarContract.Events.UID_2445,
CalendarContract.Events.DELETED,
CalendarContract.Events.LAST_DATE,
CalendarContract.Events.SYNC_DATA2,
CalendarContract.Events.ALL_DAY,
CalendarContract.Events.RRULE,
CalendarContract.Events.STATUS,
CalendarContract.Events.RDATE
};
String selection = "(" + CalendarContract.Calendars.ACCOUNT_NAME + " = ? AND deleted != 1 AND " + CalendarContract.Events.ORGANIZER + " != ?)";
// pass here google calendar sync account detials
String[] selectionArgs = new String[]{"abc#gmail.com","abc#gmail.com"};
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_CALENDAR) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_CALENDAR},12);
}
cur = cr.query(uri, eventmProjection, selection, selectionArgs, null);
if(cur.getCount()>0){
while (cur.moveToNext()) {
String eventTitle = cur.getString(cur.getColumnIndex(CalendarContract.Events.TITLE));
String eventId = cur.getString(cur.getColumnIndex(CalendarContract.Events._ID));
String startDate = cur.getString(cur.getColumnIndex(CalendarContract.Events.DTSTART));
String endDate = cur.getString(cur.getColumnIndex(CalendarContract.Events.DTEND));
String org_name=cur.getString(cur.getColumnIndex(CalendarContract.Events.ORGANIZER));
Log.d("Events", "->" + eventTitle + "->" + eventId + "->" + startDate + "->" + endDate+ "->"+org_name);
}
}
}
After you quired all needed events, when you are in Cursor loop, for every event you can get a name by this method:
private String getOrganizerNameFromAttendees(int eventId, String organizerMail) {
Logger.e(TAG, "getOrganizerNameFromAttendees");
final String[] args = new String[]{String.valueOf(eventId), organizerMail};
final Cursor cursor = mApplicationContext.getContentResolver().query(CalendarContract.Attendees.CONTENT_URI, ATTENDEE_PROJECTION, ATTENDEE_SELECTION, args, null);
String name = null;
try {
while (cursor.moveToNext()) {
String nameFromAttendees = cursor.getString(ATTENDEE_PROJECTION_NAME_INDEX);
String mailFromAttendees = cursor.getString(ATTENDEE_PROJECTION_MAIL_INDEX);
name = TextUtils.isEmpty(nameFromAttendees) ? mailFromAttendees : nameFromAttendees;
}
} catch (Exception e) {
Logger.e(TAG, "getOrganizerNameFromAttendees, exception = " + e.getMessage());
} finally {
if (cursor != null) {
cursor.close();
}
}
return name;
}
How to get dual sim number call logs in android. I followed below link to get the dual sim call logs but this method returns -1 always.
I tried other stackoverflow not much answers for dual sim call logs which is available from api 21.
https://stackoverflow.com/a/23907166/6891712
I have tried using the below method which give only the call details but not able to find that from which sim the call is dialed or received
private void getCalldetailsNow() {
#SuppressLint("MissingPermission") Cursor managedCursor=c.getContentResolver().query(CallLog.Calls.CONTENT_URI, null, null, null, CallLog.Calls.DATE + " DESC");
int number = 0;
if (managedCursor != null) {
number = managedCursor.getColumnIndex( CallLog.Calls.NUMBER );
}
int duration1 = managedCursor.getColumnIndex( CallLog.Calls.DURATION);
int type1=managedCursor.getColumnIndex(CallLog.Calls.TYPE);
int date1=managedCursor.getColumnIndex(CallLog.Calls.DATE);
int idSimId = getSimIdColumn(managedCursor);
if( managedCursor.moveToFirst() == true ) {
String phNumber = managedCursor.getString(number);
String callDuration = managedCursor.getString(duration1);
String type=managedCursor.getString(type1);
String date=managedCursor.getString(date1);
String gettSimNumber=managedCursor.getString(idSimId);
String dir = null;
int dircode = Integer.parseInt(type);
switch (dircode)
{
case CallLog.Calls.OUTGOING_TYPE:
dir = "OUTGOING";
break;
case CallLog.Calls.INCOMING_TYPE:
dir = "INCOMING";
break;
case CallLog.Calls.MISSED_TYPE:
dir = "MISSED";
break;
default:
dir = "MISSED";
break;
}
}
managedCursor.close();
}
public static int getSimIdColumn(final Cursor c) {
for (String s : new String[] { "sim_id", "simid", "sub_id" }) {
int id = c.getColumnIndex(s);
if (id >= 0) {
Log.d(" Simmmm", "sim_id column found: " + s);
return id;
}
}
Log.d(" Simmmm", "no sim_id column found");
return -1;
}
Try this method to read sim card contact ..
if you want to read first device store contact then implement to implements LoaderManager.LoaderCallbacks into class..
#Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new CursorLoader(getActivity(),
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, ProfileQuery.PROJECTION,
// Select only email addresses
null, null, null);
}
#Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
List<String> numbers = new ArrayList<>();
cursor.moveToFirst();
while (!cursor.isAfterLast()) {
String phoneNumber = cursor.getString(ProfileQuery.NUMBER).replaceAll("\\D", "");
CustomLogHandler.printDebuglog(TAG, "onLoadFinished: " + phoneNumber);
if (!TextUtils.isEmpty(phoneNumber) && !phoneNumber.startsWith(Constants.SP_COUNTRY_CODE)) {
mCountryCodeList.add(new StringBuilder().append(Constants.SP_COUNTRY_CODE).toString());
alPhoneNumbers.add(new StringBuilder().append(Constants.SP_COUNTRY_CODE).append(phoneNumber).toString());
} else {
mCountryCodeList.add(new StringBuilder().append(Constants.SP_COUNTRY_CODE).toString());
alPhoneNumbers.add(phoneNumber);
}
names.add(cursor.getString(ProfileQuery.NAME));
cursor.moveToNext();
}
allPhoneNumberName.addAll(names);
}
this below class read sim card data..
private class ReadContactFromSIMCard extends AsyncTask<Object, Object, Object> {
#Override
protected void onPostExecute(Object o) {
super.onPostExecute(o);
requestForContact();
}
#Override
protected Object doInBackground(Object[] params) {
Cursor cursorSim = null;
try {
String phoneNo;
String name;
Uri simUri = Uri.parse("content://icc/adn");
cursorSim = getActivity().getContentResolver().query(simUri, null, null, null, null);
if (cursorSim != null) {
while (cursorSim.moveToNext()) {
name = cursorSim.getString(cursorSim.getColumnIndex("name"));
phoneNo = cursorSim.getString(cursorSim.getColumnIndex("number"));
if (!TextUtils.isEmpty(name)) {
allPhoneNumberName.add(name);
}
if (!TextUtils.isEmpty(phoneNo)) {
phoneNo.replaceAll("\\D", "");
phoneNo.replaceAll("&", "");
if (!TextUtils.isEmpty(phoneNo) && !phoneNo.startsWith(Constants.SP_COUNTRY_CODE)) {
mCountryCodeList.add(Constants.SP_COUNTRY_CODE);
alPhoneNumbers.add(Constants.SP_COUNTRY_CODE + phoneNo);
} else {
mCountryCodeList.add(Constants.SP_COUNTRY_CODE);
alPhoneNumbers.add(phoneNo);
}
}
}
}
} catch (Throwable e) {
CustomLogHandler.printErrorlog(e);
} finally {
if (cursorSim != null) {
cursorSim.close();
}
}
return null;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
getLoaderManager().initLoader(0, null, FindFriendsFragment.this);
}
}
get call log details...
private void getCallDetails() {
StringBuffer sb = new StringBuffer();
Uri contacts = CallLog.Calls.CONTENT_URI;
Cursor managedCursor = this.getContentResolver().query(contacts, null, null, null, null);
int number = managedCursor.getColumnIndex(CallLog.Calls.NUMBER);
int type = managedCursor.getColumnIndex(CallLog.Calls.TYPE);
int date = managedCursor.getColumnIndex(CallLog.Calls.DATE);
int duration = managedCursor.getColumnIndex(CallLog.Calls.DURATION);
sb.append("Call Details :");
while (managedCursor.moveToNext()) {
HashMap rowDataCall = new HashMap<String, String>();
String phNumber = managedCursor.getString(number);
String callType = managedCursor.getString(type);
String callDate = managedCursor.getString(date);
String callDayTime = new Date(Long.valueOf(callDate)).toString();
// long timestamp = convertDateToTimestamp(callDayTime);
String callDuration = managedCursor.getString(duration);
String dir = null;
int dircode = Integer.parseInt(callType);
switch (dircode) {
case CallLog.Calls.OUTGOING_TYPE:
dir = "OUTGOING";
break;
case CallLog.Calls.INCOMING_TYPE:
dir = "INCOMING";
break;
case CallLog.Calls.MISSED_TYPE:
dir = "MISSED";
break;
}
sb.append("\nPhone Number:--- " + phNumber + " \nCall Type:--- " + dir + " \nCall Date:--- " + callDayTime + " \nCall duration in sec :--- " + callDuration);
sb.append("\n----------------------------------");
Uri allCalls = Uri.parse("content://call_log/calls");
Cursor c = managedQuery(allCalls, null, null, null, null);
String id = c.getString(c.getColumnIndex(CallLog.Calls.PHONE_ACCOUNT_ID));
Log.d("sim",id);
}
managedCursor.close();
System.out.println(sb);
}
and i hope you add below permission into android manifest file ..
<uses-permission android:name="android.permission.READ_CALL_LOG" />
Maybe you can get subscription_id by get "Calls.PHONE_ACCOUNT_ID" item, which called "The identifier for the account used to place or receive the call."
And after you get the subscription_id, which is match slot id, for example, slot 0 is subscription_id 0, and slot id 1 is subscription_id 1, then you can getSlotIndex using giveb subid, then you can using this slotid to query calls from this slot or to this slot.
Trying to delete the sent sms from app, when I have tried below code in Lenovo A6000(5.0.2) device
public static void deleteMessage(Context context, String phoneNo, String message) {
try {
Log.d(TAG, "deleteMessage: Deleting SMS from inbox");
Uri uriSms = Uri.parse("content://sms/");
Cursor c = context.getContentResolver().query(uriSms,
new String[]{"_id", "thread_id", "address",
"person", "date", "body"}, null, null, null);
Uri uri = null;
if (c != null && c.moveToFirst()) {
do {
long id = c.getLong(0);
long threadId = c.getLong(1);
String address = c.getString(2);
String body = c.getString(5);
int rowsDeleted = 0;
Log.d(TAG, "Deleting threads: " + threadId);
Log.d(TAG, "deleteMessage: id- "+ id + "" +
" threadId- " + threadId + "" +
" body- " + body + "" +
" rowsDeleted- " + rowsDeleted + "" +
" address- " + address);
if (address.equalsIgnoreCase(phoneNo)
&& body.equalsIgnoreCase(message)) {
ConversationQueryHandler handler = new ConversationQueryHandler(context.getContentResolver(), context);
synchronized (sDeletingThreadsLock) {
Log.v(TAG, "Conversation startDelete sDeletingThreads: " + sDeletingThreads);
if (sDeletingThreads) {
Log.e(TAG, "startDeleteAll already in the middle of a delete", new Exception());
}
sDeletingThreads = true;
uri = ContentUris.withAppendedId(Telephony.Threads.CONTENT_URI, threadId);
String selection = true ? null : "locked=0";
handler.setDeleteToken(0);
handler.startDelete(0, new Long(threadId), uri, selection, null);
}
}
} while (c.moveToNext());
}
} catch (Exception e) {
Log.d(TAG, "deleteMessage: Could not delete SMS from inbox: " + e.getMessage());
}
}
The ConversationQueryHandler sends 1 as a result in case of successful deletion of sms on to onDeletionComplete but this doesn't work in all the devices.
private static Object sDeletingThreadsLock = new Object();
private static boolean sDeletingThreads;
public static class ConversationQueryHandler extends AsyncQueryHandler {
private int mDeleteToken;
private Context mContext;
public ConversationQueryHandler(ContentResolver cr, Context context) {
super(cr);
mContext = context;
}
public void setDeleteToken(int token) {
mDeleteToken = token;
}
/**
* Always call this super method from your overridden onDeleteComplete function.
*/
#Override
protected void onDeleteComplete(int token, Object cookie, int result) {
Log.v(TAG, "Conversation onDeleteComplete token: " + token + " cookie- " + cookie + " result- " + result);
if (token == mDeleteToken) {
// release lock
synchronized (sDeletingThreadsLock) {
sDeletingThreads = false;
sDeletingThreadsLock.notifyAll();
}
}
}
}
I have tested this and found it is failed to delete the sms in all the below devices
Sony Xperia Z1(5.1.1)
Lenovo A200 device (5.1)
Samsung J210F (6.0.1)
As I mentioned earlier I am able to delete sms with the same code in
Lenovo A6000(5.0.2)
Is there a chance I am missing something here, or is this a right way of deleting the sent sms. Thank you for the help in advance.
I am building an app , there is a requirement of notifying app when a new contact added or existing contact gets edited or removed. Although a lot of questions are already available those have answers as well. But my question is little bit different. I am using approach of Content Observer as mentioned below in the code
ContactChangeObserver contactChangeObserver = new ContactChangeObserver(this, new Handler());
getContentResolver().registerContentObserver(ContactsContract.Contacts.CONTENT_URI, true, contactChangeObserver);
and in ContactChangeObserver class I am overriding onChange() method as it was already recommended in many of the post. Code is mentioned below
public class ContactChangeObserver extends ContentObserver {
private Context mContext;
public ContactChangeObserver(Context context, Handler handler) {
super(handler);
mContext = context;
}
#Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
List<ContactsModel> listOfDBContact = new ChildTrackingDB().getAllContacts(ChildTrackingDB.getInstance(mContext));
List<ContactsModel> listOfCellPhoneContact = ContactUtility.readContactDirectoryOfPhone(mContext);
if (listOfCellPhoneContact.size() == listOfDBContact.size()) {
//this is edit case
} else if (listOfCellPhoneContact.size() > listOfDBContact.size()) {
//this is add case
}else {
//this is remove case
}
}
}
I am getting call back of onChange() as expected(in all cases of adding, removing and editing case). As mentioned in above example, I am overriding onChange() that has URI param. And when I get call back i also receive uri as well. my question is that can that uri be useful to only get that contact which got changed or added? The uri I am getting is
content://com.android.contacts
In my example code, if contact is edited and the device has let's suppose more than thousands contacts then it is a very time consuming to iterate over each contact.Or is there any better approach available for the problem.
I've faced a similar kind of problem. First of all the Uri which you are getting in onChange() method is vague. From my previous encounter I can tell, You won't be able to detect which contact got inserted, updated or deleted. So yes it becomes very time-consuming to detect which contact to get and perform Crud.
To answer your second question, I would suggest you to use Set instead of List. Here is a sample class which you might helpful. It's a linear operation and i've tested it with 2-3k+ data. And it performs well.
public class AddressBookObserver extends ContentObserver {
private static final String TAG = "AddressBookObserver";
private static final String FLAG_INSERT = "INSERT";
private static final String FLAG_DELETE = "DELETE";
private long lastTimeOfCall = 0L;
private long lastTimeOfUpdate = 0L;
private long threshold_time = 5000;
private WeakReference<Context> mContextWeakReference;
public AddressBookObserver(Handler handler, Context context) {
super(handler);
this.mContextWeakReference = new WeakReference<Context>(context);
}
#Override
public void onChange(boolean selfChange) {
onChange(selfChange, null);
}
#Override
public void onChange(boolean selfChange, Uri uri) {
Log.d(TAG, "onChange() Address Book Changed!");
lastTimeOfCall = System.currentTimeMillis();
Set<String> phoneBookSet = new HashSet<>();
Set<String> providerSet = new HashSet<>();
if (checkContactPermission() && (lastTimeOfCall - lastTimeOfUpdate > threshold_time) && General.getIsContactListImported(mContextWeakReference.get())) {
lastTimeOfUpdate = System.currentTimeMillis();
phoneBookSet.addAll(getOnlyPhoneNumbers());
providerSet.addAll(getProviderNumbers());
int bookCount = phoneBookSet.size();
int providerCount = providerSet.size();
Log.e(TAG, "onChange: bookCount: " + bookCount + " providerCount: " + providerCount);
if (bookCount > providerCount) {
Log.i(TAG, "onChange() Insert!");
phoneBookSet.removeAll(providerSet);
String val = phoneBookSet.toString().replaceAll("[\\(\\)\\[\\]\\{\\}]", "");
Log.w(TAG, "value to insert: " + val);
//DO Insert Operations
} else if (bookCount < providerCount) {
Log.i(TAG, "onChange() DELETE!");
providerSet.removeAll(phoneBookSet);
String val = providerSet.toString().replaceAll("[\\(\\)\\[\\]\\{\\}]", "");
Log.w(TAG, "value to delete: " + val);
//Do Delete Operations
} else {
Log.i(TAG, "onChange() UPDATE!");
Set<String> tempPhoneBookSet = new HashSet<>();
tempPhoneBookSet.addAll(phoneBookSet);
phoneBookSet.removeAll(providerSet);
String newData = phoneBookSet.toString().replaceAll("[\\(\\)\\[\\]\\{\\}]", "");
Log.e(TAG, "newData: " + newData);
providerSet.removeAll(tempPhoneBookSet);
String deleteData = providerSet.toString().replaceAll("[\\(\\)\\[\\]\\{\\}]", "");
Log.e(TAG, "deleteData: " + deleteData);
if (!newData.equals(deleteData)) {
//DO Update Operations
} else {
Log.i(TAG, "onChange() Nothing to update!");
}
}
} else if (!checkContactPermission()) {
Log.e(TAG, "onChange() Contact Permission not granted!");
} else {
Log.e(TAG, "onChange() Time threshold not reached Or Contacts not imported yet!");
}
}
private boolean checkContactPermission() {
return ContextCompat.checkSelfPermission(mContextWeakReference.get(), Manifest.permission.READ_CONTACTS) == PackageManager.PERMISSION_GRANTED;
}
/**
* Get only phone numbers from device's addressBook
*
* #return - Set of distinct phone numbers
*/
private Set<String> getOnlyPhoneNumbers() {
Log.d(TAG, "getOnlyPhoneNumbers()");
Cursor phones = mContextWeakReference.get().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " ASC");
Set<String> uniquePhoneContacts = new HashSet<>();
while (phones.moveToNext()) {
String name = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)).replaceAll("\\D", "");
String id = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
String photoUri = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_URI));
if (uniquePhoneContacts.add(id + "," + name + "," + photoUri + "," + phoneNumber)) {
Log.w(TAG, "Book#" + id + "," + name + "," + photoUri + "," + phoneNumber);
}
}
phones.close();
return uniquePhoneContacts;
}
/**
* Get all the Contacts from provider which are not deletable
*
* #return - All distinct phone numbers from app's provider
*/
private Set<String> getProviderNumbers() {
Log.d(TAG, "getProviderNumbers()");
Cursor phones = mContextWeakReference.get().getContentResolver().query(MyContactProvider.CONTENT_URI, null, PhoneContactController.COL_IS_DELETABLE + "=?",
new String[]{"0"}, MyContactProvider.COL_CONTACT_ID + " ASC");
Set<String> uniquePhoneContacts = new HashSet<>();
while (phones.moveToNext()) {
String id = phones.getString(phones.getColumnIndex(MyContactProvider.COL_CONTACT_ID));
String name = phones.getString(phones.getColumnIndex(MyContactProvider.COL_NAME));
String phoneNumber = phones.getString(phones.getColumnIndex(MyContactProvider.COL_CONTACT_NO));
String photoUri = phones.getString(phones.getColumnIndex(MyContactProvider.COL_PHOTO_URI));
if (uniquePhoneContacts.add(id + "," + name + "," + photoUri + "," + phoneNumber)) {
Log.w(TAG, "QueryProvider#" + id + "," + name + "," + photoUri + "," + phoneNumber);
}
}
phones.close();
return uniquePhoneContacts;
}
}
I hope this helps.
I get null pointer exception at cursor moveToFirst() when retrieving contacts phone number on Lollipop devices but in other OS version it working fine.
Exception occur at pCur.moveToFirst(); under the getContact() method
please see my code:
public class MyService extends Service {
public static Context mContext;
LinkedHashMap<String, String> name = new LinkedHashMap<String, String>();
HashMap<String, String> contactDetails = new HashMap<String, String>();
HashMap<String, Bitmap> image = new HashMap<String, Bitmap>();
private Cursor pCur, contactsCursor;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
String[] PROJECTION = { Contacts._ID, Contacts.LOOKUP_KEY,
Contacts.DISPLAY_NAME_PRIMARY, Contacts.PHOTO_THUMBNAIL_URI,
Contacts.SORT_KEY_PRIMARY };
String SELECTION = Contacts.DISPLAY_NAME_PRIMARY + "<>''" + " AND "
+ Contacts.IN_VISIBLE_GROUP + "=1" + " AND "
+ Contacts.HAS_PHONE_NUMBER;
String SORT_ORDER = Contacts.SORT_KEY_ALTERNATIVE;
contactsCursor = getContentResolver().query(Contacts.CONTENT_URI,
PROJECTION, SELECTION, null, SORT_ORDER);
StoreCursor.qcursor = contactsCursor;
Log.e("cur", "cur" + StoreCursor.qcursor.getCount());
getContact();
return START_STICKY;
}
private void getContact() {
Log.e("result cursor", "" + contactsCursor.getCount());
String displayName;
String contactId;
contactsCursor.moveToFirst();
do {
displayName = contactsCursor.getString(2);
contactId = contactsCursor.getString(0);
// Log.e("disName & id", displayName + " "+contactId);
pCur = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?",
new String[] { contactId }, null);
String cPN = "";
pCur.moveToFirst(); // NullPointerException occur here.
do {
int phoneType = pCur
.getInt(pCur
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
String phoneNumber = pCur
.getString(pCur
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
switch (phoneType) {
case Phone.TYPE_MOBILE:
cPN = cPN + "(mobile number)" + phoneNumber + "\n";
break;
case Phone.TYPE_HOME:
cPN = cPN + "(home number)" + phoneNumber + "\n";
break;
case Phone.TYPE_WORK:
cPN = cPN + "(work number)" + phoneNumber + "\n";
break;
case Phone.TYPE_OTHER:
cPN = cPN + "(other number)" + phoneNumber + "\n";
break;
default:
break;
}
} while (pCur.moveToNext());
name.put(contactId, displayName);
Log.e("displayName", displayName);
StoreCursor.name = name;
contactDetails.put(contactId, cPN);
StoreCursor.contactDetails = contactDetails;
String photo = contactsCursor.getString(3) + "~";
// Log.e("photo url", photo);
if (photo.length() > 6) {
openPhoto(Long.valueOf(contactId), displayName);
}
} while (contactsCursor.moveToNext());
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
That's an easy one:
If pCur.moveToFirst(); throws a NullPointerException, this means that pCur is null. Since pCur is only set in one place,
pCur = getContentResolver().query(...);
this means that your call to ContentResolver.query returns null.
Now the real question is: Why does ContentResolver.query return null? That's a good question, and I suggest that you ask it as a new question here on SO. Be sure to include all relevant information, i.e.:
which URL are you trying to resolve,
which parameters do you use and where to you get them from,
etc.
Ideally, you should add a minimal complete example to your new question (note that your current code snippet is neither minimal nor complete).