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)
146 && ((DialUtil::IsNumericString(*keyWord) == true)
147 || keyWord->Contains("+") == true || keyWord->Contains("#") == true
148 || keyWord->Contains(",") == true || keyWord->Contains(";") == true))
150 //search for number - update list
151 if (pContact->GetPhoneNumber().Contains(*__pNumberStr) == false)
157 //update search keys.
158 pContact->ReplaceSearchKey(nextKey, *__pNumberStr);
164 //substring of contact name to match
166 //numeric keys typed, equivalent to above 'subName'.
168 String contactName = pContact->GetDisplayName();
169 contactName.SubString(0,__pNumberStr->GetLength(),subName);
170 DialUtil::ConvertNameToNumericKeys(subName,numericKey);
171 if(numericKey.Equals(*__pNumberStr) == true)
173 //update search keys.
174 pContact->ReplaceSearchKey(nextKey, subName);
182 //remove previous search key, as updated key did'nt match.
183 if(isRemoveKey == true)
185 pContact->RemoveSearchKey(nextKey);
193 //Add to contacts list to be removed
194 if(pKeyList->GetCount() <= 0)
196 __pContactsList->RemoveAt(index);
201 //Need to sort arraylist according to latest search keys.
202 if(__pContactsList->GetCount() > 0)
204 SuggestionListComparer* pComparer = new (std::nothrow) SuggestionListComparer();
205 __pContactsList->Sort(*pComparer);
210 //remove old search key
217 RetrieveContactsListTask::SearchContactsForNumber(void)
219 //Searches contacts by (part of)phone number.
220 IList* pResultList = __pAddressBook->SearchContactsByPhoneNumberN(*__pNumberStr);
221 if(pResultList != null && pResultList->GetCount() > 0)
223 SaveContactsToListByNumber(*pResultList, *__pNumberStr);
224 pResultList->RemoveAll(true);
230 RetrieveContactsListTask::SearchContactsForName(void)
232 // If phoneNumber: "23" -> Possible string matches -> 9.
233 // It is much better to do first 3(2=A,B,C) search in 1000 fields(in database), and
234 // subsequent 9 searches in locally stored array of fewer records.
235 // then to 9 search searches in 1000 fields(in database).
237 //Fetch matching names for mapping char for first digit, e.g. 2->ABC, 3->DEF.
240 __pNumberStr->SubString(0,1,strDigit);
241 Integer::Parse(strDigit,digit);
242 IList* pNamesList = DialUtil::FetchPossibleNamesListN(L"",digit);
243 if (pNamesList != null)
245 int totalMatches = pNamesList->GetCount();
246 for (int index = 0; index < totalMatches; index++)
248 //Search All names that start with single character
249 String* searchKey = static_cast<String*>(pNamesList->GetAt(index));
250 SearchContactsWithInitialChar(*searchKey);
252 pNamesList->RemoveAll();
258 RetrieveContactsListTask::SearchContactsWithInitialChar(String& searchStr)
260 //search for contacts which contains 'searchStr' anywhere in displayName.
261 IList* pResultList = __pAddressBook->SearchContactsByNameN(searchStr);
262 //Check if empty list.
263 if(pResultList == null || pResultList->GetCount() <= 0)
269 //further filter out result list - save contacts starting with 'searchStr'.
270 ArrayList* pDialInfoList = new (std::nothrow) ArrayList();
271 pDialInfoList->Construct();
273 for(int index = 0; index < pResultList->GetCount(); index++)
275 Contact* pContact = static_cast<Contact*>(pResultList->GetAt(index));
276 //Check if display name starts with search string
278 result r = pContact->GetValue(CONTACT_PROPERTY_ID_DISPLAY_NAME, contactName);
279 if ((r == E_SUCCESS) && (contactName.StartsWith(searchStr, 0) == true))
281 //substring of contact name to match
283 //numeric keys typed, equivalent to above 'subName'.
285 contactName.SubString(0,__pNumberStr->GetLength(),subName);
286 DialUtil::ConvertNameToNumericKeys(subName,numericKey);
287 if(numericKey.Equals(*__pNumberStr) == true)
289 DialContactInfo* pDialInfo = ConvertToDialContactN(*pContact,subName);
290 if(pDialInfo != null)
292 pDialInfoList->Add(*pDialInfo);
297 pResultList->RemoveAll(true);
301 if(pDialInfoList->GetCount() > 0 && __pContactsList != null)
303 //remove duplicate items
304 pDialInfoList->RemoveItems(*__pContactsList,true);
305 //Add all distinct item to list
306 __pContactsList->AddItems(*pDialInfoList);
307 //remove ownership for all items.
308 pDialInfoList->RemoveAll();
310 delete pDialInfoList;
314 RetrieveContactsListTask::SearchSpeedDialForNumberN(void)
316 //Check if only 1 digit number
317 if(__pNumberStr->GetLength() != 1)
321 //convert to speed dial rowId
323 Integer::Parse(*__pNumberStr, rowId);
324 if (rowId < 2 || rowId > 9)
329 //Fetch matched speed dial contact number
330 SettingsManager* pSettingsManager = SettingsManager::GetInstance();
331 String* contactNo = pSettingsManager->GetMappedSpeedDialNumberN(rowId);
332 if (contactNo == null)
337 //Fetch Contact for phoneNumber
338 IList* pContactList = __pAddressBook->SearchContactsByPhoneNumberN(*contactNo);
339 if (pContactList != null)
341 IEnumerator* pContactsEnum = pContactList->GetEnumeratorN();
342 while (pContactsEnum->MoveNext() == E_SUCCESS)
344 Contact* pContact = static_cast<Contact*>(pContactsEnum->GetCurrent());
347 //save to HashMap - ownership transferred of key-value pair.
348 DialContactInfo* pDialContact = ConvertToDialContactN(*pContact,*contactNo);
349 if(pDialContact != null)
351 IList* keyList = pDialContact->GetSearchKeyList();
352 keyList->SetAt(*(new String(IDS_SPEED_DIAL_SEARCH_KEY)),(keyList->GetCount()-1), true);
353 __pContactsList->Add(pDialContact);
359 delete pContactsEnum;
360 pContactList->RemoveAll(true);
367 RetrieveContactsListTask::SearchCallLogsForNumber(void)
369 //conversion "contactNumber" to char*
370 const wchar_t* pContact = __pNumberStr->GetPointer();
371 int len = __pNumberStr->GetLength()+1;
372 char* pNumber = new (std::nothrow) char[len];
373 wcstombs(pNumber, pContact, len);
375 //fetch Unknown numbers from Call logs Manager containing search string.
376 HashMapT<int, CallLogDetails>* pLogsByNumber = CallLogManager::GetInstance()->GetCallogListByUnknownNumberFromDatabaseN(pNumber);
377 if(pLogsByNumber != null)
379 IListT<CallLogDetails>* logDetailsList = pLogsByNumber->GetValuesN();
380 if(logDetailsList != null)
382 //Convert to DialContacts
383 for(int index=0;index<logDetailsList->GetCount();index++)
385 CallLogDetails logDetails;
386 result r = logDetailsList->GetAt(index,logDetails);
389 DialContactInfo* pDialContact = ConvertLogDetailsToDialContactN(logDetails);
390 if(pDialContact != null)
392 if((__pContactsList->GetCount() <= 0) || (__pContactsList->Contains(*pDialContact) == false))
394 //Add only 'unknown' number to Map
395 __pContactsList->Add(pDialContact);
405 delete logDetailsList;
407 delete pLogsByNumber;
412 RetrieveContactsListTask::SaveContactsToListByNumber(IList& saveList, String& matchedString)
414 if(__pContactsList != null)
416 //List of contacts to be saved
417 for (int index = 0; index < saveList.GetCount(); index++)
419 Contact* pContact = static_cast<Contact*>(saveList.GetAt(index));
420 DialContactInfo* pDialContact = ConvertToDialContactN(*pContact, matchedString);
421 if (pDialContact != null)
423 //check if already present
425 if (__pContactsList->IndexOf(*pDialContact, foundItemIndex) != E_SUCCESS)
428 __pContactsList->Add(pDialContact);
432 //Add search key to existing list
433 DialContactInfo* pExistingInfo = static_cast<DialContactInfo*>(__pContactsList->GetAt( foundItemIndex));
434 if (pExistingInfo != null)
436 pExistingInfo->AddSearchKey(*(pDialContact->GetSearchKey()));
446 RetrieveContactsListTask::ConvertToDialContactN(Contact& contact, String& matchedString)
448 result r = E_FAILURE;
452 r = contact.GetValue(CONTACT_PROPERTY_ID_DISPLAY_NAME, displayName);
453 TryReturn(r == E_SUCCESS,null,"Display name not available");
456 String phoneNumber(L"");
457 IList* pNumberList = contact.GetValuesN(CONTACT_MPROPERTY_ID_PHONE_NUMBERS);
458 if(pNumberList == null || pNumberList->GetCount() <= 0)
464 if(DialUtil::IsNumericString(matchedString) == true)
466 //this contact searched by phone number
467 IEnumerator* pPhoneEnum = pNumberList->GetEnumeratorN();
468 while (E_SUCCESS == pPhoneEnum->MoveNext())
470 PhoneNumber* pPhoneNumber = (PhoneNumber*) pPhoneEnum->GetCurrent();
471 //Check if this is the correct contact
472 if (pPhoneNumber->GetPhoneNumber().Contains(matchedString) == true)
474 phoneNumber.Append(pPhoneNumber->GetPhoneNumber());
482 //this contact searched by name
483 PhoneNumber* pContactNo = static_cast<PhoneNumber*>(pNumberList->GetAt(0));
484 phoneNumber.Append(pContactNo->GetPhoneNumber());
486 pNumberList->RemoveAll(true);
489 TryReturn((phoneNumber.IsEmpty() == false), null, "No matching phone number found");
491 DialContactInfo* pDialContact = new (std::nothrow) DialContactInfo();
492 pDialContact->AddSearchKey(matchedString);
493 pDialContact->SetPhoneNumber(phoneNumber);
494 pDialContact->SetDisplayName(displayName);
496 //Check if Thumbnail is present
497 Bitmap* pThumbnail = contact.GetThumbnailN();
498 if(pThumbnail != null)
500 pDialContact->SetThumbnail(pThumbnail);
506 RetrieveContactsListTask::ConvertLogDetailsToDialContactN(CallLogDetails& logDetails)
508 DialContactInfo* pDialContact = new (std::nothrow) DialContactInfo();
509 String emptyDisplayName(L"");
510 pDialContact->SetDisplayName(emptyDisplayName);
512 pDialContact->SetCallLogDbId(logDetails.GetCalllogDbId());
514 String phoneNumber(logDetails.GetPhoneNumber());
515 pDialContact->SetPhoneNumber(phoneNumber);
516 pDialContact->AddSearchKey(*__pNumberStr);
520 ///////////////////////////////////////////////
521 // SuggestionListComparer Implementation //////
522 ///////////////////////////////////////////////
524 SuggestionListComparer::Compare(const Object& objRef1, const Object& objRef2, int& cmpResult) const
526 result r = E_INVALID_ARG;
528 //Check if both object are of type 'DialContactInfo'
529 DialContactInfo* pDialInfo1 = dynamic_cast<DialContactInfo*>(const_cast<Object*>(&objRef1));
530 DialContactInfo* pDialInfo2 = dynamic_cast<DialContactInfo*>(const_cast<Object*>(&objRef2));
531 if((pDialInfo1 == null) || (pDialInfo2 == null))
537 //Rules for comparison:-
538 //Priority 1 - show contacts for Speed dial.
539 //Priority 2 - show contacts searched by Name from Contacts.
540 //Priority 3 - show contacts searched by Number from Contacts.
541 //Priority 4 - show contacts searched by Number from Logs.
543 //Fetch initial search keys for both objects
544 String displayName1 = pDialInfo1->GetDisplayName();
545 String* searchKey1 = pDialInfo1->GetSearchKey();
546 bool isNumericKey1 = DialUtil::IsNumericString(*searchKey1);
548 String displayName2 = pDialInfo2->GetDisplayName();
549 String* searchKey2 = pDialInfo2->GetSearchKey();
550 bool isNumericKey2 = DialUtil::IsNumericString(*searchKey2);
553 if(searchKey1->Equals(String(IDS_SPEED_DIAL_SEARCH_KEY)))
555 cmpResult = 1;//objRef1 is searched via Speed Dial
558 else if (searchKey2->Equals(String(IDS_SPEED_DIAL_SEARCH_KEY)))
560 cmpResult = -1;//objRef2 via Speed Dial
565 if((displayName1.IsEmpty() == false) && (displayName2.IsEmpty() == true))
567 cmpResult = -1;//objRef1 NOT via Logs, objRef2 via Logs
570 else if((displayName1.IsEmpty() == true) && (displayName2.IsEmpty() == false))
572 cmpResult = 1;//objRef2 NOT via Logs, objRef1 via Logs
575 else if((displayName1.IsEmpty() == true) && (displayName2.IsEmpty() == true))
577 //Both via Logs - keep the same ordering as shown in logs.
578 cmpResult = (pDialInfo2->GetCallLogDbId() - pDialInfo1->GetCallLogDbId());
582 //If control comes here, it means both Objects are fetched from Contacts.
583 //Here, priority is first Names than Numbers
584 if((isNumericKey1 == false) && (isNumericKey2 == true))
586 cmpResult = -1;//objRef1 via name and objRef2 via number
589 else if((isNumericKey2 == false) && (isNumericKey1 == true))
591 cmpResult = 1;//objRef2 via name and objRef1 via number
594 else if((isNumericKey1 == false) && (isNumericKey2 == false))
596 //Both searched via name - sort by alphabetic ordering of search key.
597 cmpResult = searchKey1->CompareTo(*searchKey2);
602 //Both searched via number - keep current ordering as fetched from contacts.
603 cmpResult = pDialInfo1->GetPhoneNumber().CompareTo(pDialInfo2->GetPhoneNumber());