I am currently working on a project in which I want to access the mobile contacts, So I have managed to create account with accountmanager and also able to perform Syncadapter operation. I could see my account got created in the mobile settings->Accounts. However, when I try to get all the contacts with my account with below code ,it does not work. Its showing all apps(google.com and WhatsApp.com) contacts except my app account contacts.
Cursor cursor = getContext().getContentResolver().query(ContactsContract.RawContacts.CONTENT_URI,
new String[]{ContactsContract.RawContacts.DIRTY, ContactsContract.RawContacts.ACCOUNT_TYPE},
null,
null,
null);
if (cursor != null && cursor.getCount() >0) {
cursor.moveToFirst();
while(!cursor.isAfterLast()) {
Log.d("Dirty",cursor.getString(cursor.getColumnIndex(ContactsContract.RawContacts.DIRTY)));
Log.d("ACCountType",cursor.getString(cursor.getColumnIndex(ContactsContract.RawContacts.ACCOUNT_TYPE)));
cursor.moveToNext();
}
cursor.close();
}
What I dont understand is do I need to create ContentProvider and insert all contacts back to Contactsprovider on behalf of my account?
Not sure if you've fully understood how the ContactsProvider works.
There are a few things that you should know:
Every RawContact is uniquely assigned to one specific account, it can not belong to more than one account (hence your app usually can't sync existing contacts, because they already have an account).
All apps have the same view on all the contacts, in particular all apps can see and modify all contacts (given they have the permissions), though there are a few exceptions to that rule.
When you sync a contact to your account you must specify your account as shown on ContactsContract.RawContacts
ContentValues values = new ContentValues();
values.put(RawContacts.ACCOUNT_TYPE, accountType);
values.put(RawContacts.ACCOUNT_NAME, accountName);
Uri rawContactUri = getContentResolver().insert(RawContacts.CONTENT_URI, values);
long rawContactId = ContentUris.parseId(rawContactUri);
When you read contacts you get contacts of all accounts, unless you specify Uri query parameters or a selection:
Uri rawContactUri = RawContacts.CONTENT_URI.buildUpon()
.appendQueryParameter(RawContacts.ACCOUNT_NAME, accountName)
.appendQueryParameter(RawContacts.ACCOUNT_TYPE, accountType)
.build();
Cursor c1 = getContentResolver().query(rawContactUri,
RawContacts.STARRED + "<>0", null, null, null)
This query returns all starred contacts of the specified account.
If your code operates as a sync adapter you also have to add the Uri query parameter CALLER_IS_SYNC_ADAPTER, otherwise you may get different results for many operations.
Related
How to retrieve all the work profile contacts from cursor using android.
Please update cursor URI formation here using ENTERPRISE_CONTENT_FILTER_URI
I can search any contact in work profile using the below piece of code, but am looking for to get all the work profile contacts instead of search behavior
Reference the below piece of code for search contact in work profile.
// Build the URI to look up work profile contacts whose name matches. Query
// the default work profile directory which is the locally stored contacts.
Uri contentFilterUri = ContactsContract.Contacts.ENTERPRISE_CONTENT_FILTER_URI
.buildUpon()
.appendPath(nameQuery)
.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
String.valueOf(ContactsContract.Directory.ENTERPRISE_DEFAULT))
.build();
// Query the content provider using the generated URI.
Cursor cursor = getContentResolver().query(
contentFilterUri,
new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.LOOKUP_KEY,
ContactsContract.Contacts.DISPLAY_NAME_PRIMARY
},
null,
null,
null);
if (cursor == null) {
return;
}
// Print any results found using the work profile contacts' display name.
try {
while (cursor.moveToNext()) {
Log.i(TAG, "Work profile contact: " + cursor.getString(2));
}
} finally {
cursor.close();
}
Let me know how to retrieve all the contacts info(Name/phone/profile pic url) from work profile.
This is not supported by the API by design.
Consider an organization with thousands of employees, on an old, budget phone.
That might choke the little phone's memory.
So instead the API allows organizations to implement a fetch of certain employees based on search.
To get the entire list, you can just brute force that API, searching all possible name prefixes, and storing all the results. Just make sure you don't crash your app if it runs on organizations with many employees.
I am working on a requirement, where I need to identify all Google's contact saved/synced with Android device's phonebook. Then I have to fetch unique contact Id (Google's unique contact id)of each contact which will be same on other devices and other platform.
I have read Android developer's documentation regarding RAW_CONTACT_ID. Also, tried to get raw contact id, but I am getting different value of raw contact id on other devices.
If anyone can put me on right direction, it will really helpful.
If require more information, please ask.
Try using ContactsContract.PhoneLookup
A table that represents the result of looking up a phone number, for example for caller ID. To perform a lookup you must append the number you want to find to CONTENT_FILTER_URI. This query is highly optimized.
Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
resolver.query(uri, new String[]{PhoneLookup.DISPLAY_NAME,...
where
PhoneLookup._ID
is what you're looking for.
You may also try the solution provided in this post:
public static int getContactIDFromNumber(String contactNumber,Context context)
{
contactNumber = Uri.encode(contactNumber);
int phoneContactID = new Random().nextInt();
Cursor contactLookupCursor = context.getContentResolver().query(Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI,contactNumber),new String[] {PhoneLookup.DISPLAY_NAME, PhoneLookup._ID}, null, null, null);
while(contactLookupCursor.moveToNext()){
phoneContactID = contactLookupCursor.getInt(contactLookupCursor.getColumnIndexOrThrow(PhoneLookup._ID));
}
contactLookupCursor.close();
return phoneContactID;
}
All _ID values in Android's Contacts are local, they are usually incremental, and are not synced between devices.
The values that might get synced by the app's SyncAdapter (in this case Google's SyncAdapter) are SYNC1, SYNC2, SYNC3, SYNC4.
However, note that these fields are not guaranteed to do anything, and the SyncAdapter may use them for whatever purpose it needs, usually, one of them is used as a "server identifier" you just need to print them, and check manually which one.
If a SyncAdapter A for Account A creates a raw contact in the ContactsContract.RawContacts table, can SyncAdapter B for Account B update the RawContact added by SyncAdapter A.
Of particular interest is the sync1 or any of the sync fields in the raw contacts table?
If this is possible what are the possible issues that might arise as a result.
Can anyone show a sample of how this should be done?
There's no per-contact-permission-model on the Contacts DB, every app and every SyncAdapter with the Contacts permission can read/write to any field in any contact.
However, the syncX fields under RawContact are used for proprietary purposes by the owning SyncAdapter (e.g. to keep track on what contact requires syncing, which one is dirty, when was it last synced, the backend-contact-id value, etc.), so make sure you don't touch anything you don't know what it's for, or you might risk corrupting some contacts.
To modify the Sync1 value on RawContact with id 1234, do:
ContentResolver cr = context.getContentResolver();
ContentValues values = new ContentValues(2);
values.put(RawContacts.SYNC1, "Hello World");
cr.update(RawContacts.CONTENT_URI, values, RawContacts._ID + "=" + 1234, null);
UPDATE - batch updates
ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
ops.add(ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
.withSelection(RawContacts._ID + "=" + 1234, null)
.withValue(RawContacts.SYNC1, "Hello")
.build());
ops.add(ContentProviderOperation.newUpdate(RawContacts.CONTENT_URI)
.withSelection(RawContacts._ID + "=" + 5678, null)
.withValue(RawContacts.SYNC1, "World")
.build());
getContentResolver().applyBatch(ContactsContract.AUTHORITY, ops);
I want to retrive all the contact from phone book that has facebook account.
Steps i did
I got contact id from Contacts.
Based on id get Accounts from RawContact table.
All account associated with contact found but facebook account not found.
You can follow below algorithm to get contacts with specific account type.
1. First, query on raw contacts table and find all raw contacts. Check what are different Account type and Account name are available. http://developer.android.com/reference/android/provider/ContactsContract.SyncColumns.html#ACCOUNT_TYPE
Facebook contact will have account type with text "facebook" in it.
2. Once you got exact account type, you can query on raw contacts with account type = facebook.
3. This will give all Facebook raw contacts. Raw contact table has contact_id field using which you can query on Contacts table to get all Facebook contacts.
Below is the code snippet which can print all account names and types which are currently configured on device for which contacts are present. This is just Sample code to check what all account types are there. If you don't find any account name/type related to facebook, I guess there are no facebook contacts present.
String[] projection = { RawContacts._ID, RawContacts.ACCOUNT_TYPE,
RawContacts.ACCOUNT_NAME };
Cursor cur = cr.query(RawContacts.CONTENT_URI, projection, null, null,
null);
if (cur != null) {
while (cur.moveToNext()) {
long rawContactId = cur.getLong(cur
.getColumnIndexOrThrow(RawContacts._ID));
String accountType = cur.getString(cur
.getColumnIndexOrThrow(RawContacts.ACCOUNT_TYPE));
String accountName = cur.getString(cur
.getColumnIndexOrThrow(RawContacts.ACCOUNT_NAME));
}
}
My problem is that I try to disallow to native Android Contacts application to delete my application's contacts (which are specified by my application account type) from device.
For that I've specified my own SyncAdapter with it's own Service and it's meta-data described in syncadapter.xml. The value of supportsUploading is set to false (this way I say that contacts created by my application are read-only)
However, when I try to delete a contact of my application from standard Contacts app I get the message which says:
You can't delete contacts from read-only accounts, but you can hide
them in your contacts list
Everything seems fine until I try to get data of the contact which I previously deleted ("hide") from standard "Contacts" in my own application.
The returned cursor is null because there isn't any row in Data table associated with this contact's RAW_CONTACT_ID. I also check if the contact exists on the device looking for
it's DELETED flag value in RawContacts table and observed that it has been set to 1 which means that contact has been deleted.
As official documentation describes:
Some sync adapters are read-only, meaning that they only sync
server-side changes to the phone, but not the reverse. If one of those
raw contacts is marked for deletion, it will remain on the phone.
However it will be effectively invisible, because it will not be part
of any aggregate contact.
So the problem is that I can't display this contact's data in my application any more because I don't know how to retrieve them from contacts database. If somebody knows how to handle this situation I would appreciate any advice. Thanks
So after more meticulous search I found the way to retrieve data for any RAW_CONTACT in my application independently of was it deleted from some other application or not.
Using of RawContacts.Entity API does this job.
Previously I tried to retrieve contact's data using such logic:
public Cursor getContactData(long rawContactId) {
return getContentResolver().query(ContactsContract.Data.CONTENT_URI, null,
ContactsContract.Data.RAW_CONTACT_ID + "=" + rawContactId, null);
}
And this method always returned null for deleted contact.
But using RawContacts.Entity such way:
public Cursor getContactData(long rawContactId) {
Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, id);
rawContactUri = Uri.withAppendedPath(rawContactUri, RawContacts.Entity.CONTENT_DIRECTORY);
return getResolver().query(rawContactUri, null, null, null);
}
allows to fetch contact's data inside application with appropriate authority regardless was it deleted by 3d-party application or not.