Merge remote-tracking branch 'download/tizen'
[platform/core/csapi/tizenfx.git] / src / Tizen.Pims.Contacts / Tizen.Pims.Contacts / ContactsDatabase.cs
1 /*
2 * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3 *
4 * Licensed under the Apache License, Version 2.0 (the License);
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an AS IS BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 using System;
18 using System.Collections.Generic;
19 using System.Runtime.InteropServices;
20
21 namespace Tizen.Pims.Contacts
22 {
23     /// <summary>
24     /// ContactsDatabase provides methods to manage contacts information from/to the database.
25     /// </summary>
26     /// <remarks>
27     /// This class allows user to access/create/update db operations for contacts information.
28     /// </remarks>
29     public class ContactsDatabase
30     {
31         private Object thisLock = new Object();
32         private Interop.Database.ContactsDBStatusChangedCallback _contactsDBStatusChangedCallback;
33         private event EventHandler<DBStatusChangedEventArgs> _dbStatusChanged;
34         private Dictionary<string, ContactsDBChangedDelegate> _callbackMap = new Dictionary<string, ContactsDBChangedDelegate>();
35         private Dictionary<string, Interop.Database.ContactsDBChangedCallback> _delegateMap = new Dictionary<string, Interop.Database.ContactsDBChangedCallback>();
36         private Interop.Database.ContactsDBChangedCallback _dbChangedDelegate;
37         /// <summary>
38         /// Delegete for detecting the contacts database changes
39         /// </summary>
40         /// <param name="uri">The contacts view URI</param>
41         /// <remarks>
42         /// The delegate must be registered using AddDBChangedDelegate.
43         /// It's invoked when the designated view changes.
44         /// </remarks>
45         /// <see cref="AddDBChangedDelegate"/>
46         public delegate void ContactsDBChangedDelegate(string uri);
47
48         internal ContactsDatabase()
49         {
50             ///To be created in ContactsManager only.
51         }
52
53         /// <summary>
54         /// Enumeration for contacts database status.
55         /// </summary>
56         public enum DBStatus
57         {
58             /// <summary>
59             /// Normal
60             /// </summary>
61             Normal,
62             /// <summary>
63             /// Changing collation.
64             /// </summary>
65             ChangingCollation
66         }
67
68         /// <summary>
69         /// Enumeration for Contacts search range.
70         /// </summary>
71         public enum SearchRange
72         {
73             /// <summary>
74             /// Search record from name
75             /// </summary>
76             Name = 0x00000001,
77             /// <summary>
78             /// Search record from number
79             /// </summary>
80             Number = 0x00000002,
81             /// <summary>
82             /// Search record from data
83             /// </summary>
84             Data = 0x00000004,
85             /// <summary>
86             /// Search record from email. Now, support only PersonEmail view
87             /// </summary>
88             Email = 0x00000008,
89         }
90
91         /// <summary>
92         /// Occurs when contacts database status is changed.
93         /// </summary>
94         public event EventHandler<DBStatusChangedEventArgs> DBStatusChanged
95         {
96             add
97             {
98                 lock (thisLock)
99                 {
100                     _contactsDBStatusChangedCallback = (DBStatus status, IntPtr userData) =>
101                     {
102                         DBStatusChangedEventArgs args = new DBStatusChangedEventArgs(status);
103                         _dbStatusChanged?.Invoke(this, args);
104                     };
105
106                     int error = Interop.Database.AddStatusChangedCb(_contactsDBStatusChangedCallback, IntPtr.Zero);
107                     if ((int)ContactsError.None != error)
108                     {
109                         Log.Error(Globals.LogTag, "Add StatusChanged Failed with error " + error);
110                     }
111                     else
112                     {
113                         _dbStatusChanged += value;
114                     }
115                 }
116
117             }
118
119             remove
120             {
121                 lock (thisLock)
122                 {
123                     int error = Interop.Database.RemoveStatusChangedCb(_contactsDBStatusChangedCallback, IntPtr.Zero);
124                     if ((int)ContactsError.None != error)
125                     {
126                         Log.Error(Globals.LogTag, "Remove StatusChanged Failed with error " + error);
127                     }
128
129                     _dbStatusChanged -= value;
130                 }
131             }
132
133         }
134
135         /// <summary>
136         /// The current contacts database version.
137         /// </summary>
138         public int Version
139         {
140             get
141             {
142                 int version = -1;
143                 int error = Interop.Database.GetVersion(out version);
144                 if ((int)ContactsError.None != error)
145                 {
146                     Log.Error(Globals.LogTag, "Version Failed with error " + error);
147                 }
148                 return version;
149             }
150         }
151
152         /// <summary>
153         /// The last successful changed contacts database version on the current connection.
154         /// </summary>
155         public int LastChangeVersion
156         {
157             get
158             {
159                 int version = -1;
160                 int error = Interop.Database.GetLastChangeVersion(out version);
161                 if ((int)ContactsError.None != error)
162                 {
163                     Log.Error(Globals.LogTag, "LastChangeVersion Failed with error " + error);
164                 }
165                 return version;
166             }
167         }
168
169         /// <summary>
170         /// The contacts database status.
171         /// </summary>
172         public DBStatus Status
173         {
174             get
175             {
176                 DBStatus status = DBStatus.Normal;
177                 int error = Interop.Database.GetStatus(out status);
178                 if ((int)ContactsError.None != error)
179                 {
180                     Log.Error(Globals.LogTag, "GetStatus Failed with error " + error);
181                 }
182                 return status;
183             }
184         }
185
186         /// <summary>
187         /// Inserts a record into the contacts database.
188         /// </summary>
189         /// <param name="record">The record to insert</param>
190         /// <returns>The ID of inserted record</returns>
191         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
192         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
193         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
194         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
195         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
196         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
197         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
198         public int Insert(ContactsRecord record)
199         {
200             int id = -1;
201             int error = Interop.Database.Insert(record._recordHandle, out id);
202             if ((int)ContactsError.None != error)
203             {
204                 Log.Error(Globals.LogTag, "Insert Failed with error " + error);
205                 throw ContactsErrorFactory.CheckAndCreateException(error);
206             }
207             return id;
208         }
209
210         /// <summary>
211         /// Inserts multiple records into the contacts database as a batch operation.
212         /// </summary>
213         /// <param name="list">The record list</param>
214         /// <returns>The inserted record ID array</returns>
215         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
216         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
217         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
218         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
219         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
220         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
221         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
222         public int[] Insert(ContactsList list)
223         {
224             IntPtr ids;
225             int count;
226             int error = Interop.Database.InsertRecords(list._listHandle, out ids, out count);
227             if ((int)ContactsError.None != error)
228             {
229                 Log.Error(Globals.LogTag, "Insert Failed with error " + error);
230                 throw ContactsErrorFactory.CheckAndCreateException(error);
231             }
232
233             int[] idArr = new int[count];
234             Marshal.Copy(ids, idArr, 0, count);
235
236             return idArr;
237         }
238
239         /// <summary>
240         /// Gets a record from the contacts database.
241         /// </summary>
242         /// <param name="viewUri">The view URI of a record</param>
243         /// <param name="recordId">The record ID</param>
244         /// <returns>The record associated with the record ID</returns>
245         /// <privilege>http://tizen.org/privilege/contact.read</privilege>
246         /// <privilege>http://tizen.org/privilege/callhistory.read</privilege>
247         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
248         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
249         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
250         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
251         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
252         public ContactsRecord Get(string viewUri, int recordId)
253         {
254             IntPtr handle;
255             int error = Interop.Database.Get(viewUri, recordId, out handle);
256             if ((int)ContactsError.None != error)
257             {
258                 Log.Error(Globals.LogTag, "Get Failed with error " + error);
259                 throw ContactsErrorFactory.CheckAndCreateException(error);
260             }
261             return new ContactsRecord(handle);
262         }
263
264         /// <summary>
265         /// Updates a record in the contacts database.
266         /// </summary>
267         /// <param name="record">The record to update</param>
268         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
269         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
270         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
271         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
272         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
273         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
274         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
275         public void Update(ContactsRecord record)
276         {
277             int error = Interop.Database.Update(record._recordHandle);
278             if ((int)ContactsError.None != error)
279             {
280                 Log.Error(Globals.LogTag, "Update Failed with error " + error);
281                 throw ContactsErrorFactory.CheckAndCreateException(error);
282             }
283         }
284
285         /// <summary>
286         /// Updates multiple records in the contacts database as a batch operation.
287         /// </summary>
288         /// <param name="list">The record list</param>
289         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
290         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
291         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
292         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
293         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
294         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
295         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
296         public void Update(ContactsList list)
297         {
298             int error = Interop.Database.UpdateRecords(list._listHandle);
299             if ((int)ContactsError.None != error)
300             {
301                 Log.Error(Globals.LogTag, "Update Failed with error " + error);
302                 throw ContactsErrorFactory.CheckAndCreateException(error);
303             }
304         }
305
306         /// <summary>
307         /// Deletes a record from the contacts database with related child records.
308         /// </summary>
309         /// <param name="viewUri">The view URI of a record</param>
310         /// <param name="recordId">The record ID to delete</param>
311         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
312         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
313         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
314         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
315         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
316         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
317         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
318         public void Delete(string viewUri, int recordId)
319         {
320             int error = Interop.Database.Delete(viewUri, recordId);
321             if ((int)ContactsError.None != error)
322             {
323                 Log.Error(Globals.LogTag, "Delete Failed with error " + error);
324                 throw ContactsErrorFactory.CheckAndCreateException(error);
325             }
326         }
327
328         /// <summary>
329         /// Deletes multiple records with related child records from the contacts database as a batch operation.
330         /// </summary>
331         /// <param name="viewUri">The view URI of the records to delete</param>
332         /// <param name="idArray">The record IDs to delete</param>
333         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
334         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
335         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
336         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
337         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
338         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
339         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
340         public void Delete(string viewUri, int[] idArray)
341         {
342             int error = Interop.Database.DeleteRecords(viewUri, idArray, idArray.Length);
343             if ((int)ContactsError.None != error)
344             {
345                 Log.Error(Globals.LogTag, "Delete Failed with error " + error);
346                 throw ContactsErrorFactory.CheckAndCreateException(error);
347             }
348         }
349
350         /// <summary>
351         /// Replaces a record in the contacts database.
352         /// </summary>
353         /// <param name="record">The record to replace</param>
354         /// <param name="recordId">the record ID to be replaced</param>
355         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
356         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
357         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
358         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
359         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
360         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
361         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
362         public void Replace(ContactsRecord record, int recordId)
363         {
364             int error = Interop.Database.Replace(record._recordHandle, recordId);
365             if ((int)ContactsError.None != error)
366             {
367                 Log.Error(Globals.LogTag, "Replace Failed with error " + error);
368                 throw ContactsErrorFactory.CheckAndCreateException(error);
369             }
370         }
371
372         /// <summary>
373         /// Replaces multiple records in the contacts database as a batch operation.
374         /// </summary>
375         /// <param name="list">The record list to replace</param>
376         /// <param name="idArray">The record IDs to be replaced</param>
377         /// <privilege>http://tizen.org/privilege/contact.write</privilege>
378         /// <privilege>http://tizen.org/privilege/callhistory.write</privilege>
379         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
380         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
381         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
382         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
383         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
384         public void Replace(ContactsList list, int[] idArray)
385         {
386             int error = Interop.Database.ReplaceRecords(list._listHandle, idArray, idArray.Length);
387             if ((int)ContactsError.None != error)
388             {
389                 Log.Error(Globals.LogTag, "Replace Failed with error " + error);
390                 throw ContactsErrorFactory.CheckAndCreateException(error);
391             }
392         }
393
394         /// <summary>
395         /// Retrieves all records as a list.
396         /// </summary>
397         /// <param name="viewUri">The view URI to get records</param>
398         /// <param name="offset">The index from which results</param>
399         /// <param name="limit">The number to limit results(value 0 is used for all records)</param>
400         /// <returns>
401         /// The record list
402         /// </returns>
403         /// <privilege>http://tizen.org/privilege/contact.read</privilege>
404         /// <privilege>http://tizen.org/privilege/callhistory.read</privilege>
405         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
406         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
407         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
408         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
409         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
410         public ContactsList GetAll(string viewUri, int offset, int limit)
411         {
412             IntPtr handle;
413             int error = Interop.Database.GetRecords(viewUri, offset, limit, out handle);
414             if ((int)ContactsError.None != error)
415             {
416                 Log.Error(Globals.LogTag, "GetAll Failed with error " + error);
417                 throw ContactsErrorFactory.CheckAndCreateException(error);
418             }
419             return new ContactsList(handle);
420         }
421
422         /// <summary>
423         /// Retrieves records using a query.
424         /// </summary>
425         /// <param name="query">The query to filter the results</param>
426         /// <param name="offset">The index from which to get results</param>
427         /// <param name="limit">The number to limit results(value 0 is used for get all records)</param>
428         /// <returns>
429         /// The record list
430         /// </returns>
431         /// <privilege>http://tizen.org/privilege/contact.read</privilege>
432         /// <privilege>http://tizen.org/privilege/callhistory.read</privilege>
433         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
434         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
435         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
436         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
437         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
438         public ContactsList GetRecordsWithQuery(ContactsQuery query, int offset, int limit)
439         {
440             IntPtr handle;
441             int error = Interop.Database.GetRecords(query._queryHandle, offset, limit, out handle);
442             if ((int)ContactsError.None != error)
443             {
444                 Log.Error(Globals.LogTag, "GetAllWithQuery Failed with error " + error);
445                 throw ContactsErrorFactory.CheckAndCreateException(error);
446             }
447             return new ContactsList(handle);
448         }
449
450         /// <summary>
451         /// Retrieves records changes since the given database version.
452         /// </summary>
453         /// <param name="viewUri">The view URI to get records</param>
454         /// <param name="addressbookId">The address book ID to filter</param>
455         /// <param name="contactsDBVersion">The contacts database version</param>
456         /// <param name="currentDBVersion">The current contacts database version</param>
457         /// <returns>
458         /// The record list
459         /// </returns>
460         /// <privilege>http://tizen.org/privilege/contact.read</privilege>
461         /// <exception cref="InvalidOperationException">Thrown when method failed due to invalid operation</exception>
462         /// <exception cref="NotSupportedException">Thrown when an invoked method is not supported</exception>
463         /// <exception cref="ArgumentException">Thrown when one of the arguments provided to a method is not valid</exception>
464         /// <exception cref="OutOfMemoryException">Thrown when failed due to out of memory</exception>
465         /// <exception cref="UnauthorizedAccessException">Thrown when application does not have proper privileges</exception>
466         public ContactsList GetChangesByVersion(string viewUri, int addressbookId, int contactsDBVersion, out int currentDBVersion)
467         {
468             IntPtr recordList;
469             int error = Interop.Database.GetChangesByVersion(viewUri, addressbookId, contactsDBVersion, out recordList,out currentDBVersion);
470             if ((int)ContactsError.None != error)
471             {
472                 Log.Error(Globals.LogTag, "GetChangesByVersion Failed with error " + error);
473                 throw ContactsErrorFactory.CheckAndCreateException(error);
474             }
475             return new ContactsList(recordList);
476         }
477
478         /// <summary>
479         /// Finds records based on a given keyword.
480         /// </summary>
481         /// <remarks>
482         /// This API works only for the Views below.
483         /// Person, PersonContact, PersonGroupRelation, PersonGroupAssigned and PersonGroupNotAssigned.
484         /// </remarks>
485         /// <param name="viewUri">The view URI to find records</param>
486         /// <param name="keyword">The keyword</param>
487         /// <param name="offset">The index from which to get results</param>
488         /// <param name="limit">The number to limit results(value 0 is used for get all records)</param>
489         /// <returns></returns>
490         /// <privilege>http://tizen.org/privilege/contact.read</privilege>
491         public ContactsList Search(string viewUri, string keyword, int offset, int limit)
492         {
493             IntPtr recordList;
494             int error = Interop.Database.Search(viewUri, keyword, offset, limit, out recordList);
495             if ((int)ContactsError.None != error)
496             {
497                 Log.Error(Globals.LogTag, "Search Failed with error " + error);
498                 throw ContactsErrorFactory.CheckAndCreateException(error);
499             }
500             return new ContactsList(recordList);
501         }
502
503         /// <summary>
504         /// Finds records based on given query and keyword.
505         /// </summary>
506         /// <remarks>
507         /// This API works only for the Views below.
508         /// Person, PersonContact, PersonGroupRelation, PersonGroupAssigned and PersonGroupNotAssigned.
509         /// </remarks>
510         /// <param name="query">The query to filter</param>
511         /// <param name="keyword">The keyword</param>
512         /// <param name="offset">The index from which to get results</param>
513         /// <param name="limit">The number to limit results(value 0 used for get all records)</param>
514         /// <returns>The record list</returns>
515         public ContactsList Search(ContactsQuery query, string keyword, int offset, int limit)
516         {
517             IntPtr recordList;
518             int error = Interop.Database.Search(query._queryHandle, keyword, offset, limit, out recordList);
519             if ((int)ContactsError.None != error)
520             {
521                 Log.Error(Globals.LogTag, "Search Failed with error " + error);
522                 throw ContactsErrorFactory.CheckAndCreateException(error);
523             }
524             return new ContactsList(recordList);
525         }
526
527         /// <summary>
528         /// Finds records based on a keyword and range.
529         /// </summary>
530         /// <remarks>
531         /// This API works only for the Views below.
532         /// Person, PersonContact, PersonGroupRelation, PersonGroupAssigned, PersonGroupNotAssigned, PersonNumber and PersonEmail
533         /// </remarks>
534         /// <param name="viewUri">The view URI</param>
535         /// <param name="keyword">The keyword</param>
536         /// <param name="offset">The index from which to get results</param>
537         /// <param name="limit">The number to limit results(value 0 is used for get all records)</param>
538         /// <param name="range">The search range, it should be a element of SearchRange or bitwise OR operation of them</param>
539         /// <returns>The record list</returns>
540         public ContactsList Search(string viewUri, string keyword, int offset, int limit, int range)
541         {
542             IntPtr recordList;
543             int error = Interop.Database.Search(viewUri, keyword, offset, limit, range, out recordList);
544             if ((int)ContactsError.None != error)
545             {
546                 Log.Error(Globals.LogTag, "Search Failed with error " + error);
547                 throw ContactsErrorFactory.CheckAndCreateException(error);
548             }
549             return new ContactsList(recordList);
550         }
551
552         /// <summary>
553         /// Finds records based on a given keyword for snippet
554         /// </summary>
555         /// <remarks>
556         /// This API works only for the Views below.
557         /// Person, PersonContact, PersonGroupRelation, PersonGroupAssigned and PersonGroupNotAssigned.
558         /// Because start match and end match are needed to be composed with keyword, this API performance is lower than Search(string viewUri, string keyword, int offset, int limit).
559         /// </remarks>
560         /// <param name="viewUri">The view URI to find records</param>
561         /// <param name="keyword">The keyword</param>
562         /// <param name="offset">The index from which to get results</param>
563         /// <param name="limit">The number to limit results(value 0 used for get all records)</param>
564         /// <param name="startMatch">The text which is inserted into the fragment before the keyword(If NULL, default is "[")</param>
565         /// <param name="endMatch">The text which is inserted into the fragment after the keyword(If NULL, default is "]")</param>
566         /// <param name="tokenNumber">The one side extra number of tokens near keyword(If negative value, full sentence is printed. e.g. if token number is 3 with 'abc' keyword, "my name is [abc]de and my home")</param>
567         /// <returns>The record list</returns>
568         public ContactsList Search(string viewUri, string keyword, int offset, int limit, string startMatch, string endMatch, int tokenNumber)
569         {
570             IntPtr recordList;
571             int error = Interop.Database.Search(viewUri, keyword, offset, limit, startMatch, endMatch, tokenNumber, out recordList);
572             if ((int)ContactsError.None != error)
573             {
574                 Log.Error(Globals.LogTag, "Search Failed with error " + error);
575                 throw ContactsErrorFactory.CheckAndCreateException(error);
576             }
577             return new ContactsList(recordList);
578         }
579
580         /// <summary>
581         /// Finds records based on given query and keyword for snippet.
582         /// </summary>
583         /// <remarks>
584         /// This API works only for the Views below.
585         /// Person, PersonContact, PersonGroupRelation, PersonGroupAssigned and PersonGroupNotAssigned.
586         /// Because start match and end match are needed to be composed with keyword, this API performance is lower than Search(ContactsQuery query, string keyword, int offset, int limit).
587         /// </remarks>
588         /// <param name="query">The query to filter</param>
589         /// <param name="keyword">The keyword</param>
590         /// <param name="offset">The index from which to get results</param>
591         /// <param name="limit">The number to limit results(value 0 used for get all records)</param>
592         /// <param name="startMatch">The text which is inserted into the fragment before the keyword(If NULL, default is "[")</param>
593         /// <param name="endMatch">The text which is inserted into the fragment after the keyword(If NULL, default is "]")</param>
594         /// <param name="tokenNumber">The one side extra number of tokens near keyword(If negative value, full sentence is printed. e.g. if token number is 3 with 'abc' keyword, "my name is [abc]de and my home")</param>
595         /// <returns>The record list</returns>
596         public ContactsList Search(ContactsQuery query, string keyword, int offset, int limit, string startMatch, string endMatch, int tokenNumber)
597         {
598             IntPtr recordList;
599             int error = Interop.Database.Search(query._queryHandle, keyword, offset, limit, startMatch, endMatch, tokenNumber, out recordList);
600             if ((int)ContactsError.None != error)
601             {
602                 Log.Error(Globals.LogTag, "Search Failed with error " + error);
603                 throw ContactsErrorFactory.CheckAndCreateException(error);
604             }
605             return new ContactsList(recordList);
606         }
607
608         /// <summary>
609         /// Finds records based on a keyword and range for snippet.
610         /// </summary>
611         /// <remarks>
612         /// This API works only for the Views below.
613         /// Person, PersonContact, PersonGroupRelation, PersonGroupAssigned, PersonGroupNotAssigned, PersonNumber and PersonEmail
614         /// Because start match and end match are needed to be composed with keyword, this API performance is lower than Search(string viewUri, string keyword, int offset, int limit, int range).
615         /// </remarks>
616         /// <param name="viewUri">The view URI</param>
617         /// <param name="keyword">The keyword</param>
618         /// <param name="offset">The index from which to get results</param>
619         /// <param name="limit">The number to limit results(value 0 is used for get all records)</param>
620         /// <param name="range">The search range, it should be a element of SearchRange or bitwise OR operation of them</param>
621         /// <param name="startMatch">The text which is inserted into the fragment before the keyword(If NULL, default is "[")</param>
622         /// <param name="endMatch">The text which is inserted into the fragment after the keyword(If NULL, default is "]")</param>
623         /// <param name="tokenNumber">The one side extra number of tokens near keyword(If negative value, full sentence is printed. e.g. if token number is 3 with 'abc' keyword, "my name is [abc]de and my home")</param>
624         /// <returns>The record list</returns>
625         public ContactsList Search(string viewUri, string keyword, int offset, int limit, int range, string startMatch, string endMatch, int tokenNumber)
626         {
627             IntPtr recordList;
628             int error = Interop.Database.Search(viewUri, keyword, offset, limit, range, startMatch, endMatch, tokenNumber, out recordList);
629             if ((int)ContactsError.None != error)
630             {
631                 Log.Error(Globals.LogTag, "Search Failed with error " + error);
632                 throw ContactsErrorFactory.CheckAndCreateException(error);
633             }
634             return new ContactsList(recordList);
635         }
636
637         /// <summary>
638         /// Gets the number of records in a specific view
639         /// </summary>
640         /// <param name="viewUri">The view URI</param>
641         /// <returns>The count of records</returns>
642         public int GetCount(string viewUri)
643         {
644             int count = -1;
645             int error = Interop.Database.GetCount(viewUri, out count);
646             if ((int)ContactsError.None != error)
647             {
648                 Log.Error(Globals.LogTag, "GetCount Failed with error " + error);
649                 throw ContactsErrorFactory.CheckAndCreateException(error);
650             }
651             return count;
652         }
653
654         /// <summary>
655         /// Gets the number of records matching a query.
656         /// </summary>
657         /// <param name="query">The query used for filtering the results</param>
658         /// <returns>The count of records</returns>
659         public int GetCount(ContactsQuery query)
660         {
661             int count = -1;
662             int error = Interop.Database.GetCount(query._queryHandle, out count);
663             if ((int)ContactsError.None != error)
664             {
665                 Log.Error(Globals.LogTag, "GetCount Failed with error " + error);
666                 throw ContactsErrorFactory.CheckAndCreateException(error);
667             }
668             return count;
669         }
670
671         /// <summary>
672         /// Registers a callback function to be invoked when a record changes.
673         /// </summary>
674         /// <param name="viewUri">The view URI of records whose changes are monitored</param>
675         /// <param name="callback">The callback function to register</param>
676         public void AddDBChangedDelegate(string viewUri, ContactsDBChangedDelegate callback)
677         {
678             _dbChangedDelegate = (string uri, IntPtr userData) =>
679             {
680                 _callbackMap[uri](uri);
681             };
682             int error = Interop.Database.AddChangedCb(viewUri, _dbChangedDelegate, IntPtr.Zero);
683             if ((int)ContactsError.None != error)
684             {
685                 Log.Error(Globals.LogTag, "AddDBChangedDelegate Failed with error " + error);
686                 throw ContactsErrorFactory.CheckAndCreateException(error);
687             }
688             _callbackMap[viewUri] = callback;
689             _delegateMap[viewUri] = _dbChangedDelegate;
690         }
691
692         /// <summary>
693         /// Unregisters a callback function.
694         /// </summary>
695         /// <param name="viewUri">The view URI of records whose changes are monitored</param>
696         /// <param name="callback">The callback function to register</param>
697         public void RemoveDBChangedDelegate(string viewUri, ContactsDBChangedDelegate callback)
698         {
699             int error = Interop.Database.RemoveChangedCb(viewUri, _delegateMap[viewUri], IntPtr.Zero);
700             if ((int)ContactsError.None != error)
701             {
702                 Log.Error(Globals.LogTag, "RemoveDBChangedDelegate Failed with error " + error);
703                 throw ContactsErrorFactory.CheckAndCreateException(error);
704             }
705             _callbackMap.Remove(viewUri);
706             _delegateMap.Remove(viewUri);
707         }
708     }
709 }