B4A Library [class] ContactsUtils - Provides read / write access to the stored contacts

Status
Not open for further replies.
ContactsUtils is a class based on ContentResolver library.

ContactsUtils allows you to read all kinds of information from the device stored contacts and also to modify the information, add new contacts and delete existing contacts.

Most of the methods expect a contact id. You can get this id by calling one of the Find methods. All the Find methods return a List that holds cuContact items.

The cuContact object holds the contact name and id. With that id you can get more information, add or modify existing fields and delete the contact.

Types:
B4X:
Type cuContact (Id As Long, DisplayName As String)
Type cuEmail (Email As String, EmailType As String)
Type cuPhone (Number As String, PhoneType As String)
Type cuEvent (DateString As String, EventType As String)

Public subs:
B4X:
'Returns a List with cuContact items based on the given name.
'Name - Name to look for.
'Exact - Whether to search for the exact name or to search for names that contain the given value.
'VisibleOnly - Whether to return only visible contacts. In most cases there are many invisible contacts.
Public Sub FindContactsByName(Name As String, Exact As Boolean, VisibleOnly As Boolean) As List

'Similar to FindContactsByName. Finds contacts based on the mail address.
Public Sub FindContactsByMail(Mail As String, Exact As Boolean, VisibleOnly As Boolean) As List

'Similar to FindContactsByName. Finds contacts based on the notes field.
Public Sub FindContactsByNotes(Note As String, Exact As Boolean, VisibleOnly As Boolean) As List

'Similar to FindContactsByName. Finds contacts based on the phone number.
Public Sub FindContactsByPhone(PhoneNumber As String, Exact As Boolean, VisibleOnly As Boolean) As List

'Returns the starred contacts.
Public Sub FindContactsByStarred(Starred As Boolean) As List

'Returns all contacts.
Public Sub FindAllContacts(VisibleOnly As Boolean) As List

'Returns all contacts with a photo.
Public Sub FindContactsWithPhotos As List

'Returns a List with cuEmail items.
Public Sub GetEmails(Id As Long) As List

'Returns a List with cuEvents items.
Public Sub GetEvents(Id As Long) As List

'Returns a List with cuPhone items.
Public Sub GetPhones(id As Long) As List

'Returns the note field.
Public Sub GetNote(id As Long) As String

'Returns the thumbnail photo of the given contact. Returns an uninitialized bitmap if no photo is available.
Public Sub GetPhoto(Id As Long) As Bitmap

'Gets whether the contact is "starred".
Public Sub GetStarred(Id As Long) As Boolean

'Sets the note field of the given id.
Public Sub SetNote(Id As Long, Note As String)

'Adds an email field to the given contact id.
'EmailType - One of the email types strings (see Initialize method).
Public Sub AddEmail(Id As Long, Email As String, EmailType As String)

'Adds a phone field to the given contact id.
'PhoneType - One of the phone types strings (see Initialize method).
Public Sub AddPhone(Id As Long, PhoneNumber As String, PhoneType As String)

'Deletes the given phone number.
Public Sub DeletePhone(Id As Long, PhoneNumber As String)

'Deletes the given email address.
Public Sub DeleteEmail(Id As Long,Email As String)

'Sets the starred state of the given id.
Public Sub SetStarred (Id As Long, Starred As Boolean)

'Deletes the contact with the given Id.
Public Sub DeleteContact(Id As Long)

'Inserts a new contact and returns the cuContact object of this contact.
Public Sub InsertContact(Name As String, Phone As String) As cuContact

To use this class you need to add a reference to the ContentResolver and SQL libraries.

The following permissions should be added in the manifest editor:
B4X:
AddPermission("android.permission.READ_CONTACTS")
AddPermission("android.permission.WRITE_CONTACTS") 'if write access is required

It should be pretty simple to extend this class and retrieve or modify other fields based on the existing code.

The attached project, which includes the ContactsUtils class shows a list with the visible contacts. Pressing on a contact will show some details about the contact and its photo. Long pressing on a contact will change its starred state.

V1.20 - Adds GetGroups and GetAccounts methods.
V1.10 - Adds GetEvents method.
V1.05 - Fixes an issue with InsertContact on HTC devices.
 

Attachments

  • ContactsUtils.zip
    11.6 KB · Views: 1,355
Last edited:
D

Deleted member 103

Guest
This is a log-file created by "printCursor(crsr)"
B4X:
name: Fili 1
number: 123456789
emails: null
_id: 0
***************
name: Fili 2
number: 987654321
emails: null
_id: 1
***************
name: Fili 1
number: 123456789
emails: null
_id: 0
***************
name: Fili 2
number: 987654321
emails: null
_id: 1
***************
 
D

Deleted member 103

Guest
I have started my new smartphone and now everything works, thank you. :)
 
D

Deleted member 103

Guest
Hi Erel,

maybe you can help me again.
With this code I can write the SIM contacts.

B4X:
        values.Initialize
        values.PutLong("_id", rawContactId)
        values.PutString("tag", kontakt1.DisplayName)
        values.PutString("number", kontakt1.Number)
        cr.Insert(simUri, values)

How to modify a SIM contact?

I tried with this code so far but it does not work.
B4X:
        values.Initialize
        values.PutString("number", kontakt1.Number)
        'SetData("vnd.android.cursor.item/phone_v2", values, rawContactId, True)
        cr.Update(simUri, values, "mimetype = ? AND _id = ?", Array As String("vnd.android.cursor.item/phone", rawContactId))
       
        values.Initialize
        values.PutString("tag", kontakt1.DisplayName)
        'SetData("vnd.android.cursor.item/name", values, rawContactId, True)
        cr.Update(simUri, values, "mimetype = ? AND _id = ?", Array As String("vnd.android.cursor.item/name", rawContactId))
 

DKCERT

Member
Licensed User
Longtime User
It will set the current notes field. You can modify the code in ContactsUtils to add a new note (if multiple notes are supported).

Erel; Could you please throw an AddNote sub together. Mine eighter updates all Notes or only leaves the first one (deletes all others).

Btw: This a version of GetNote(s) that steps through all Notes and returns them as a List:

B4X:
Public Sub GetNotes(id As Long) As List
    Dim nl As List
    nl.Initialize
    For Each obj() As Object In GetData("vnd.android.cursor.item/note", Array As String("data1"), id, Null)
        If obj(0) <> "" Then nl.Add(obj(0))
    Next
    Return nl
End Sub
 

DKCERT

Member
Licensed User
Longtime User
@DKCERT, have you tried to set the last parameter in SetNote sub to False?

Yes I have. It results in an exception (this is the Sub):

B4X:
Public Sub AddNote(Id As Long, Note As String)
    Dim v As ContentValues
    v.Initialize
    v.PutString("data1", Note)
    SetData("vnd.android.cursor.item/note", v, Id, False)
End Sub
...
...
Sub lstContacts_ItemLongClick (Position As Int, Value As Object)
    Dim c As cuContact = Value
    cu.AddNote(c.Id, "New Note")
    'update the text
    lstContacts_ItemClick(Position, Value)
End Sub

B4X:
contactsutils_setdata (java line: 685)
java.lang.IllegalArgumentException: Invalid column name_raw_contact_id
  at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:144)
  at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:114)
  at android.content.ContentProviderProxy.bulkQueryInternal(ContentProviderNative.java:398)
  at android.content.ContentProviderProxy.query(ContentProviderNative.java:439)
  at android.content.ContentResolver.query(ContentResolver.java:264)
  at anywheresoftware.b4a.objects.ContentResolverWrapper.Query(ContentResolverWrapper.java:43)
  at testapp.contactsutils._setdata(contactutils.java:685)
  at testapp.contactsutils._addnote(contactutils.java:96)
  at testapp.contactsutils.main._lstcontacts_itemlongclick(main.java:384)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:507)
  at anywheresoftware.b4a.BA.raiseEvent2(BA.java:169)
  at anywheresoftware.b4a.BA$2.run(BA.java:272)
  at android.os.Handler.handleCallback(Handler.java:587)
  at android.os.Handler.dispatchMessage(Handler.java:92)
  at android.os.Looper.loop(Looper.java:150)
  at android.app.ActivityThread.main(ActivityThread.java:4385)
  at java.lang.reflect.Method.invokeNative(Native Method)
  at java.lang.reflect.Method.invoke(Method.java:507)
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:849)
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:607)
  at dalvik.system.NativeStart.main(Native Method)
java.lang.IllegalArgumentException: Invalid column name_raw_contact_id

I hope this helps?
 
D

Deleted member 103

Guest
I tried it that way, but unfortunately it does not work. :(
B4X:
        values.Initialize
        values.PutString("number", kontakt1.Number)
        Log(cr.Update(simUri, values, "_id = ?", Array As String(rawContactId)) )
       
        values.Initialize
        values.PutString("tag", kontakt1.DisplayName)
        Log(cr.Update(simUri, values, "_id = ?", Array As String(rawContactId)) )
Maybe you have an idea again?
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
@DKCERT, I tried this code and it worked fine:
B4X:
Public Sub AddNote(Id As Long, Note As String)
   Dim v As ContentValues
   v.Initialize
   v.PutString("data1", Note)
   SetData("vnd.android.cursor.item/note", v, Id, False)
End Sub
Maybe there is a problem somewhere else in your code.

Sorry Filippo. Not sure why it doesn't work. Try to find a Java solution. It should be simple to convert it.
 

DKCERT

Member
Licensed User
Longtime User
@DKCERT, I tried this code and it worked fine:
B4X:
Public Sub AddNote(Id As Long, Note As String)
   Dim v As ContentValues
   v.Initialize
   v.PutString("data1", Note)
   SetData("vnd.android.cursor.item/note", v, Id, False)
End Sub
Maybe there is a problem somewhere else in your code.
Hi Erel, I'm actually using your demo code for ContactsUtils as my test platform :)
How do you test the code and on what device(s)? It fails on my test device: HTC Desire S (v/2.3.5 - API 10).
Reason for asking is I stumbled on these ones: https://code.google.com/p/android/issues/detail?id=11619 from http://stackoverflow.com/questions/...ntract-contact-missing-constants-from-the-api
Anyway, the Desire allows adding Notes to the given Contact - so it is of course possible. Any ideas?
 

thedesolatesoul

Expert
Licensed User
Longtime User
@DKCERT from your logs its seems you made some modifications to your class?
It cannot find name_raw_contact_id in contactUri. See here: http://developer.android.com/reference/android/provider/ContactsContract.Contacts.html
It should be there, I dont understand how you get that exception unless your device doesnt have that feature or you changed the uri. Try testing on the emulator as well with a different android version.

@Filippo are you sure you need to pass the raw contact id rather than the contact_id when doing a modify? Do you have documentation for the simUri and its fields?
 

DKCERT

Member
Licensed User
Longtime User
@DKCERT from your logs its seems you made some modifications to your class?
It cannot find name_raw_contact_id in contactUri. See here: http://developer.android.com/reference/android/provider/ContactsContract.Contacts.html
It should be there, I dont understand how you get that exception unless your device doesnt have that feature or you changed the uri. Try testing on the emulator as well with a different android version.

Well... modifications... I added AddNote (Update As Boolean -> False) and GetNotes (loops through all notes) and AddPhoto2 to the class. The "name_raw_contact_id" param is from the SetData sub in ContactsUtils v/1.05:

B4X:
Private Sub SetData(Mime As String, Values As ContentValues, Id As Long, Update As Boolean)
    If Update Then
        cr.Update(dataUri, Values, "mimetype = ? AND contact_id = ?", Array As String(Mime, Id))
    Else
        Dim crsr As Cursor = cr.Query(contactUri, Array As String("name_raw_contact_id"), _    <---------------------------
            "_id = ?", Array As String(Id), "")
        If crsr.RowCount = 0 Then
            Log("Error getting raw_contact_id")
            crsr.Close
            Return
        End If
        crsr.Position = 0
        Values.PutString("raw_contact_id", crsr.GetString("name_raw_contact_id"))   <---------------------------
        crsr.Close
        Values.PutString("mimetype", Mime)
        cr.Insert(dataUri, Values)
    End If
End Sub

The emulator fails as well (using API level 8 -> Android v/2.2). So does the physical HTC Desire S (API level 10 -> Android 2.3.5).
 
D

Deleted member 103

Guest
I have found the solution.

With this code you can change a SIM-contact:

B4X:
    Dim cr As ContentResolver
    Dim values As ContentValues

    values.Initialize
    values.PutString("tag", old_DisplayName)
    values.PutString("number", old_Number)
    values.PutString("newTag", new_DisplayName)
    values.PutString("newNumber", new_Number)
   
    cr.Update(simUri, values, Null, Null)
 

DKCERT

Member
Licensed User
Longtime User
@DKCERT I tested it with Nexus 4. Seems like your device misses this column.

The purpose of this column is to find the primary raw_contact_id from the aggregated contact. If you like you can check which other columns are available and see whether there is an alternative way to find the raw_contact_id.

The emulator fails as well (using API level 8 -> Android v/2.2). So does the physical HTC Desire S (API level 10 -> Android 2.3.5).

Well... I somehow hoped you could help me there ;) As the SDK also fails you properly have the right tools to pin down this issue!?
 

shaffnert03

Member
Licensed User
Longtime User
Is it possible for me to add birthday to what this library can pull? And if so, any advice on where I'd start?
 
Status
Not open for further replies.
Top