Android Question normalize contact list to E164 format

leitor79

Active Member
Licensed User
Longtime User
Hello,

I need my app to get all the contacts of the device and get the phone number of each one in E164 format. I assume the user could be anywhere in the world so is not "strip the first 0 and replace it with your country prefix" because I don't know for sure if each mobile number in the world starts with 0.

I've tried mixing this with this but I can't get it work it right. I'll explain:

First I've tried ContentResolver:

B4X:
    Dim u As Uri
    Dim i As Int
    Dim PeopleProjection() As String = Array As String("display_name", "has_phone_number", "_id", "raw_contact_id", "photo_id", "data4", "data1")
   
    u.Parse("content://com.android.contacts/data")   
    Dim crsr As Cursor = cr.Query(u, PeopleProjection, "has_phone_number = 1 AND data4 is not null and data1 is not null", Null, "")

    For i = 0 To crsr.RowCount - 1
        crsr.Position = i

        Dim numE164 As String = crsr.GetString("data4")
        Dim id As String = crsr.GetString("raw_contact_id")
        Dim nombre As String = crsr.getstring("display_name")
        Dim HasNumberFlag As String = crsr.GetString("has_phone_number")
        Dim num As String = crsr.GetString("data1")
        Log(id & ";" & nombre & ";" & HasNumberFlag & ";" & num & ";" & numE164)
     
    Next
   crsr.Close

With this code, I get "duplicate" entries for each contact, not knowing for sure which entry corresponds to the E164 number and which one doesn't. Yes, at sight I could tell, but this is an example of what I get from one of my contacts (changing name and some numbers of course):

So I've tried a different approach: Using ContactsUtils to get each contact and, for each contact, try to get the data4. I have trouble with this, I'ts like the contact ID doesn't match the other ID:

So, I have the following code (I've switched from ContactUtils to contactresolver to make some tests). The idea is "Test" ask for all contacts and, for each one, I call a sub to get the data4 (e164 number) by the ID:

B4X:
Sub Test()
   
    Dim u As Uri
    Dim PeopleProjection() As String = Array As String("times_contacted", "last_time_contacted", "display_name", "has_phone_number", "starred", "_id", "photo_id")
    Dim l As Long
   
    cr.Initialize("cr")
    cr2.Initialize("cr2")
   
    u.Parse("content://com.android.contacts/contacts")
    Dim crsr As Cursor = cr.Query(u, PeopleProjection, "", Null, "")
   
       For i = 0 To crsr.RowCount - 1
        crsr.Position = i
        l = crsr.GetString("_id")
         Log(l & ";" & crsr.GetString("display_name") & ";" & GetNumeroNormalizado(l))
    Next
    crsr.Close
   
   
End Sub

B4X:
Sub GetNumeroNormalizado(ContactoID As Long) As String
    Dim u As Uri
    Dim i As Int
    Dim s As String
    Dim PeopleProjection2() As String = Array As String("data4", "_id", "raw_contact_id", "display_name")
   
    u.Parse("content://com.android.contacts/data")   
    Dim crsr As Cursor = cr2.Query(u, PeopleProjection2, "raw_contact_id = ?", Array As String(ContactoID), "display_name")
   
    For i = 0 To crsr.RowCount - 1
         crsr.Position = i
         s = crsr.GetString("data4")
    Next
    crsr.Close
   
    Return s
   
End Sub

So, my problem is that most calls to GetNumeroNormalizado returns null (99%?) and, the few ones that doesn't, don't match the contact (I get a number from another person). This shouldn't be like this since the first method (the one where I get too much info) I get E164 numbers from most contacts and they correspond to the person.

I've tried replacing, in the last query, raw_contact_id for _id, but the same (or so).

I've read sometimes the data4 could be null, in that case I manually normalize it.

Also, I'd like to know how to filter the query contacts so I don't get stuff that are not numbers. I've tried filtering using ¿mimes? but I don't get the concept yet.

Thank you very much!
 

leitor79

Active Member
Licensed User
Longtime User
Hi Erel; thank you very much for your answer!

No, I did not tried that and I regret it profoundly. it worked perfectly.

So; I add to my question... as expected, some of the data4 returns null. Some of them should return a value (is a valid number, just written without the country prefix, as many). I suppose I should normalize them "manually". Since the format for mobile numbers here is something like 091234567, the correct way should be removing the first 0 and add the +598 (my country code), but I don't know if that method would be correct in all countries. Also, some countries has phone mobile numbers without the beggining 0, but I don't know if its valid to add the country prefix before the number without removing anything... does somebody know?

Although I've tried to do it for two days and googled a lot, I'm still not clear about when I have to use the URIs; for example, "vnd.android.cursor.item/phone_v2" or "content://com.android.contacts/contacts", or "content://com.android.contacts/data"... I've read several android developer pages but the pages seems to explain properties, not what are the possible URIs or something...

Thank you very much!
 
Upvote 0

Erel

B4X founder
Staff member
Licensed User
Longtime User
This is indeed an obscure feature of Android. I recommend you to always start from ContactUtils code. I did quite a lot of research when I wrote it.
 
Upvote 0
Cookies are required to use this site. You must accept them to continue using the site. Learn more…