Android contacts accounts - android

I need to add new contacts dynamically from my application.
I list all the phone accounts with the AccountManager getAccounts method but I get accounts like weather, stock, etc.
How can I get only contact accounts ?

There's actually no good way to do this by using the API, the method we found to be most accurate was to think backwards: which accounts are used for storing contacts?
It's a bit crude, but it gives pretty good results (cache the list and you don't need to do it every time).
// Pseudo-code
for contact in RawContacts
uniqueAccountTypes.put(contact.account)
for accountType in uniqueAccountTypes
uniqueAccountsWithContacts.putAll(accountManager.getAccountsByType(accountType))
I don't have access a copy of the contacts database right now, so the code above might be slightly off, but the concept should be clear. Let me know if I should clarify further.

Had a similar situation.
After a little search found this method of AccountManager:
getAccountsByTypeAndFeatures();
here if you set parameter features as "service_mail" , "service_talk" etc, you will get accounts supporting e-mail and chat, hence these accounts will support contacts also.
UPDATE
"service_ah" will give the account device is linked to.

Related

How to get full information about "other contacts" using People API?

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.

Sync contacts firebase

I'm developing a feature in my app to help users find friends who are registered and are in the contact list on the phone. Something like what instagram does here:
Does firebase have any way to synchronize and compare contacts? I think that comparing each phone contact with each database contact will not be very efficient in terms of performance.
Does firebase have any way to synchronize and compare contacts?
It does not. You should create your own system for that.
I think that comparing each phone contact with each database contact will not be very efficient in terms of performance.
Is not. In fact, is quite simple and efficient since Firebase SDK provides a method that can help you simply verify if a user exist or not in the database, this method is called exists().
For more informations, please also see my answer from this post.

How to change ACCOUNT_TYPE field for specific, existing, contact to one of Google, and make it sync?

Background
Suppose I have a contact on the device (or I'm about to create one), which I wish to save into Google account, so that it will be synced with it. I also wish to be able to let the user choose which account to save to.
This is what a Samsung device shows upon creating a new contact:
If the device also had a Samsung account, it will also be shown in this dialog.
The problem
I've found out how to insert a new one (here), but as I remember, modifying an existing contact is only allowed in specific cases (maybe only if the contact is in the device/sim itself, and not of other accounts).
I also can't find a way to get the list of accounts to save to (device, sim, google,...)
What I've found
I've ran this code on a Samsung device that has contacts on sim, storage and Google accounts:
final Map<String, String> result = new HashMap<>();
final Cursor cursor = getContentResolver()
.query(ContactsContract.RawContacts.CONTENT_URI, new String[]{RawContacts.ACCOUNT_TYPE, RawContacts.ACCOUNT_NAME},
null, null,
null);
final int accountNameIdx = cursor.getColumnIndex(RawContacts.ACCOUNT_NAME);
final int accountTypeIdx = cursor.getColumnIndex(RawContacts.ACCOUNT_TYPE);
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
result.put(cursor.getString(accountTypeIdx), cursor.getString(accountNameIdx));
}
cursor.close();
Log.d("AppLog", "accounts found:");
for (Entry<String, String> account : result.entrySet())
Log.d("AppLog", account.getKey() + ":" + account.getValue());
And the result was :
vnd.sec.contact.sim:primary.sim.account_name
com.google:somegmailaddress#gmail.com
vnd.sec.contact.phone:vnd.sec.contact.phone
But, as I've found (here), the sim/device accounts might be different on various devices.
The questions
What's the correct way to modify an existing contact, so that its ACCOUNT_TYPE will be of Google's ?
Does using the first item of the next code get the main Google account of the user, so that I should consider using it:
AccountManager.get(context).getAccountsByType("com.google")
?
Is there a way to check that the account that was found has auto-synced enabled, and if not , use an intent to go to the screen to make it sync? Is it possible to trigger a sync once the contact modification was done, in case auto-sync isn't enabled?
Is there a way to get all available accounts that can be set for a contact (including sim/local), so that I could present the user with a dialog to choose in which account to save the contact? Will "getAccounts" suffice, or should I filter the results somehow?
EDIT: for #4, it seems "getAccounts" doesn't provide me sim&local as the possible accounts to save into. Still, I want to know how to get them, so that I could offer the user to choose them.
So Many questions here. I might be able to answer a few. Let's see
1) You cannot modify the Account_Type of an existing user. This is explained here
This clearly states that Account Type can only be changed once. this is most likely to be used so that you can add an account type to each row for a Contact.
2) The code that you provided will return to you a list of all the Accounts of type com.google. So if a user has logged into their phone with 3 google accounts you get a list of all 3. Now an ideal user experience in this case is to show the user a list of all these accounts for them to choose and you perform your operations after the user selection on that particular account.
For more code Check here
3) To check if sync is enabled use the flag SHOULD_SYNC from ContactContracts.Settings .Rather than send an intent I reckon you just set this value, and the data source would have implemented the relevant content observers to do the job for you.
4) I am not sure if AccountManager holds detailsof SIM contacts at all. Atleast the documentation does not mention this. you can debug using a rooted device and extracting the sqlite database of the same, but in case you only want to fetch the details I think this stackoverflow question has certain approaches worth trying and look like they might work on the face of it
Hopefully this answers your questions.

Firebase Query: equalTo on a list

We are building an android app that needs to synchronize phone contacts with people already registered on the app. We are using firebase
To do this, we'd like to retrieve a list of existing users based on their phone numbers.
I have managed to retrieve users based on their phone number with ref.orderByChild("phone").equalTo($phoneNumber)
But I am wondering if there is a way of passing a list of phone numbers, instead of querying for each phone number one at a time ?
Something like this:
ref.orderByChild("phone").isIn([phone1, phone2, phone3])
I am just beginning to learn Firebase but I love the concept :)
Thanks a lot for your answers!
Firebase doesn't have or or in operators on its queries.
The closest you can come with with the startAt and endAt functions, to select a range. But that doesn't work for your use-case.
Normally when people are asking for this type of operation, there is a relation between all the pieces that they're trying to combine in a query. For example in your case, the use-case is likely something like: "get the name for all contacts in the user's address book".
In such a situation there are a few options:
monitor each contact with a separate query
embed the necessary metadata for each contact into the user's address book
Option 2 is the cheapest way to get the information, because you only need to read the address book. But it comes at the cost of data duplication, which more relationally trained developers are unused to. See this answer for a coughgreatcough example of such denormalization: Firebase data structure and url
Option 1 is not nearly as expensive as you may expect, since Firebase will open a socket connection only once and then perform all additional queries over that same connection.

android check if a contact installed an app android (like whatsapp)

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.

Categories

Resources