﻿B4A=true
Group=Default Group
ModulesStructureVersion=1
Type=Class
Version=6
@EndOfDesignText@
'Version: 1.21 from @walt61 with firstname and lastname added by @Alain75
'Class module
Sub Class_Globals
	Type cuContact	(Id As Long, DisplayName As String, FirstName As String, LastName As String)
	Type cuEmail	(Email As String, EmailType As String)
	Type cuPhone	(Number As String, PhoneType As String)
	Type cuAddress	(Street As String, Neighborhood As String, City As String, PostCode As String, AddressType As String, RawAddress As String)
	Type cuEvent 	(DateString As String, EventType As String)
	Type cuOrganization	(Company As String, Title As String)
	Private mailTypes, phoneTypes, eventTypes, addressTypes As Map 
	Private cr As ContentResolver
	Private dataUri, contactUri, rawContactUri As Uri
	Private GroupSources, GroupSourcesByName, GroupRows, GroupRowsByName As Map

End Sub

Public Sub Initialize
	dataUri.Parse("content://com.android.contacts/data")
	contactUri.Parse("content://com.android.contacts/contacts")
	rawContactUri.Parse("content://com.android.contacts/raw_contacts")
	cr.Initialize("cr")
	mailTypes.Initialize
	mailTypes.Put("1", "home")
	mailTypes.Put("2", "work")
	mailTypes.Put("3", "other")
	mailTypes.Put("4", "mobile")
	
	phoneTypes.Initialize
	phoneTypes.Put("1", "home")
	phoneTypes.Put("2", "mobile")
	phoneTypes.Put("3", "work")
	phoneTypes.Put("4", "fax_work")
	phoneTypes.Put("5", "fax_home")
	phoneTypes.Put("6", "pager")
	phoneTypes.Put("7", "other")
	phoneTypes.Put("8", "callback")
	phoneTypes.Put("9", "car")
	phoneTypes.Put("10", "company_main")
	phoneTypes.Put("11", "isdn")
	phoneTypes.Put("12", "main")
	phoneTypes.Put("13", "other_fax")
	phoneTypes.Put("14", "radio")
	phoneTypes.Put("15", "telex")
	phoneTypes.Put("16", "tty_tdd")
	phoneTypes.Put("17", "work_mobile")
	phoneTypes.Put("18", "work_pager")
	phoneTypes.Put("19", "assistant")
	phoneTypes.Put("20", "mms")
	
	addressTypes.Initialize
	addressTypes.Put("1", "home")
	addressTypes.Put("2", "work")
	addressTypes.Put("3", "other")
	addressTypes.Put("4", "custom")
	
	eventTypes.Initialize
	eventTypes.Put("1", "anniversary")
	eventTypes.Put("2", "other")
	eventTypes.Put("3", "birthday")
End Sub

'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.
Public Sub FindContactsByName(Name As String, Exact As Boolean, VisibleOnly As Boolean) As List
	Return FindContactsIdFromData("name", "data1", Name, "=", Exact, VisibleOnly,"")
End Sub

'Similar to FindContactsByName. Finds contacts based on the mail address.
Public Sub FindContactsByMail(Mail As String, Exact As Boolean, VisibleOnly As Boolean) As List
	Return FindContactsIdFromData("email_v2", "data1", Mail, "=", Exact, VisibleOnly,"")
End Sub

'Similar to FindContactsByName. Finds contacts based on the notes field.
Public Sub FindContactsByNotes(Note As String, Exact As Boolean, VisibleOnly As Boolean) As List
	Return FindContactsIdFromData("note", "data1", Note, "=", Exact, VisibleOnly,"")
End Sub

'Similar to FindContactsByName. Finds contacts based on the phone number.
Public Sub FindContactsByPhone(PhoneNumber As String, Exact As Boolean, VisibleOnly As Boolean) As List
	Return FindContactsIdFromData("phone_v2", "data1", PhoneNumber, "=", Exact, VisibleOnly,"")
End Sub

'Returns the starred contacts.
Public Sub FindContactsByStarred(Starred As Boolean) As List
	Dim value As String = IIf(Starred,"1","0")
	Return FindContactsIdFromData("name", "starred", value,"=", True, True,"")
End Sub
'Returns all contacts.
Public Sub FindAllContacts(VisibleOnly As Boolean, SortColumn As String) As List
	Return FindContactsIdFromData("name", "data1", "null", "<>", True, VisibleOnly,SortColumn)
End Sub
'Returns all contacts with a photo.
Public Sub FindContactsWithPhotos As List
	Return FindContactsIdFromData("photo", "data15", "null", "<>", True, False,"")
End Sub
'Returns all contacts that are member of the specified group ID.
Public Sub FindContactsByGroupRowId(gid As Int, VisibleOnly As Boolean) As List
	Dim projCols() As String = Array As String("contact_id", "display_name")
	Return FindContactsIdFromData2("vnd.android.cursor.item/group_membership", "data1", gid, "=", True, VisibleOnly, projCols)
End Sub
'Returns all contacts that are member of a specified group name (part)
Public Sub FindContactsByGroupName(gname As String, VisibleOnly As Boolean) As List
	Dim l As List
	l.Initialize
	FillGroupSources
	gname = gname.ToLowerCase
	For Each k As String In GroupRowsByName.Keys
		' Search of the group as the beginnning (1 car) or part of the key (except "starred in android" because of its dedicated function)
		If Not(k.Contains("starred")) Then 
			If (gname.Length=1 And k.ToLowerCase.StartsWith(gname)) Or (gname.Length<>1 And k.ToLowerCase.Contains(gname)) Then 
				gname = k
				Exit
			End If
		End If
	Next
	If Not(GroupRowsByName.ContainsKey(gname)) Then Return l ' Return an empty list
	Dim i As Int
	If IsNumber(GroupRowsByName.Get(gname)) Then
		i = GroupRowsByName.Get(gname)
	Else
		Try
			i = Bit.ParseInt(GroupRowsByName.Get(gname), 16)
		Catch
			Return l
		End Try
	End If
	Return FindContactsByGroupRowId(i, VisibleOnly)
End Sub

Private Sub FindContactsIdFromData (Mime As String, DataColumn As String, Value As String, Operator As String, _
	Exact As Boolean, VisibleOnly As Boolean, SortColumn As String) As List
	If Not(Exact) Then 
		Operator = "LIKE"
		Value = "%" & Value & "%"
	End If
	Dim selection As String = "mimetype = ? AND " & DataColumn & " " & Operator & " ? "
	If VisibleOnly Then selection = selection & " AND in_visible_group = 1"
	Dim crsr As Cursor = cr.Query(dataUri, Array As String("contact_id", "data1","data2","data3"), selection, _
		Array As String("vnd.android.cursor.item/"&Mime, Value), SortColumn)
	Dim res As List
	res.Initialize
	Dim m As Map
	m.Initialize
	For i = 0 To crsr.RowCount - 1
		crsr.Position = i
		Dim Id As Long = crsr.GetLong("contact_id")
		If m.ContainsKey(Id) Then Continue
		m.Put(Id, Null)
		If Mime = "name" Then
			Dim c As cuContact
			c.Initialize
			c.Id 			= Id
			c.DisplayName	= crsr.GetString2(1)
			c.FirstName		= IIf(crsr.GetString2(2)<>Null,crsr.GetString2(2),"")
			c.LastName		= IIf(crsr.GetString2(3)<>Null,crsr.GetString2(3),"")
		Else
			Dim c As cuContact = GetNames(Id)
		End If	
		res.Add(c)
	Next
	crsr.Close
	Return res
End Sub

' Like FindContactsIdFromData, but the 'projection' columns are specified by the caller
Private Sub FindContactsIdFromData2(Mime As String, DataColumn As String, Value As String, Operator As String, _
	Exact As Boolean, VisibleOnly As Boolean, projectionColumns() As String) As List
	If Not(Exact) Then
		Operator = "LIKE"
		Value = "%" & Value & "%"
	End If
	Dim selection As String = "mimetype = ? AND " & DataColumn & " " & Operator & " ? "
	If VisibleOnly Then selection = selection & " AND in_visible_group = 1"
	Dim crsr As Cursor = cr.Query(dataUri, projectionColumns, selection, Array As String(Mime, Value), "display_name")
	Dim res As List
	res.Initialize
	Dim m As Map
	m.Initialize
	For i = 0 To crsr.RowCount - 1
		crsr.Position = i
		Dim Id As Long = crsr.GetLong("contact_id")
		If m.ContainsKey(Id) Then Continue
		Dim cu As cuContact = GetNames(Id)
		m.Put(cu.Id, Null)
		res.Add(cu)
	Next
	crsr.Close
	Return res
End Sub

Private Sub FillGroupSources ' WM - added processing for GroupSourcesByName, GroupRows, GroupRowsByName
	If GroupSources.IsInitialized = False Then
		GroupSources.Initialize
		GroupSourcesByName.Initialize
		GroupRows.Initialize
		GroupRowsByName.Initialize
		Dim gu As Uri
		gu.Parse("content://com.android.contacts/groups")
		Dim c As Cursor = cr.Query(gu, Array As String("_id", "sourceid", "title"), "", Null, "")
		For i = 0 To c.RowCount - 1
			c.Position = i
			GroupSources.Put(c.GetString("sourceid"), c.GetString("title"))
			GroupSourcesByName.Put(c.GetString("title").ToLowerCase, c.GetString("sourceid")) ' Note: title is downshifted to make it easier to look up values in the map
			GroupRows.Put(c.GetString("_id"), c.GetString("title"))
			GroupRowsByName.Put(c.GetString("title").ToLowerCase, c.GetString("_id")) ' Note: title is downshifted to make it easier to look up values in the map
		Next
	End If
End Sub

'*************************************************************************************************************************************************
' GET Functions
'*************************************************************************************************************************************************

Private Sub GetData(Mime As String, DataColumns() As String, Id As Long, Blobs() As Boolean) As List
	Dim crsr As Cursor = cr.Query(dataUri, DataColumns, "mimetype = ? AND contact_id = ?", Array As String(Mime, Id), "")
	Dim res As List
	res.Initialize
	For i = 0 To crsr.RowCount - 1
		crsr.Position = i
		Dim row(DataColumns.Length) As Object
		For c = 0 To DataColumns.Length - 1
			If  Blobs <> Null And Blobs(c) = True Then
				row(c) = crsr.GetBlob2(c)
			Else
				row(c) = crsr.GetString2(c)
			End If
		Next
		res.Add(row)
	Next
	crsr.Close
	Return res
End Sub
'Small utility to find the type integer value from the type name
Private Sub GetKeyFromValue(m As Map, v As String, defaultValue As Int) As Int
	Dim t As Int = defaultValue
	For i = 0 To m.Size - 1
		If m.GetValueAt(i) = v Then
			t = m.GetKeyAt(i)
			Exit
		End If
	Next
	Return t
End Sub

'Returns a Map. The keys are the account names and the values are the account types.
Public Sub GetAccounts(Id As Long) As Map
	Dim uri As Uri
	uri.Parse("content://com.android.contacts/contacts/" & Id & "/entities")
	Dim c As Cursor = cr.Query(uri, Array As String("account_name", "account_type"), "", Null, "")
	Dim m As Map
	m.Initialize
	For i = 0 To c.RowCount - 1
		c.Position = i
		m.Put(c.GetString("account_name"), c.GetString("account_type"))
	Next
	c.Close

	Return m
End Sub
'Returns a List with cuAddress items.
Public Sub GetAddresses(Id As Long) As List
	Dim res As List
	res.Initialize
	For Each obj() As Object In GetData("vnd.android.cursor.item/postal-address_v2", Array As String("data1", "data2", "data4","data6","data7","data9"), Id, Null)
		Dim a As cuAddress
		a.Initialize
		a.RawAddress	= obj(0)
		a.AddressType	= addressTypes.Get(obj(1))
		a.Street		= IIf(obj(2)<>Null,obj(2),"")
		a.Neighborhood	= IIf(obj(3)<>Null,obj(3),"")
		a.City			= IIf(obj(4)<>Null,obj(4),"")
		a.PostCode		= IIf(obj(5)<>Null,obj(5),"")

		res.Add(a)
	Next
	Return res
End Sub
'Returns a List with cuEmail items.
Public Sub GetEmails(Id As Long) As List
	Dim res As List
	res.Initialize
	For Each obj() As Object In GetData("vnd.android.cursor.item/email_v2", Array As String("data1", "data2"), Id, Null)
		Dim e As cuEmail
		e.Initialize
		e.Email		= obj(0)
		e.EmailType = mailTypes.Get(obj(1))
		res.Add(e)
	Next
	Return res
End Sub
'Returns a List with cuEvents items.
Public Sub GetEvents(Id As Long) As List
	Dim res As List
	res.Initialize
	For Each obj() As Object In GetData("vnd.android.cursor.item/contact_event", Array As String("data1", "data2"), Id, Null)
		Dim e As cuEvent
		e.Initialize
		e.DateString = obj(0)
		e.EventType	 = eventTypes.Get(obj(1))
		res.Add(e)
	Next
	Return res
End Sub
'Returns a List of groups
Public Sub GetGroups(Id As Long) As List
	FillGroupSources
	Dim uri As Uri
	uri.Parse("content://com.android.contacts/contacts/" & Id & "/entities")
	Dim c As Cursor = cr.Query(uri, Array As String("group_sourceid"), "", Null, "")
	Dim groups As List
	groups.Initialize
	For i = 0 To c.RowCount - 1
		c.Position = i
		If c.GetString("group_sourceid") <> Null Then
			Dim source As String = c.GetString("group_sourceid")
			If GroupSources.ContainsKey(source) Then groups.Add(GroupSources.Get(source))
		End If
	Next
	c.Close
	Return groups
End Sub
'Returns the names fields.
Public Sub GetNames(id As Long) As cuContact
	Dim names As List = GetData("vnd.android.cursor.item/name", Array As String("data1", "data2","data3"), id, Null)
	Dim c As cuContact
	If names.Size > 0 Then
		c.Initialize
		Dim obj() As Object = names.Get(0)
		c.Id			= id
		c.DisplayName	= obj(0)
		c.Firstname		= IIf(obj(1)<>Null,obj(1),"")
		c.LastName		= IIf(obj(2)<>Null,obj(2),"")
	End If
	Return c
End Sub
'Returns the note field.
Public Sub GetNote(id As Long) As String
	Dim raw As List = GetData("vnd.android.cursor.item/note", Array As String("data1"), id, Null)
	If raw.Size = 0 Then Return ""
	Dim obj() As Object = raw.Get(0)
	Return IIf(obj(0)<>Null,obj(0),"")
End Sub
'Returns the Organization fields (company and title)
Public Sub GetOrganization(Id As Long) As cuOrganization
	Dim organizations As List = GetData("vnd.android.cursor.item/organization", Array As String("data1", "data4"), _
		Id, Null)
	Dim o As cuOrganization
	If organizations.Size > 0 Then
		o.Initialize
		Dim obj() As Object = organizations.Get(0)
		o.Company	= IIf(obj(0)<>Null,obj(0),"")
		o.Title		= IIf(obj(1)<>Null,obj(1),"")
	End If
	Return o
End Sub
'Returns the owner(s) gmail
Public Sub GetOwner() As String
	Dim r As String, c As JavaObject, j As JavaObject
	c.InitializeContext
	j = j.InitializeStatic("android.accounts.AccountManager").RunMethod("get", Array(c))
	Dim accounts() As Object = j.RunMethod("getAccountsByType", Array("com.google"))
	For Each a As JavaObject In accounts
		r = r & a.GetField("name") & " "
	Next
	Return r.Trim
End Sub
'Returns a List with cuPhone items.
Public Sub GetPhones(Id As Long) As List
	Dim r As List
	r.Initialize
	For Each obj() As Object In GetData("vnd.android.cursor.item/phone_v2", Array As String("data1", "data2"), Id, Null)
		Dim p As cuPhone
		p.Initialize
		p.Number 	= IIf(obj(0)<>Null,obj(0),"")
		p.PhoneType = phoneTypes.Get(obj(1))
		r.Add(p)
	Next
	Return r
End Sub
'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
	Dim raw As List = GetData("vnd.android.cursor.item/photo", Array As String("data15"), Id, Array As Boolean(True))
	Dim bmp As Bitmap
	If raw.Size > 0 Then
		Dim obj() As Object = raw.Get(0)
		Dim bytes() As Byte = obj(0)
		If bytes <> Null Then
			Dim In As InputStream
			In.InitializeFromBytesArray(bytes, 0, bytes.Length)
			bmp.Initialize2(In)
			In.Close
		End If
	End If
	Return bmp
End Sub
'Gets whether the contact is "starred".
Public Sub GetStarred(Id As Long) As Boolean
	Dim crsr As Cursor = cr.Query(contactUri, Array As String("starred"), "_id = ?", Array As String(Id), "")
	crsr.Position = 0
	Dim res As Boolean = IIf(crsr.RowCount>0, (crsr.GetInt("starred")=1), False)
	crsr.Close
	Return res
End Sub

'*************************************************************************************************************************************************
' SET Functions
'*************************************************************************************************************************************************

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 "&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
Private Sub SetData2(Mime As String, Values As ContentValues, OldValue As String, Id As Long)
	Values.PutString("mimetype", Mime)
	cr.Update(dataUri, Values, "mimetype = ? AND contact_id = ? AND data1 = ?", Array As String(Mime, Id, OldValue))
End Sub
' Sets an structured postal address for a contact.
Public Sub SetAddress(Id As Long, Address As cuAddress, RawOld As String)
	Dim v As ContentValues
	v.Initialize
	v.PutInteger("data2", GetKeyFromValue(addressTypes, Address.AddressType, 2))
	v.PutString("data4", Address.Street)
	v.PutString("data6", Address.Neighborhood)
	v.PutString("data7", Address.City)
	v.PutString("data9", Address.PostCode)
	SetData2("vnd.android.cursor.item/postal-address_v2", v, RawOld, Id)
End Sub
' Sets an existing contact's DisplayName.
Public Sub SetDisplayName(Id As Long, DisplayName As String)
	Dim cv As ContentValues
	cv.Initialize
	cv.PutString("data1", DisplayName)
	SetData("vnd.android.cursor.item/name", cv, Id, True)
End Sub
'Sets an existing event field to the given contact id
Public Sub SetEvent(Id As Long, DateString As String, EventType As String)
	Dim v As ContentValues
	If DateString.Contains("/") Then DateString = Regex.Replace("(..)/(..)/(....)",DateString,"$3-$2-$1")
	v.Initialize
	v.PutString("data1", DateString)
	v.PutInteger("data2", GetKeyFromValue(eventTypes, EventType, 2))
	SetData("vnd.android.cursor.item/contact_event", v, Id, True)
End Sub
'Sets firstname or lastname to the given contact id
Public Sub SetName(Id As Long, Name As String, TypeName As String)
	Dim cv As ContentValues
	cv.Initialize
	cv.PutString("data"&IIf(TypeName.ToLowerCase="firstname","2","3"), Name)
	SetData("vnd.android.cursor.item/name", cv, Id, True)
End Sub
'Sets firstname, lastname and display_name to the given contact id
Public Sub SetNames(Id As Long, c As cuContact)
	Dim v As ContentValues
	v.Initialize
	v.PutString("data2",c.FirstName)
	v.PutString("data3",c.LastName)
	v.PutString("data1",c.DisplayName)
	SetData("vnd.android.cursor.item/name", v, Id, True)
End Sub
'Sets the note field of the given id.
Public Sub SetNote(Id As Long, Note As String)
	Dim v As ContentValues
	v.Initialize
	v.PutString("data1", Note)
	SetData("vnd.android.cursor.item/note", v, Id, True)
End Sub
'Sets/Add/Delete the organization fields of the given id
Public Sub SetOrganization(Id As Long, Organization As cuOrganization, Update As Boolean)
	Dim v As ContentValues, Mime As String = "vnd.android.cursor.item/organization"
	v.Initialize
	If (Organization.Company&Organization.Title).trim<>"" Then
		v.PutString("data1",Organization.Company)
		v.PutString("data4",Organization.Title)
		SetData(Mime,v,Id,Update)
	Else
		cr.Delete(dataUri, "mimetype = ? AND contact_id = ?", Array As String(Mime, Id))
	End If
End Sub
'Sets a phone field to the given contact id.
Public Sub SetPhone(Id As Long, New As String, PhoneType As String, Old As String)
	Dim v As ContentValues, t As Int = GetKeyFromValue(phoneTypes, PhoneType, 2)
	v.Initialize
	v.PutString("data1", New)
	v.PutInteger("data2", t) 'Default=mobile
	SetData2("vnd.android.cursor.item/phone_v2", v, Old , Id)
End Sub
'Sets the starred state of the given id.
Public Sub SetStarred (Id As Long, Starred As Boolean)
	Dim v As ContentValues
	v.Initialize
	v.PutInteger("starred", IIf(Starred,1,0))
	cr.Update(contactUri, v, "_id = ?", Array As String(Id))
End Sub

'**************************************************************************************************************************************************
' DELETE Functions
'**************************************************************************************************************************************************

Private Sub DeleteData(Mime As String, Data1 As String, Id As Long)
	cr.Delete(dataUri, "mimetype = ? AND data1 = ? AND contact_id = ?", Array As String(Mime, Data1, Id))
End Sub
Private Sub DeleteData2(Mime As String, Data2 As Int, Id As Long)
	cr.Delete(dataUri, "mimetype = ? AND data2 = ? AND contact_id = ?", Array As String(Mime, Data2, Id))
End Sub
'Delete the given address of the given type
Public Sub DeleteAddress(Id As Long,RawAddress As String)
	DeleteData("vnd.android.cursor.item/postal-address_v2",RawAddress, Id)
End Sub
Public Sub DeleteAddressByType(Id As Long, AddressType As String)
	'Log("2Del:"&RawAddress.Replace(CRLF,"|")&"<")
	'Dim c As Cursor = cr.Query(dataUri, Array As String("data1"),"mimetype = ? AND contact_id = ?", Array As String("vnd.android.cursor.item/postal-address_v2" ,Id), "")
	'For i = 0 To c.RowCount - 1
	'	c.Position = i
	'	Log("Read:"&c.GetString("data1").Replace(CRLF,"|")&"<")
	'Next
	Dim Data2 As Int = GetKeyFromValue(addressTypes, AddressType, 99) 'if not recognize, no deletion of default !
	DeleteData2("vnd.android.cursor.item/postal-address_v2", Data2, Id)
End Sub
'Deletes the contact with the given Id.
Public Sub DeleteContact(Id As Long)
	cr.Delete(rawContactUri, "contact_id = ?", Array As String(Id))
End Sub
'Deletes the given email address.
Public Sub DeleteEmail(Id As Long, Email As String)
	DeleteData("vnd.android.cursor.item/email_v2", Email, Id)
End Sub
'Deletes the given email address.
Public Sub DeleteEmailByType(Id As Long, EmailType As String)
	Dim Data2 As Int = GetKeyFromValue(mailTypes, EmailType, 99) 'if not recognize, no deletion of default !
	DeleteData2("vnd.android.cursor.item/email_v2", Data2, Id)
End Sub
'Deletes the given event 
Public Sub DeleteEvent(Id As Long, Event As String)
	If Event.Contains("/") Then Event = Regex.Replace("(..)/(..)/(....)",Event,"$3-$2-$1")
	DeleteData("vnd.android.cursor.item/contact_event", Event, Id)
End Sub
'Deletes the given note for the given id
Public Sub DeleteNote(Id As Long, Note As String)
	DeleteData("vnd.android.cursor.item/note", Note, Id)
End Sub
'Deletes the given phone number.
Public Sub DeletePhone(Id As Long, PhoneNumber As String)
	DeleteData("vnd.android.cursor.item/phone_v2", PhoneNumber, Id)
End Sub
Public Sub DeletePhoneByType(Id As Long, PhoneType As String)
	Dim Data2 As Int = GetKeyFromValue(phoneTypes, PhoneType, 99) 'if not recognize, no deletion of default !
	DeleteData2("vnd.android.cursor.item/phone_v2", Data2, Id)
End Sub


'*************************************************************************************************************************************************
' ADD Functions
'*************************************************************************************************************************************************

' Adds an structured postal address for a contact.
Public Sub AddAddress(Id As Long, Address As cuAddress)
	Dim v As ContentValues, t As Int = GetKeyFromValue(addressTypes, Address.AddressType, 2)
	v.Initialize
	v.PutInteger("data2", t)
	v.PutString("data4", Address.Street)
	v.PutString("data6", Address.Neighborhood)
	v.PutString("data7", Address.City)
	v.PutString("data9", Address.PostCode)
	SetData("vnd.android.cursor.item/postal-address_v2", v, Id, False)
End Sub
'Adds an email field to the given contact id.
Public Sub AddEmail(Id As Long, Email As String, EmailType As String)
	Dim v As ContentValues
	v.Initialize
	v.PutString("data1", Email)
	v.PutInteger("data2", GetKeyFromValue(mailTypes, EmailType, 1)) ' Default=home
	SetData("vnd.android.cursor.item/email_v2", v, Id, False)
End Sub
'Adds an event field to the given contact id
Public Sub AddEvent(Id As Long, DateString As String, EventType As String)
	Dim v As ContentValues
	If DateString.Contains("/") Then DateString = Regex.Replace("(..)/(..)/(....)",DateString,"$3-$2-$1")
	v.Initialize
	v.PutString("data1", DateString)
	v.PutInteger("data2", GetKeyFromValue(eventTypes, EventType, 2))
	SetData("vnd.android.cursor.item/contact_event", v, Id, False)
End Sub
'Adds a group to the givien contact id
Public Sub AddGroup(Id As Long, GroupId As String)
	Dim uri As Uri, v As ContentValues
	uri.Parse("content://com.android.contacts/contacts/" & Id & "/entities")
	v.initialize
	v.PutString("group_sourceid",GroupId)
	cr.Insert(uri,v)
End Sub
'Adds a Note to the given contact id (even if one exists already...)
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
'Adds a phone field to the given contact id.
Public Sub AddPhone(Id As Long, PhoneNumber As String, PhoneType As String)
	Dim v As ContentValues, t As Int = GetKeyFromValue(phoneTypes, PhoneType, 2)
	v.Initialize
	v.PutString("data1", PhoneNumber)
	v.PutInteger("data2", t) 'Default=mobile
	SetData("vnd.android.cursor.item/phone_v2", v, Id, False)
End Sub

'Inserts a new contact and returns the cuContact object of this contact.
Public Sub CreateContact(Name As String, AccountName As String, AccountType As String) As cuContact
	Dim values As ContentValues
	values.Initialize
	If AccountName <> "" Then values.PutString("account_name",AccountName) Else values.PutNull("account_name")
	If AccountType <> "" Then values.PutString("account_type",AccountType) Else values.PutNull("account_type") 
	Dim rawUri As Uri = cr.Insert(rawContactUri, values)
	Dim rawContactId As Long = rawUri.ParseId

	values.Initialize
	values.PutLong("raw_contact_id", rawContactId)
	values.PutString("mimetype", "vnd.android.cursor.item/name")
	values.PutString("data1", Name)
	cr.Insert(dataUri, values)
	
	Dim cu As cuContact
	cu.Initialize
	Dim crsr As Cursor = cr.Query(dataUri, Array As String("contact_id", "display_name"), "raw_contact_id = ?", Array As String(rawContactId), "")
	crsr.Position = 0
	cu.DisplayName = crsr.GetString("display_name")
	cu.Id = crsr.GetLong("contact_id")
	Return cu
End Sub

'useful for debugging
Private Sub printCursor(c As Cursor) 'ignore
	For r = 0 To c.RowCount - 1
		c.Position = r
		For col = 0 To c.ColumnCount - 1
			Try
				Log(c.GetColumnName(col) & ": " & c.GetString2(col))
			Catch
				Log(c.GetColumnName(col) & ": " & LastException)
			End Try
		Next
		Log("***************")
	Next
End Sub
