2 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 // Licensed under the Flora License, Version 1.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
8 // http://floralicense.org/license/
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.
18 * @file PhnRetrieveSuggestionsTasks.cpp
19 * @brief RetrieveContactsListTask class
21 #include "PhnAppUtility.h"
22 #include "PhnCalllogManager.h"
23 #include "PhnCommonUtils.h"
24 #include "PhnDialContactInfo.h"
25 #include "PhnRetrieveSuggestionsTasks.h"
26 #include "PhnSettingsManager.h"
29 using namespace Tizen::Base;
30 using namespace Tizen::Base::Collection;
31 using namespace Tizen::Graphics;
32 using namespace Tizen::Social;
35 RetrieveContactsListTask::RetrieveContactsListTask(ISuggestionsRetrievedEventListener& pEventListener)
36 : __pEventListener(pEventListener), __pContactsList(null), __pNumberStr(null)
40 RetrieveContactsListTask::~RetrieveContactsListTask()
46 if (__pAddressBook != null)
48 delete __pAddressBook;
53 RetrieveContactsListTask::Construct(String& searchString,const IList* oldSearchResults)
57 __pAddressBook = new (std::nothrow) Addressbook();
58 r = __pAddressBook->Construct();
59 TryCatch (r == E_SUCCESS,, "AddressBook.Contruct() failed");
60 //new search string and result list
61 __pNumberStr = new (std::nothrow) String(searchString);
62 __pContactsList = new (std::nothrow) ArrayList(SingleObjectDeleter);
63 r = __pContactsList->Construct();
64 TryCatch (r == E_SUCCESS,,"ArrayList.Contruct() failed");
66 //Copy old search result, if available
67 if(oldSearchResults != null)
69 IEnumerator* pOldResultsEnum = oldSearchResults->GetEnumeratorN();
70 while(pOldResultsEnum->MoveNext() == E_SUCCESS)
72 DialContactInfo* pContactInfo = (static_cast<DialContactInfo*>(pOldResultsEnum->GetCurrent()))->CloneN();
73 if(pContactInfo != null)
75 __pContactsList->Add(pContactInfo);
78 delete pOldResultsEnum;
84 delete __pAddressBook;
86 delete __pContactsList;
91 RetrieveContactsListTask::Run(void)
93 //check if this is a new search
94 if(__pContactsList != null && __pContactsList->GetCount() > 0)
96 //filter out suggestion list
97 UpdateSuggestionList();
101 //search for Speed dial number -> 1st Priority in Result List.
102 SearchSpeedDialForNumberN();
104 if(__pNumberStr->GetLength() > 0)
106 //searches contacts by name -> 2nd Priority in result list
107 SearchContactsForName();
108 //Searches contacts by number -> 3rd Priority in result list
109 SearchContactsForNumber();
111 //TODO: Search logs by number - Last Priority in the list
112 //Only Unknown Numbers are added, since known numbers will be added from above searches
113 /*SearchCallLogsForNumber();*/
116 //Inform listener about search completion.
117 __pEventListener.HandleContactsRetrievalCompleted(__pContactsList);
118 __pContactsList = null;
123 RetrieveContactsListTask::UpdateSuggestionList(void)
125 //search through each list to filter out suggestions not matching new search string.
126 for (int index = 0; index < __pContactsList->GetCount(); index++)
128 DialContactInfo* pContact = static_cast<DialContactInfo*>(__pContactsList->GetAt(index));
133 //Fetch search key list
134 IList* pKeyList = pContact->GetSearchKeyList();
136 while(nextKey < pKeyList->GetCount())
138 bool isRemoveKey = false;
139 //search for Speed dial
140 String* keyWord = static_cast<String*>(pKeyList->GetAt(nextKey));
141 if(keyWord->Equals(String(IDS_SPEED_DIAL_SEARCH_KEY)) == true && __pNumberStr->GetLength() > 1)
145 else if((__pNumberStr->GetLength() > 0) && (DialUtil::IsNumericString(*keyWord) == true))
147 //search for number - update list
148 if (pContact->GetPhoneNumber().Contains(*__pNumberStr) == false)
154 //update search keys.
155 pContact->ReplaceSearchKey(nextKey, *__pNumberStr);
161 //substring of contact name to match
163 //numeric keys typed, equivalent to above 'subName'.
165 String contactName = pContact->GetDisplayName();
166 contactName.SubString(0,__pNumberStr->GetLength(),subName);
167 DialUtil::ConvertNameToNumericKeys(subName,numericKey);
168 if(numericKey.Equals(*__pNumberStr) == true)
170 //update search keys.
171 pContact->ReplaceSearchKey(nextKey, subName);
179 //remove previous search key, as updated key did'nt match.
180 if(isRemoveKey == true)
182 pContact->RemoveSearchKey(nextKey);
190 //Add to contacts list to be removed
191 if(pKeyList->GetCount() <= 0)
193 __pContactsList->RemoveAt(index);
198 //Need to sort arraylist according to latest search keys.
199 if(__pContactsList->GetCount() > 0)
201 SuggestionListComparer* pComparer = new (std::nothrow) SuggestionListComparer();
202 __pContactsList->Sort(*pComparer);
207 //remove old search key
214 RetrieveContactsListTask::SearchContactsForNumber(void)
216 //Searches contacts by (part of)phone number.
217 IList* pResultList = __pAddressBook->SearchContactsByPhoneNumberN(*__pNumberStr);
218 if(pResultList != null && pResultList->GetCount() > 0)
220 SaveContactsToListByNumber(*pResultList, *__pNumberStr);
221 pResultList->RemoveAll(true);
227 RetrieveContactsListTask::SearchContactsForName(void)
229 // If phoneNumber: "23" -> Possible string matches -> 9.
230 // It is much better to do first 3(2=A,B,C) search in 1000 fields(in database), and
231 // subsequent 9 searches in locally stored array of fewer records.
232 // then to 9 search searches in 1000 fields(in database).
234 //Fetch matching names for mapping char for first digit, e.g. 2->ABC, 3->DEF.
237 __pNumberStr->SubString(0,1,strDigit);
238 Integer::Parse(strDigit,digit);
239 IList* pNamesList = DialUtil::FetchPossibleNamesListN(L"",digit);
240 if (pNamesList != null)
242 int totalMatches = pNamesList->GetCount();
243 for (int index = 0; index < totalMatches; index++)
245 //Search All names that start with single character
246 String* searchKey = static_cast<String*>(pNamesList->GetAt(index));
247 SearchContactsWithInitialChar(*searchKey);
249 pNamesList->RemoveAll();
255 RetrieveContactsListTask::SearchContactsWithInitialChar(String& searchStr)
257 //search for contacts which contains 'searchStr' anywhere in displayName.
258 IList* pResultList = __pAddressBook->SearchContactsByNameN(searchStr);
259 //Check if empty list.
260 if(pResultList == null || pResultList->GetCount() <= 0)
266 //further filter out result list - save contacts starting with 'searchStr'.
267 ArrayList* pDialInfoList = new (std::nothrow) ArrayList();
268 pDialInfoList->Construct();
270 for(int index = 0; index < pResultList->GetCount(); index++)
272 Contact* pContact = static_cast<Contact*>(pResultList->GetAt(index));
273 //Check if display name starts with search string
275 result r = pContact->GetValue(CONTACT_PROPERTY_ID_DISPLAY_NAME, contactName);
276 if ((r == E_SUCCESS) && (contactName.StartsWith(searchStr, 0) == true))
278 //substring of contact name to match
280 //numeric keys typed, equivalent to above 'subName'.
282 contactName.SubString(0,__pNumberStr->GetLength(),subName);
283 DialUtil::ConvertNameToNumericKeys(subName,numericKey);
284 if(numericKey.Equals(*__pNumberStr) == true)
286 DialContactInfo* pDialInfo = ConvertToDialContactN(*pContact,subName);
287 if(pDialInfo != null)
289 pDialInfoList->Add(*pDialInfo);
294 pResultList->RemoveAll(true);
298 if(pDialInfoList->GetCount() > 0 && __pContactsList != null)
300 //remove duplicate items
301 pDialInfoList->RemoveItems(*__pContactsList,true);
302 //Add all distinct item to list
303 __pContactsList->AddItems(*pDialInfoList);
304 //remove ownership for all items.
305 pDialInfoList->RemoveAll();
307 delete pDialInfoList;
311 RetrieveContactsListTask::SearchSpeedDialForNumberN(void)
313 //Check if only 1 digit number
314 if(__pNumberStr->GetLength() != 1)
318 //convert to speed dial rowId
320 Integer::Parse(*__pNumberStr, rowId);
321 if (rowId < 2 || rowId > 9)
326 //Fetch matched speed dial contact number
327 SettingsManager* pSettingsManager = SettingsManager::GetInstance();
328 String* contactNo = pSettingsManager->GetMappedSpeedDialNumberN(rowId);
329 if (contactNo == null)
334 //Fetch Contact for phoneNumber
335 IList* pContactList = __pAddressBook->SearchContactsByPhoneNumberN(*contactNo);
336 if (pContactList != null)
338 IEnumerator* pContactsEnum = pContactList->GetEnumeratorN();
339 while (pContactsEnum->MoveNext() == E_SUCCESS)
341 Contact* pContact = static_cast<Contact*>(pContactsEnum->GetCurrent());
344 //save to HashMap - ownership transferred of key-value pair.
345 DialContactInfo* pDialContact = ConvertToDialContactN(*pContact,*contactNo);
346 if(pDialContact != null)
348 IList* keyList = pDialContact->GetSearchKeyList();
349 keyList->SetAt(*(new String(IDS_SPEED_DIAL_SEARCH_KEY)),(keyList->GetCount()-1), true);
350 __pContactsList->Add(pDialContact);
356 delete pContactsEnum;
357 pContactList->RemoveAll(true);
364 RetrieveContactsListTask::SearchCallLogsForNumber(void)
366 //conversion "contactNumber" to char*
367 const wchar_t* pContact = __pNumberStr->GetPointer();
368 int len = __pNumberStr->GetLength()+1;
369 char* pNumber = new (std::nothrow) char[len];
370 wcstombs(pNumber, pContact, len);
372 //fetch Unknown numbers from Call logs Manager containing search string.
373 HashMapT<int, CallLogDetails>* pLogsByNumber = CallLogManager::GetInstance()->GetCallogListByUnknownNumberFromDatabaseN(pNumber);
374 if(pLogsByNumber != null)
376 IListT<CallLogDetails>* logDetailsList = pLogsByNumber->GetValuesN();
377 if(logDetailsList != null)
379 //Convert to DialContacts
380 for(int index=0;index<logDetailsList->GetCount();index++)
382 CallLogDetails logDetails;
383 result r = logDetailsList->GetAt(index,logDetails);
386 DialContactInfo* pDialContact = ConvertLogDetailsToDialContactN(logDetails);
387 if(pDialContact != null)
389 if((__pContactsList->GetCount() <= 0) || (__pContactsList->Contains(*pDialContact) == false))
391 //Add only 'unknown' number to Map
392 __pContactsList->Add(pDialContact);
402 delete logDetailsList;
404 delete pLogsByNumber;
409 RetrieveContactsListTask::SaveContactsToListByNumber(IList& saveList, String& matchedString)
411 if(__pContactsList != null)
413 //List of contacts to be saved
414 for (int index = 0; index < saveList.GetCount(); index++)
416 Contact* pContact = static_cast<Contact*>(saveList.GetAt(index));
417 DialContactInfo* pDialContact = ConvertToDialContactN(*pContact, matchedString);
418 if (pDialContact != null)
420 //check if already present
422 if (__pContactsList->IndexOf(*pDialContact, foundItemIndex) != E_SUCCESS)
425 __pContactsList->Add(pDialContact);
429 //Add search key to existing list
430 DialContactInfo* pExistingInfo = static_cast<DialContactInfo*>(__pContactsList->GetAt( foundItemIndex));
431 if (pExistingInfo != null)
433 pExistingInfo->AddSearchKey(*(pDialContact->GetSearchKey()));
443 RetrieveContactsListTask::ConvertToDialContactN(Contact& contact, String& matchedString)
445 result r = E_FAILURE;
449 r = contact.GetValue(CONTACT_PROPERTY_ID_DISPLAY_NAME, displayName);
450 TryReturn(r == E_SUCCESS,null,"Display name not available");
453 String phoneNumber(L"");
454 IList* pNumberList = contact.GetValuesN(CONTACT_MPROPERTY_ID_PHONE_NUMBERS);
455 if(pNumberList == null || pNumberList->GetCount() <= 0)
461 if(DialUtil::IsNumericString(matchedString) == true)
463 //this contact searched by phone number
464 IEnumerator* pPhoneEnum = pNumberList->GetEnumeratorN();
465 while (E_SUCCESS == pPhoneEnum->MoveNext())
467 PhoneNumber* pPhoneNumber = (PhoneNumber*) pPhoneEnum->GetCurrent();
468 //Check if this is the correct contact
469 if (pPhoneNumber->GetPhoneNumber().Contains(matchedString) == true)
471 phoneNumber.Append(pPhoneNumber->GetPhoneNumber());
479 //this contact searched by name
480 PhoneNumber* pContactNo = static_cast<PhoneNumber*>(pNumberList->GetAt(0));
481 phoneNumber.Append(pContactNo->GetPhoneNumber());
483 pNumberList->RemoveAll(true);
486 TryReturn((phoneNumber.IsEmpty() == false), null, "No matching phone number found");
488 DialContactInfo* pDialContact = new (std::nothrow) DialContactInfo();
489 pDialContact->AddSearchKey(matchedString);
490 pDialContact->SetPhoneNumber(phoneNumber);
491 pDialContact->SetDisplayName(displayName);
493 //Check if Thumbnail is present
494 Bitmap* pThumbnail = contact.GetThumbnailN();
495 if(pThumbnail != null)
497 pDialContact->SetThumbnail(pThumbnail);
503 RetrieveContactsListTask::ConvertLogDetailsToDialContactN(CallLogDetails& logDetails)
505 DialContactInfo* pDialContact = new (std::nothrow) DialContactInfo();
506 String emptyDisplayName(L"");
507 pDialContact->SetDisplayName(emptyDisplayName);
509 pDialContact->SetCallLogDbId(logDetails.GetCalllogDbId());
511 String phoneNumber(logDetails.GetPhoneNumber());
512 pDialContact->SetPhoneNumber(phoneNumber);
513 pDialContact->AddSearchKey(*__pNumberStr);
517 ///////////////////////////////////////////////
518 // SuggestionListComparer Implementation //////
519 ///////////////////////////////////////////////
521 SuggestionListComparer::Compare(const Object& objRef1, const Object& objRef2, int& cmpResult) const
523 result r = E_INVALID_ARG;
525 //Check if both object are of type 'DialContactInfo'
526 DialContactInfo* pDialInfo1 = dynamic_cast<DialContactInfo*>(const_cast<Object*>(&objRef1));
527 DialContactInfo* pDialInfo2 = dynamic_cast<DialContactInfo*>(const_cast<Object*>(&objRef2));
528 if((pDialInfo1 == null) || (pDialInfo2 == null))
534 //Rules for comparison:-
535 //Priority 1 - show contacts for Speed dial.
536 //Priority 2 - show contacts searched by Name from Contacts.
537 //Priority 3 - show contacts searched by Number from Contacts.
538 //Priority 4 - show contacts searched by Number from Logs.
540 //Fetch initial search keys for both objects
541 String displayName1 = pDialInfo1->GetDisplayName();
542 String* searchKey1 = pDialInfo1->GetSearchKey();
543 bool isNumericKey1 = DialUtil::IsNumericString(*searchKey1);
545 String displayName2 = pDialInfo2->GetDisplayName();
546 String* searchKey2 = pDialInfo2->GetSearchKey();
547 bool isNumericKey2 = DialUtil::IsNumericString(*searchKey2);
550 if(searchKey1->Equals(String(IDS_SPEED_DIAL_SEARCH_KEY)))
552 cmpResult = 1;//objRef1 is searched via Speed Dial
555 else if (searchKey2->Equals(String(IDS_SPEED_DIAL_SEARCH_KEY)))
557 cmpResult = -1;//objRef2 via Speed Dial
562 if((displayName1.IsEmpty() == false) && (displayName2.IsEmpty() == true))
564 cmpResult = -1;//objRef1 NOT via Logs, objRef2 via Logs
567 else if((displayName1.IsEmpty() == true) && (displayName2.IsEmpty() == false))
569 cmpResult = 1;//objRef2 NOT via Logs, objRef1 via Logs
572 else if((displayName1.IsEmpty() == true) && (displayName2.IsEmpty() == true))
574 //Both via Logs - keep the same ordering as shown in logs.
575 cmpResult = (pDialInfo2->GetCallLogDbId() - pDialInfo1->GetCallLogDbId());
579 //If control comes here, it means both Objects are fetched from Contacts.
580 //Here, priority is first Names than Numbers
581 if((isNumericKey1 == false) && (isNumericKey2 == true))
583 cmpResult = -1;//objRef1 via name and objRef2 via number
586 else if((isNumericKey2 == false) && (isNumericKey1 == true))
588 cmpResult = 1;//objRef2 via name and objRef1 via number
591 else if((isNumericKey1 == false) && (isNumericKey2 == false))
593 //Both searched via name - sort by alphabetic ordering of search key.
594 cmpResult = searchKey1->CompareTo(*searchKey2);
599 //Both searched via number - keep current ordering as fetched from contacts.
600 cmpResult = pDialInfo1->GetPhoneNumber().CompareTo(pDialInfo2->GetPhoneNumber());