How can I update the phone numbers of contacts in Android Studios - java

I am new to developing apps with android studio, and I decided to make an app to edit the phone numbers of my phone contacts as my first test app.
I use a class to get information about all the contacts that I have on my cell phone, then I have created a listview where I show the contact's name, ID, avatar and registered phone numbers.
The information has been gotten from the ContactsContract.Contacts table. This all works fine, so far.
But now I have to edit the phone numbers of all the contacts, but I don't know exactly how to do it. I've been going through the Android devs documentation but I can't get anything that can help me. I don't want to use Intent in this case.
I have this kotlin class that I use to get the information of all contacts is this:
#file:Suppress("unused")
package com.example.uimx
import android.Manifest
import android.content.ContentUris
import android.content.Context
import android.net.Uri
import android.provider.ContactsContract
import androidx.annotation.RequiresPermission
#RequiresPermission(Manifest.permission.READ_CONTACTS)
fun Context.isContactExists(
phoneNumber: String
): Boolean {
val lookupUri = Uri.withAppendedPath(
ContactsContract.PhoneLookup.CONTENT_FILTER_URI,
Uri.encode(phoneNumber)
)
val projection = arrayOf(
ContactsContract.PhoneLookup._ID,
ContactsContract.PhoneLookup.NUMBER,
ContactsContract.PhoneLookup.DISPLAY_NAME
)
contentResolver.query(lookupUri, projection, null, null, null).use {
return (it?.moveToFirst() == true)
}
}
#RequiresPermission(Manifest.permission.READ_CONTACTS)
#JvmOverloads
fun Context.retrieveAllContacts(
searchPattern: String = "",
retrieveAvatar: Boolean = true,
limit: Int = -1,
offset: Int = -1
): List<ContactData> {
val result: MutableList<ContactData> = mutableListOf()
contentResolver.query(
ContactsContract.Contacts.CONTENT_URI,
CONTACT_PROJECTION,
if (searchPattern.isNotBlank()) "${ContactsContract.Contacts.DISPLAY_NAME_PRIMARY} LIKE '%?%'" else null,
if (searchPattern.isNotBlank()) arrayOf(searchPattern) else null,
if (limit > 0 && offset > -1) "${ContactsContract.Contacts.DISPLAY_NAME_PRIMARY} ASC LIMIT $limit OFFSET $offset"
else ContactsContract.Contacts.DISPLAY_NAME_PRIMARY + " ASC"
)?.use {
if (it.moveToFirst()) {
do {
val contactId = it.getLong(it.getColumnIndex(CONTACT_PROJECTION[0]))
val name = it.getString(it.getColumnIndex(CONTACT_PROJECTION[2])) ?: ""
val hasPhoneNumber = it.getString(it.getColumnIndex(CONTACT_PROJECTION[3])).toInt()
val phoneNumber: List<String> = if (hasPhoneNumber > 0) {
retrievePhoneNumber(contactId)
} else mutableListOf()
val avatar = if (retrieveAvatar) retrieveAvatar(contactId) else null
result.add(ContactData(contactId, name, phoneNumber, avatar))
} while (it.moveToNext())
}
}
return result
}
private fun Context.retrievePhoneNumber(contactId: Long): List<String> {
val result: MutableList<String> = mutableListOf()
contentResolver.query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
"${ContactsContract.CommonDataKinds.Phone.CONTACT_ID} =?",
arrayOf(contactId.toString()),
null
)?.use {
if (it.moveToFirst()) {
do {
result.add(it.getString(it.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)))
} while (it.moveToNext())
}
}
return result
}
private fun Context.retrieveAvatar(contactId: Long): Uri? {
return contentResolver.query(
ContactsContract.Data.CONTENT_URI,
null,
"${ContactsContract.Data.CONTACT_ID} =? AND ${ContactsContract.Data.MIMETYPE} = '${ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE}'",
arrayOf(contactId.toString()),
null
)?.use {
if (it.moveToFirst()) {
val contactUri = ContentUris.withAppendedId(
ContactsContract.Contacts.CONTENT_URI,
contactId
)
Uri.withAppendedPath(
contactUri,
ContactsContract.Contacts.Photo.CONTENT_DIRECTORY
)
} else null
}
}
private val CONTACT_PROJECTION = arrayOf(
ContactsContract.Contacts._ID,
ContactsContract.Contacts.LOOKUP_KEY,
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY,
ContactsContract.Contacts.HAS_PHONE_NUMBER
)
data class ContactData(
val contactId: Long,
val name: String,
val phoneNumber: List<String>,
val avatar: Uri?
)
I have a button prepared that receives the click event and calls a function that would have the script to replace all the phone numbers of all the contacts, for new phone numbers that I will define for each contact.
I have this next code that I got on the internet but I can't get it to work in my app.
private int updateContactPhoneByID(long rawContactId)
{
int ret = 0;
ContentResolver contentResolver = getContentResolver();
// Update data table phone number use contact raw contact id.
if(rawContactId > -1) {
// Update mobile phone number.
updatePhoneNumber(contentResolver, rawContactId, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE, "66666666666666");
// Update work mobile phone number.
updatePhoneNumber(contentResolver, rawContactId, ContactsContract.CommonDataKinds.Phone.TYPE_WORK_MOBILE, "8888888888888888");
// Update home phone number.
updatePhoneNumber(contentResolver, rawContactId, ContactsContract.CommonDataKinds.Phone.TYPE_HOME, "99999999999999999");
ret = 1;
}else
{
ret = 0;
}
return ret;
}
/* Update phone number with raw contact id and phone type.*/
private void updatePhoneNumber(ContentResolver contentResolver, long rawContactId, int phoneType, String newPhoneNumber)
{
// Create content values object.
ContentValues contentValues = new ContentValues();
// Put new phone number value.
contentValues.put(ContactsContract.CommonDataKinds.Phone.NUMBER, newPhoneNumber);
// Create query condition, query with the raw contact id.
StringBuffer whereClauseBuf = new StringBuffer();
// Specify the update contact id.
whereClauseBuf.append(ContactsContract.Data.RAW_CONTACT_ID);
whereClauseBuf.append("=");
whereClauseBuf.append(rawContactId);
// Specify the row data mimetype to phone mimetype( vnd.android.cursor.item/phone_v2 )
whereClauseBuf.append(" and ");
whereClauseBuf.append(ContactsContract.Data.MIMETYPE);
whereClauseBuf.append(" = '");
String mimetype = ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE;
whereClauseBuf.append(mimetype);
whereClauseBuf.append("'");
// Specify phone type.
whereClauseBuf.append(" and ");
whereClauseBuf.append(ContactsContract.CommonDataKinds.Phone.TYPE);
whereClauseBuf.append(" = ");
whereClauseBuf.append(phoneType);
// Update phone info through Data uri.Otherwise it may throw java.lang.UnsupportedOperationException.
Uri dataUri = ContactsContract.Data.CONTENT_URI;
// Get update data count.
int updateCount = contentResolver.update(dataUri, contentValues, whereClauseBuf.toString(), null);
}
How to make the above script work to update the correct contact table with the information I have.

I think you have a confusion about contactId and rawContactId.
When you read all the contacts from the device, you're getting the contactId of that contact, but the updateContactPhoneByID method you're trying to use is expecting a rawContactId which is different.
In a nutshell, every Contact in the ContactsContract.Contacts table is comprised out of multiple RawContacts each is usually synced by some different app or account (e.g. one RawContact from your personal Google account, another RawContact from your work Google account, another one from Whatsapp, and one from Yahoo), the details from ALL these RawContacts are join to make up a single contact profile.
I'm not sure how you want the edit to work, if a contact has multiple phone numbers, do you want to replace ALL those phones with a single new phone number, or do you allow the user to type multiple phones in your edit screen?
Anyway, here's a small kotlin function that takes a contactId and an existing phone number X and replaces that single number with a new one.
I hope you can adapt it to your needs.
private fun updatePhone(contactId:Long, existingNumber:String, newNumber:String) {
val contentValues = ContentValues()
contentValues.put(Phone.NUMBER, newNumber)
val where = Data.CONTACT_ID + "=?" + " AND " + Data.MIMETYPE + "=?" + " AND " + Phone.NUMBER + "=?"
val whereArgs = arrayOf<String>((contactId).toString(), Phone.CONTENT_ITEM_TYPE, existingNumber)
contentResolver.update(Data.CONTENT_URI, contentValues, where, whereArgs)
}
Note that the existingNumber param must match the string in the ContactsContract DB exactly.

Related

How to fetch Video File Paths From Android Tv Internal and Sd Card Storage...?

I am using following code to fetch video file paths that is available on Android offical documentation..
fun getAllVideosPath(context: Context) {
val videoList = mutableListOf<VideoInfo>()
val collection =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
MediaStore.Video.Media.getContentUri(
MediaStore.VOLUME_EXTERNAL
)
} else {
MediaStore.Video.Media.EXTERNAL_CONTENT_URI
}
val projection = arrayOf(
MediaStore.Video.Media._ID,
MediaStore.Video.Media.DISPLAY_NAME,
MediaStore.Video.Media.DURATION,
MediaStore.Video.Media.SIZE
)
// Show only videos that are at least 5 minutes in duration.
val selection = "${MediaStore.Video.Media.DURATION} >= ?"
val selectionArgs = arrayOf(
TimeUnit.MILLISECONDS.convert(1, TimeUnit.SECONDS).toString()
)
// Display videos in alphabetical order based on their display name.
val sortOrder = "${MediaStore.Video.Media.DISPLAY_NAME} ASC"
val query =
context.contentResolver.query(collection, projection, selection, selectionArgs, sortOrder)
query?.use { cursor ->
// Cache column indices.
val idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID)
val nameColumn =
cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME)
val durationColumn =
cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION)
val sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE)
Log.i("CursorSize", "${cursor.position}")
while (cursor.moveToNext()) {
// Get values of columns for a given video.
val id = cursor.getLong(idColumn)
val name = cursor.getString(nameColumn)
val duration = cursor.getInt(durationColumn)
val size = cursor.getInt(sizeColumn)
val contentUri: Uri = ContentUris.withAppendedId(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
id
)
// Stores column values and the contentUri in a local object
// that represents the media file.
videoList += VideoInfo(contentUri, name, duration, size)
Log.i("asdsa", name)
}
}
}
I am getting file paths on android mobile using this Up to Android 12 but unable to get paths on Andorid tv. Is i am missing some thing or there is some other way to get file paths on android tv...?

Passing phone number or CONTACT_ID from android contact details to activity (whatsapp like)

What I'm trying to achieve is to add shortcut to my app in android book contact details, similar to what whatsapp is doing.
I've been following this tutotial: http://blogs.quovantis.com/syncing-contacts-with-an-android-application-2/ and it works well but the author doesn't show how to pass data from contact details to ViewingActivity: https://github.com/ajkh35/ContactsDemo/blob/master/app/src/main/java/com/example/ajay/contacts_4/ViewingActivity.java
There was some comments below the article but no specific answer from the author, can't find anything useful in
Uri data = getIntent().getData(); //content://com.android.contacts/data/1169
List<String> params = data.getPathSegments();
String first = params.get(0);
String second = params.get(1);
there is some number passed in second param but it's not CONTACT_ID or RAW_CONTACT_ID. Any help?
Ok, so it seems the Uri you're getting from the Contacts app is a Data uri.
Data rows contain info about a specific data-item (like a phone number or an email) of a specific RawContact, so a single Data row "belongs" to a single RawContact which "belongs" to a single Contact.
Luckily, the ContactsContract API allows for implicit joins when querying the Data table, so you can do something like this:
Uri dataUri = getIntent().getData(); //content://com.android.contacts/data/1169
String[] projection = new String[]{
Data.CONTACT_ID,
Data.RAW_CONTACT_ID,
Data.DISPLAY_NAME,
Data.MIMETYPE,
Data.DATA1};
Cursor cur = getContentResolver().query(dataUri, projection, null, null, null);
cur.moveToFirst(); // there should always be exactly one result, since we have a specific data uri here
Log.i("Contact Info", "Got info: id=" + cur.getLong(0) + ", raw-id=" + cur.getLong(1) + ", " + cur.getString(2) + ", " + cur.getString(3) + ", " + cur.getString(4));
cur.close();
I know this is a very late response but checkout the following code.
class MessageActivity : AppCompatActivity() {
private val TAG: String = javaClass.simpleName
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_message)
if(intent != null && intent.data != null) {
Log.e(TAG, intent.data.toString())
var contactName = ""
val cursor = contentResolver.query(intent.data!!,
arrayOf(ContactsContract.Data.DATA1,ContactsContract.Data.DATA2,ContactsContract.Data.DATA3),
null,null,null)
if(cursor != null && cursor.moveToFirst()) {
do{
Log.e(TAG, cursor.getString(cursor
.getColumnIndexOrThrow(ContactsContract.Data.DATA1)))
contactName = cursor.getString(cursor
.getColumnIndexOrThrow(ContactsContract.Data.DATA2))
Log.e(TAG, contactName)
Log.e(TAG, cursor.getString(cursor
.getColumnIndexOrThrow(ContactsContract.Data.DATA3)))
}while (cursor.moveToNext())
cursor.close()
}
messaging_text.text = getString(R.string.messaging) + " $contactName"
}
}}
So when you register a contact you set some Data1, Data2 and Data3 values. Data3 is what gets displayed in the contacts. You can set Data1 and Data2 some value you like and then retrieve it like in the code I mentioned above.
You can also checkout my blog here. Look for the "Sync Service" section, towards the end you will find the MessageActivity.
Thanks & regards

How to find and prefix all phone number in Contacts Android?

Sorry for the bad english!
I want to scan all contacts 's phone number and prefix them. However my code is not useful. It missed a lot of phone numbers when reading contacts. Help me plz!
`
String[] columns = {ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.HAS_PHONE_NUMBER};
ContentResolver cr =getContentResolver();
Cursor cursor=cr.query(ContactsContract.Contacts.CONTENT_URI, columns,null,null,null);
cursor.moveToFirst();
while(cursor.moveToNext())
{
String contactId = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
if(!(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER)).endsWith("0")) )
{
Cursor phones = cr.query( ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = " + contactId, null, null);
if(phones.getCount() > 0)
while (phones.moveToNext())
{
String number = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)).replaceAll("[ \\-().]", ""); //this is phone number
int type = phones.getInt(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.TYPE));
String idIndex = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID));
switch (type)
{
case ContactsContract.CommonDataKinds.Phone.TYPE_HOME:
//prefix number function and write contacts here.
break;
case ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE:
//prefix number function and write contacts here.
break;
case ContactsContract.CommonDataKinds.Phone.TYPE_WORK:
//prefix number function and write contacts here.
break;
//some other type here...
}
}
phones.close();
}
}
cursor.close();`
No need for a loop-within-loop here, just one query that goes over all numbers in the Contacts DB:
String[] projection = new String[] { Phone.NUMBER, Phone.TYPE, Phone._ID };
Cursor phones = cr.query(Phone.CONTENT_URI, null, null, null, null);
while (phones.moveToNext()) {
String number = phones.getString(0).replaceAll("[ \\-().]", ""); //you can instead use Phone.NORMALIZED_NUMBER if you're using a high-enough API level
int type = phones.getInt(1);
long id = cursor.getLong(2);
Log.v("LOG", "got phone: " + id + ", " + number + ", " + type);
prefixNumber(id, number, type);
}
phones.close();
`sssss
public void updatePhoneNumber(ContentResolver contentResolver, long rawContactId, int phoneType, String PhoneNumber) {
// Create content values object.
ContentValues contentValues = new ContentValues();
// Put new phone number value.
contentValues.put(ContactsContract.CommonDataKinds.Phone.NUMBER, PhoneNumber);
// Create query condition, query with the raw contact id.
StringBuffer whereClauseBuf = new StringBuffer();
// Specify the update contact id.
whereClauseBuf.append(ContactsContract.Data.RAW_CONTACT_ID);
whereClauseBuf.append("=");
whereClauseBuf.append(rawContactId);
// Specify the row data mimetype to phone mimetype( vnd.android.cursor.item/phone_v2 )
whereClauseBuf.append(" and ");
whereClauseBuf.append(ContactsContract.Data.MIMETYPE);
whereClauseBuf.append(" = '");
String mimetype = ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE;
whereClauseBuf.append(mimetype);
whereClauseBuf.append("'");
// Specify phone type.
whereClauseBuf.append(" and ");
whereClauseBuf.append(ContactsContract.CommonDataKinds.Phone.TYPE);
whereClauseBuf.append(" = ");
whereClauseBuf.append(phoneType);
// Update phone info through Data uri.Otherwise it may throw java.lang.UnsupportedOperationException.
Uri dataUri = ContactsContract.Data.CONTENT_URI;
// Get update data count.
int updateCount = contentResolver.update(dataUri, contentValues, whereClauseBuf.toString(), null);
}`

How to get the phone contacts in a hashmap and store it locally and use it anywhere in the project?

I am trying to get the phone contacts and store it in a Hashmap. I want to save that locally and use it anywhere in the project.
Following is my code to get phone contacts:
public HashMap getPhoneContacts() {
ArrayList contactList=null;
ContentResolver cr = getContext().getContentResolver(); //Activity/Application android.content.Context
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null
, null, null, null);
if(cursor.moveToFirst())
{
contactList = new ArrayList<String>();
do
{
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
String contactName=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
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 contactId = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
String noramliseNum;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
noramliseNum = PhoneNumberUtils.normalizeNumber(contactNumber);
}else{
noramliseNum=contactNumber.replaceAll("\\s","");
}
phoneContacts.put(noramliseNum,contactName);
break;
}
pCur.close();
}
} while (cursor.moveToNext()) ;
}
return phoneContacts;
}
Its already taking lot of time to fetch all the contacts. So I dont want to call this function again and again from other classes. Instead I need to call the function only once,and then store it in a Hashmap locally and use it whenever we want,so that it wont take time to fetch the details again.
Please help.
You could put it into SharedPreferences if you don't want to re-download every time you start the app. Then, once the data is retreived, you could have a Singleton class to hold your Hashmap.
If you have many contacts, you should consider using a database.
Take a look at https://developer.android.com/guide/topics/data/data-storage.html
This would be more efficient than keeping everything in memory.

Retrieving a phone number with ContactsContract in Android - function doesn't work

I wrote the following function in order to retrieve one single phone number that belongs to the contact with id "contactID".
The function which is to retrieve the phone number:
private String getContactPhone(String contactID) {
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String[] projection = null;
String where = ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?";
String[] selectionArgs = new String[] { contactID };
String sortOrder = null;
Cursor result = managedQuery(uri, projection, where, selectionArgs, sortOrder);
if (result.moveToFirst()) {
String phone = result.getString(result.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
if (phone == null) {
result.close();
return null;
}
result.close();
return phone;
}
result.close();
return null;
}
How this function is called:
ArrayList<Contact> resultContacts = new ArrayList<Contact>();
Cursor result = null;
Uri uri = ContactsContract.Data.CONTENT_URI;
String[] projection = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Event.CONTACT_ID,
ContactsContract.CommonDataKinds.Event.START_DATE,
};
String where = ContactsContract.Data.MIMETYPE+" = ? AND "+ContactsContract.CommonDataKinds.Event.TYPE+" = "+ContactsContract.CommonDataKinds.Event.TYPE_BIRTHDAY;
String[] selectionArgs = new String[] {ContactsContract.CommonDataKinds.Event.CONTENT_ITEM_TYPE};
String sortOrder = null;
result = managedQuery(uri, projection, where, selectionArgs, sortOrder);
while (result.moveToNext()) {
Long id = result.getLong(result.getColumnIndex(ContactsContract.Contacts._ID));
String phone = getContactPhone(String.valueOf(id));
...
}
...
Unfortunately, it doesn't work. I get null if I call this function with the value that I got from "ContactsContract.Contacts._ID". Why is this so? What is wrong?
Edit: I used to map Contacts._ID to CommonDataKinds.Phone.CONTACT_ID - which didn't work. But now I map Contacts.DISPLAY_NAME to CommonDataKinds.Phone.DISPLAY_NAME and it works suddenly - strange, isn't it? But I would rather like to map the IDs instead of the display names. So the question is still topical. Could this be due to different IDs in those tables? Isn't this why there are lookup IDs?
To get the contact id in the first part, you should use:
ContactsContract.Data.CONTACT_ID
instead of:
ContactsContract.Contacts._ID
So the projection should be:
String[] projection = new String[] {
ContactsContract.Data.CONTACT_ID,
ContactsContract.CommonDataKinds.Event.CONTACT_ID,
ContactsContract.CommonDataKinds.Event.START_DATE,
};
And then of course get the correct row:
Long id = result.getLong(result.getColumnIndex(ContactsContract.Data.CONTACT_ID));
You are getting null because you have set your projection to null. The projection is basically the list of columns that you want returned e.g.
String[] projection = {ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.HAS_PHONE_NUMBER};
Usually, when you find the contact, they may have a list of phone numbers, so you have to use another cursor to iterate through the phone numbers, e.g.
Cursor phones = mContext.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ contactId, null, null);
while (phones.moveToNext())
{
phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DATA));
}
Hope this helps.
Your code for getContactPhone() works fine on my end. I tested by launching a contact picker, selecting a contact, then using the ID that was returned and passed that into your method.
So I suspect you are indeed passing in an invalid ID. Can you post the full stack trace for the null pointer exception?
Yes, lookup keys are available because _IDs are not guaranteed to stay the same since syncs and contact aggregation changes them.

Categories