Background
I work on an app that needs to get information of "other contacts" as they appear on the address book page on "Contacts" website of Google:
The problem
The Contacts API is becoming deprecated, and instead we need to use People API.
For this, I use the Java library (here) which makes it easier to reach the various functions.
Sadly, according to the docs (here), querying the list of items from "other contacts" you will get only up to 3 possible fields:
emailAddresses
names
phoneNumbers
Indeed, when using it, that's what I got. I also got fields of "etag" and "resourceName", but that's it. No photos, no cover photos, no nothing else...
The code to do it is very short (after you set everything up) :
val otherContactsResponse =
otherContacts.list().setReadMask("emailAddresses,names,phoneNumbers")
.setPageSize(itemsCountToRequest).setPageToken(nextPageToken).execute()
val result=otherContactsResponse.otherContacts
What I've tried
I tried to see if I can query by "reourceName" (example this one), but it seems that "other contacts" are handled differently than normal ones, so this won't work:
result.forEach { personBasic: Person ->
val test: Person? = peopleService.get(personBasic.resourceName!!)
.setPersonFields(
"addresses,ageRanges,birthdays,coverPhotos,emailAddresses,genders,metadata,names,nicknames,occupations,organizations,phoneNumbers,photos,urls")
.execute()
Log.d("AppLog", "$test")
}
Sadly there is no similar query for "other contacts" part to search (other than here, which gives you again the same 3 fields).
Tried to find if there are other fields that I missed that could be used somewhere else. I don't even know if resourceName or etag are reliable and unique for querying.
Tried to add more fields to the query, despite the docs talking about just 3 fields. Failed, of course...
There is a function called copyOtherContactToMyContactsGroup (here) which seems that it will copy contacts to the main group of contacts. I guess that if I use this and then query the contacts themselves (not just "other contacts"), I could get the needed information. But this is a waste of time and can pollute the user's address book, even temporarily. I would have to make sure I delete the contacts from there right after I add them...
EDIT: tried this too, and while it seems to work, I don't want to use it as it pollutes the address book with contacts that the users hasn't added. Plus I got sometimes an image which is simply the letter of the person with a background. This is the code of it:
result.firstOrNull { !it.names.isNullOrEmpty()&&!it.emailAddresses.isNullOrEmpty() }?.let { person ->
val request =
CopyOtherContactToMyContactsGroupRequest().setCopyMask(
"emailAddresses,names,phoneNumbers")
.setReadMask(
"addresses,ageRanges,birthdays,coverPhotos,emailAddresses,genders,metadata,names,nicknames,occupations,organizations,phoneNumbers,photos,urls")
val copyResult: Person? =
services!!.otherContacts.copyOtherContactToMyContactsGroup(
person.resourceName, request).execute()
Log.d("AppLog", "success $copyResult")
}
Also, this seems to be extremely slow compared to simple queries, and there is no batch operation for it either. In addition, testing it out, I think it can cause various server issues related to quota being reached (about 180 per minute or so).
I think that as the website shows the photos and can show you per-contact information, we should have this API too, no?
I thought that maybe I could create a new group (label) , copy the "other contacts" to there, and then fetch the information from there (as it allows to get more fields), but the docs (here) say that it was possible before, and not anymore:
The only system contact groups that can have members added are contactGroups/myContacts and contactGroups/starred. Other system contact groups are deprecated and can only have contacts removed.
This is a bit better solution (if it worked) as I can remove groups safely without affecting actual contacts.
The question
What's the best way that I should use in order to get all kinds of information (like normal contacts) about each item in the "other contacts" list? Is it possible without copying to the contacts list and without getting "fake" photos (of the contact initial letter) ?
OK so sadly for now I got a workaround.
First I copy the various fields to a new Person object, one for each of the results of the query, then I add them all using a batchCreateContacts (here, max items per batch is ), and then I deleted them all using batchDeleteContacts (here , max items per batch is 500)
Sadly this still pollutes the address book, but it's much faster than what I've found, and it's quite temporary too.
Weird things I've found :
API usage doesn't seem to show the exact same items as on the website. I know because I tried to find names and emails on the website that I've found from the API but it didn't show them. Even weirder: The count of items seems the same between them
Some items just have names, which is weird because: how did they get there?
"Other" contacts are different from "normal" contacts and have less information available, but why is this? I looked into this a little and found the following:
Save contact info when you interact with people
When you interact with people on Google products, you can automatically save their contact info, including names, email addresses, and phone numbers. When this setting is turned on, you'll keep the contact info for:
People you've shared something with, like a document in Drive
People who share content with you, like shared albums in Google Photos
People included in events or groups you're in
I think that these are the "other" contacts that become a sort of staging ground with minimal collected information.
I have also found that, on the Google Contacts web page that whenever I add information to an "other contact," the contact automatically disappears from the "other" section and appears with the regular contacts.
So, from the web interface, it looks like "other" contacts should only have the minimal information such as name, email address and phone numbers and should be promoted to the regular contact list if information is added/updated. This scenario will explain why "other" contacts are treated differently.
If you are seeing "other" contacts with more than the minimal information, maybe that is the problem.
Update: Well, it turns out that any "normal" contact can be hidden in the web interface and all the information is transferred with the contact to the "other contacts" list, so "other" contacts can have more than the minimal information.
This looks like an unintended state of affairs to me.
I've built an application that requires to export 2000 contacts to native Android Contacts. I use contentresolver.applyBatch to make this happen, but if the user logs out I want to delete all of the apps exported contacts. It can occur that the contentresolver is not fully finished with saving the contacts.
My question:
How can I cancel the following opperation?:
resolver.applyBatch(ContactsContract.AUTHORITY, ops);
What I've tried so far:
I've tried to cancel the sync of the contentresolver like this:
ContentResolver.cancelSync(null, ContactsContract.AUTHORITY);
This doesn't work and I'm also not sure about the null value. It says it needs an account to stop syncing it for. But I'm not starting the sync on a specific account so why would it be needed?
What I need?
Something like resolver.stopBatch (a way to stop applying the batch).
Thank you for all your effort reading this.
If I understand the use case, you're syncing in new RawContacts into the device, when a user logs into your app.
If that's the case, you should create a SyncProvider, and have it sync in RawContacts on an account that is tied to your app and package name.
That way, when a user uninstalls your app, the account is automatically removed along with the data you've synced into the device, and when a user logs out of her account, you simply remove the contacts account programatically, which will also remove all data synced to the device.
Read these tutorials on how to create a contacts account, a SyncProvider and use it to sync contacts on your account:
http://blog.udinic.com/2013/04/24/write-your-own-android-authenticator/
http://blog.udinic.com/2013/07/24/write-your-own-android-sync-adapter/
https://developer.android.com/training/sync-adapters/creating-sync-adapter.html
I want to create a Contact Provider so I can populate it from our database and let our business workforce to have all the customer data. That's the "easy" part.
But what I need is to isolate those contacts and avoid them to be cloned disallowing the people to copy/clone them and loosing track of that information.
Is there a way to do that? I haven't found a way to do that and I think the only way is to show the contacts in a custom Contact app. The problem with that solution is that it wouldn't be possible to know who's calling.
Is there a way to do that?
On an Android device, there will be roughly zero lines of code that knows anything about a custom ContentProvider that you create. If you do not want to share data from that provider, do not offer any UI to allow people to share data from that provider, and do not export the provider to third-party apps.
I haven't found a way to do that and I think the only way is to show the contacts in a custom Contact app
You needed to write that anyway. There are ~2 billion Android devices. None of them will have a Contacts-style app that knows anything about some custom ContentProvider that you create.
The problem with that solution is that it wouldn't be possible to know who's calling.
Correct. After all, the devices' call managers do not know anything about your custom ContentProvider.
Now, it could be that by "create a Contact Provider", you really meant "not create a Contact Provider". In this case, the "it" in "I can populate it from our database and let our business workforce to have all the customer data" might mean the standard Android ContactsContract ContentProvider. In this case, the Contacts app and in-call screens and everything else that works with contacts will work with your contacts. However, this is a system-supplied ContentProvider, exported to third-party apps, with documentation and so on. There are thousands of apps, both pre-installed and available via the Play Store and elsewhere, that can work with ContactsContract. You have no means of stopping that, and you have no means of preventing those apps from doing whatever it is that they want with this data.
IOW, you cannot satisfy "I want the Contacts app to have my contacts" and "I do not want the Contacts app to have my contacts" at the same time.
I have a requirement like, I can be able to find the people who are using a particular app from my contacts. It is much similar like Whatsapp contacts syncing.
Whatsapp contacts is so fast & very accurate. What is the logic for it?
I'm not sure of their exact logic, but a way that I have seen it done before is as follows...
Access the phone's contacts (duh)
Get the contact that you want to add as a "friend" in your app.
Cross reference that contact's phone number with the user information that you have stored in your application's database
If that phone number exists in your database of users, then you've got a match and you can process things however you'd like from there.
That's one way of doing it, but I don't know if that's exactly how WhatsApp does it. Hope this helps!
I want to let my app scan the users contactlist , and display the name of the contacts who also installed the app.
I have no idea where to begin with this . so if someone could help me getting started , that would be apreciated.
grtz
You will need to research ContentResolver because you will have to query the database containing the contacts. To do these queries, you will need the URI and column/header names for contacts db which can be found in the Contacts class.
You will also need users to register that they have your app on your own servers and the registration will need a piece of information about the user that other users would have in their contacts (the users phone number, email address, etc).
You will then need to query a few users at a time from the users contacts for this piece of information (using the ContentResolver and Contacts class), pass it to your server (as text) where it will check if they are registered, then send a message back to initial user (and possibly the match) that you found a match.
That's where you should start, and end :)
Note, you will need these permissions in the Manifest file:
android.permission.INTERNET
android.permission.READ_CONTACTS
First of all, welcome to StackOverflow. StackOverflow is for programming questions. As is such, a post asking for help should always provide a description of what you have already tried. If you haven't tried anything yet, I highly encourage you to try something, and post when you encounter a problem.
As your question stands now, we don't know what the problem is. Are you having problems scanning a contact list? Or are you having problems trying to figure out if another user has installed the app?
That being said, you will have to maintain a database for your app containing a list of people who have installed your app. When your app is launched on one device, do whatever you need to do to register the user in your database. Due to the nature of a "contact," one person's phone may only have their phone number, email address, or even just a name. This is of course something you will have to deal with in your implementation.