summaryrefslogtreecommitdiff
path: root/lib-phone/ph-dialer/src
diff options
context:
space:
mode:
Diffstat (limited to 'lib-phone/ph-dialer/src')
-rw-r--r--lib-phone/ph-dialer/src/PhDialerAddToContactsPopup.cpp98
-rw-r--r--lib-phone/ph-dialer/src/PhDialerEntry.cpp89
-rw-r--r--lib-phone/ph-dialer/src/PhDialerKey.cpp108
-rw-r--r--lib-phone/ph-dialer/src/PhDialerResultListPopup.cpp126
-rw-r--r--lib-phone/ph-dialer/src/PhDialerSearchController.cpp210
-rw-r--r--lib-phone/ph-dialer/src/PhDialerSpeeddialPopup.cpp81
-rw-r--r--lib-phone/ph-dialer/src/PhDialerView.cpp392
-rw-r--r--lib-phone/ph-dialer/src/predictive-number/PhDialerPredictiveNumber.cpp223
-rw-r--r--lib-phone/ph-dialer/src/predictive-number/PhDialerPredictiveNumberUtils.cpp219
-rw-r--r--lib-phone/ph-dialer/src/predictive-number/PhDialerSearchInfo.cpp157
10 files changed, 1703 insertions, 0 deletions
diff --git a/lib-phone/ph-dialer/src/PhDialerAddToContactsPopup.cpp b/lib-phone/ph-dialer/src/PhDialerAddToContactsPopup.cpp
new file mode 100644
index 0000000..4ed3e85
--- /dev/null
+++ b/lib-phone/ph-dialer/src/PhDialerAddToContactsPopup.cpp
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2009-2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "ContactsAppControl.h"
+#include "PhDialerAddToContactsPopup.h"
+#include "PhStrings.h"
+#include "WDebugBase.h"
+
+#define STYLE_ITEM "type1"
+#define PART_MAIN_TEXT "elm.text"
+
+PhDialerAddToContactsPopup::PhDialerAddToContactsPopup(std::string number)
+ : m_Number(std::move(number))
+{}
+
+Evas_Object* PhDialerAddToContactsPopup::onCreate(Evas_Object *parent, void *param)
+{
+ setTitle(PAT_(PH_KPD_BUTTON_ADD_TO_CONTACTS_ABB2));
+ setContent(std::bind(&PhDialerAddToContactsPopup::createGenlist, this, std::placeholders::_1));
+
+ Evas_Object *popup = WPopup::onCreate(parent, param);
+ elm_popup_orient_set(popup, ELM_POPUP_ORIENT_CENTER);
+
+ return popup;
+}
+
+Evas_Object *PhDialerAddToContactsPopup::createGenlist(Evas_Object *parent)
+{
+ Evas_Object *genlist = elm_genlist_add(parent);
+ elm_genlist_homogeneous_set(genlist, EINA_TRUE);
+ elm_genlist_mode_set( genlist, ELM_LIST_COMPRESS );
+ elm_scroller_content_min_limit( genlist, EINA_FALSE, EINA_TRUE );
+
+ Elm_Genlist_Item_Class *itc = createItemClass();
+
+ elm_genlist_item_append(genlist, itc, PAT_(PH_LOGS_BUTTON_CREATE_CONTACT_ABB),
+ NULL, ELM_GENLIST_ITEM_NONE, launchContactCreate, this);
+ elm_genlist_item_append(genlist, itc, PAT_(PH_LOGS_BUTTON_UPDATE_CONTACT_ABB2),
+ NULL, ELM_GENLIST_ITEM_NONE, launchContactUpdate, this);
+
+ elm_genlist_item_class_free(itc);
+ return genlist;
+}
+
+Elm_Genlist_Item_Class *PhDialerAddToContactsPopup::createItemClass()
+{
+ Elm_Genlist_Item_Class *itc = elm_genlist_item_class_new();
+ WPRET_VM(!itc, NULL, "elm_genlist_item_class_new() failed");
+ itc->item_style = STYLE_ITEM;
+ itc->func.text_get = getItemText;
+ return itc;
+}
+
+char *PhDialerAddToContactsPopup::getItemText(void *data, Evas_Object *obj, const char *part)
+{
+ WPRET_VM(!data, NULL, "data = NULL");
+ const char *text = (const char *)data;
+
+ if(!strcmp(part, PART_MAIN_TEXT)) {
+ return strdup(text);
+ }
+
+ return NULL;
+}
+
+void PhDialerAddToContactsPopup::launchContactCreate(void *data,
+ Evas_Object *obj, void *event_info)
+{
+ WPRET_M(!data, "data = NULL");
+ PhDialerAddToContactsPopup *popup = (PhDialerAddToContactsPopup*)data;
+
+ ::launchContactCreate(popup->m_Number.c_str());
+ popup->destroy();
+}
+
+void PhDialerAddToContactsPopup::launchContactUpdate(void *data,
+ Evas_Object *obj, void *event_info)
+{
+ WPRET_M(!data, "data = NULL");
+ PhDialerAddToContactsPopup *popup = (PhDialerAddToContactsPopup*)data;
+
+ ::launchContactEdit(0, popup->m_Number.c_str());
+ popup->destroy();
+}
diff --git a/lib-phone/ph-dialer/src/PhDialerEntry.cpp b/lib-phone/ph-dialer/src/PhDialerEntry.cpp
new file mode 100644
index 0000000..960bb27
--- /dev/null
+++ b/lib-phone/ph-dialer/src/PhDialerEntry.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2009-2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "PhDialerEntry.h"
+#include <Elementary.h>
+#include <efl_extension.h>
+
+std::string PhDialerEntry::getNumber()
+{
+ std::string number;
+
+ char *str = elm_entry_markup_to_utf8(elm_entry_entry_get(getEvasObj()));
+ if (str) {
+ number = str;
+ free(str);
+ }
+
+ return number;
+}
+
+void PhDialerEntry::setNumber(const std::string &number)
+{
+ elm_entry_entry_set(getEvasObj(), number.c_str());
+ elm_entry_cursor_line_end_set(getEvasObj());
+}
+
+void PhDialerEntry::insert(char c)
+{
+ char str[] = { c, '\0' };
+ elm_entry_entry_insert(getEvasObj(), str);
+}
+
+void PhDialerEntry::popBack()
+{
+ int pos = elm_entry_cursor_pos_get(getEvasObj());
+ if (pos > 0) {
+ elm_entry_select_region_set(getEvasObj(), pos - 1, pos);
+ elm_entry_entry_insert(getEvasObj(), "");
+ }
+}
+
+void PhDialerEntry::clear()
+{
+ elm_entry_entry_set(getEvasObj(), "");
+}
+
+void PhDialerEntry::setOnChanged(std::function<void(PhDialerEntry&)> callback)
+{
+ m_Changed = std::move(callback);
+}
+
+Evas_Object *PhDialerEntry::onCreate(Evas_Object *parent, void *param)
+{
+ Evas_Object *entry = elm_entry_add(parent);
+ elm_entry_single_line_set(entry, EINA_TRUE);
+ elm_entry_scrollable_set(entry, EINA_TRUE);
+ elm_entry_input_panel_enabled_set(entry, EINA_FALSE);
+
+ static Elm_Entry_Filter_Accept_Set filter = { "+*#;,1234567890", NULL };
+ elm_entry_markup_filter_append(entry, elm_entry_filter_accept_set, &filter);
+ elm_entry_text_style_user_push(entry, "DEFAULT='font=Tizen:style=Light font_size=60 color=#fff align=center'");
+
+ eext_entry_selection_back_event_allow_set(entry, EINA_TRUE);
+ evas_object_smart_callback_add(entry, "changed",
+ &PhDialerEntry::onChanged, this);
+ return entry;
+}
+
+void PhDialerEntry::onChanged(void *data, Evas_Object *obj, void *event_info)
+{
+ PhDialerEntry *entry = (PhDialerEntry*) data;
+ if (entry->m_Changed) {
+ entry->m_Changed(*entry);
+ }
+}
diff --git a/lib-phone/ph-dialer/src/PhDialerKey.cpp b/lib-phone/ph-dialer/src/PhDialerKey.cpp
new file mode 100644
index 0000000..bf42fb9
--- /dev/null
+++ b/lib-phone/ph-dialer/src/PhDialerKey.cpp
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2009-2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "PhDialerKey.h"
+#include "ContactsCommon.h"
+#include "ContactsDebug.h"
+#include "PhDialerLayout.h"
+
+#include <Elementary.h>
+#include <feedback.h>
+
+#define DIALER_LAYOUT_EDJ "phone/ph-dialer-keypad.edj"
+
+namespace
+{
+ char values[] = {
+ '1',
+ '2',
+ '3',
+ '4',
+ '5',
+ '6',
+ '7',
+ '8',
+ '9',
+ '*',
+ '0',
+ '#',
+ };
+
+ const char *groups[] = {
+ KEYPAD_NUMBER_1,
+ KEYPAD_NUMBER_2,
+ KEYPAD_NUMBER_3,
+ KEYPAD_NUMBER_4,
+ KEYPAD_NUMBER_5,
+ KEYPAD_NUMBER_6,
+ KEYPAD_NUMBER_7,
+ KEYPAD_NUMBER_8,
+ KEYPAD_NUMBER_9,
+ KEYPAD_NUMBER_ASTERISK,
+ KEYPAD_NUMBER_0,
+ KEYPAD_NUMBER_SHARP
+ };
+
+ const feedback_pattern_e patterns[] = {
+ FEEDBACK_PATTERN_KEY1,
+ FEEDBACK_PATTERN_KEY2,
+ FEEDBACK_PATTERN_KEY3,
+ FEEDBACK_PATTERN_KEY4,
+ FEEDBACK_PATTERN_KEY5,
+ FEEDBACK_PATTERN_KEY6,
+ FEEDBACK_PATTERN_KEY7,
+ FEEDBACK_PATTERN_KEY8,
+ FEEDBACK_PATTERN_KEY9,
+ FEEDBACK_PATTERN_KEY_STAR,
+ FEEDBACK_PATTERN_KEY0,
+ FEEDBACK_PATTERN_KEY_SHARP
+ };
+}
+
+PhDialerKey::PhDialerKey(Id id)
+ : m_Id(id), m_Value(values[id]), m_Tone(0)
+{
+}
+
+Evas_Object *PhDialerKey::onCreate(Evas_Object *parent, void *param)
+{
+ static const std::string path = ContactsCommon::getAppEdjePath(DIALER_LAYOUT_EDJ);
+ Evas_Object *layout = elm_layout_add(parent);
+ Eina_Bool res = elm_layout_file_set(layout, path.c_str(), groups[m_Id]);
+ WPWARN(res != EINA_TRUE, "elm_layout_file_set() failed");
+
+ evas_object_event_callback_add(layout, EVAS_CALLBACK_MOUSE_DOWN,
+ &PhDialerKey::onMouseDown, this);
+
+ return layout;
+}
+
+char PhDialerKey::getValue() const
+{
+ return m_Value;
+}
+
+PhDialerKey::Id PhDialerKey::getId() const
+{
+ return m_Id;
+}
+
+void PhDialerKey::onMouseDown(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+ PhDialerKey *key = (PhDialerKey*) data;
+ feedback_play(patterns[key->m_Id]);
+}
diff --git a/lib-phone/ph-dialer/src/PhDialerResultListPopup.cpp b/lib-phone/ph-dialer/src/PhDialerResultListPopup.cpp
new file mode 100644
index 0000000..f923c18
--- /dev/null
+++ b/lib-phone/ph-dialer/src/PhDialerResultListPopup.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2009-2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "PhDialerResultListPopup.h"
+#include "PhDialerLayout.h"
+#include "PhDialerPredictiveNumberUtils.h"
+#include "PhStrings.h"
+#include "PhDialerEntry.h"
+#include "ContactsCommon.h"
+#include "ContactsDebug.h"
+
+#include <Elementary.h>
+
+#define PREDICTIVE_LAYOUT_EDJ "phone/ph-dialer-predictive.edj"
+
+#define STYLE_ITEM "type1"
+#define PART_MAIN_TEXT "elm.text"
+#define PART_SUB_TEXT "elm.text.sub"
+#define PART_CONTENT "elm.swallow.icon"
+
+using namespace Ph::Dialer;
+
+namespace
+{
+ const std::string layoutFilePath = ContactsCommon::getAppEdjePath(PREDICTIVE_LAYOUT_EDJ);
+}
+
+PhDialerResultListPopup::PhDialerResultListPopup(const Ph::Dialer::SearchList &result, PhDialerEntry &entry)
+ : m_Result(result), m_Entry(entry)
+{}
+
+Evas_Object* PhDialerResultListPopup::onCreate(Evas_Object *parent, void *param)
+{
+ const size_t bufferSize = 32;
+ char buffer[bufferSize];
+ snprintf(buffer, bufferSize, PAT_(PH_KPD_HEADER_SEARCH_RESULTS_HPD_ABB), m_Result.size());
+
+ setTitle(buffer);
+ setContent(std::bind(&PhDialerResultListPopup::createContactList, this, std::placeholders::_1));
+
+ Evas_Object *popup = WPopup::onCreate(parent, param);
+ elm_popup_align_set(popup, ELM_NOTIFY_ALIGN_FILL, 1.0);
+ elm_object_style_set(popup, "theme_bg");
+ elm_popup_orient_set(popup, ELM_POPUP_ORIENT_CENTER);
+
+ return popup;
+}
+
+Evas_Object* PhDialerResultListPopup::createContactList(Evas_Object *parent)
+{
+ Evas_Object *genlist = elm_genlist_add(parent);
+ elm_genlist_homogeneous_set(genlist, EINA_TRUE);
+ elm_genlist_mode_set( genlist, ELM_LIST_COMPRESS );
+
+ Elm_Genlist_Item_Class *itc = createItemClass();
+
+ for(auto &info : m_Result) {
+ elm_genlist_item_append(genlist, itc, info.get(), nullptr,
+ ELM_GENLIST_ITEM_NONE, onItemClicked, this);
+ }
+
+ elm_genlist_item_class_free(itc);
+ return genlist;
+}
+
+Elm_Genlist_Item_Class* PhDialerResultListPopup::createItemClass()
+{
+ Elm_Genlist_Item_Class *itc = elm_genlist_item_class_new();
+ WPRET_VM(!itc, NULL, "elm_genlist_item_class_new() failed");
+ itc->item_style = STYLE_ITEM;
+ itc->func.text_get = getItemText;
+ itc->func.content_get = [](void *data, Evas_Object *obj, const char *part) -> Evas_Object* {
+ const SearchInfo &info = *(SearchInfo*)data;
+
+ if(!strcmp(part, PART_CONTENT)) {
+ return Utils::createThumbnail(obj, info.getId());
+ }
+
+ return nullptr;
+ };
+
+ return itc;
+}
+
+char *PhDialerResultListPopup::getItemText(void *data, Evas_Object *obj, const char *part)
+{
+ const SearchInfo &info = *(SearchInfo*)data;
+ const std::string &name = info.getName(true);
+ const std::string &number = info.getNumber(true);
+
+ if(!strcmp(part, PART_MAIN_TEXT)) {
+ return strdup(name.empty() ? number.c_str() : name.c_str());
+ } else if(!strcmp(part, PART_SUB_TEXT)) {
+ if (!name.empty()) {
+ return strdup(number.c_str());
+ }
+ }
+
+ return nullptr;
+}
+
+void PhDialerResultListPopup::onItemClicked(void* data, Evas_Object* obj, void* event_info)
+{
+ elm_genlist_item_selected_set((Elm_Object_Item*)event_info, false);
+
+ const SearchInfo *info = (SearchInfo*)elm_object_item_data_get((Elm_Object_Item*)event_info);
+
+ PhDialerResultListPopup *self = (PhDialerResultListPopup*)data;
+ self->m_Entry.setNumber(info->getNumber(false));
+
+ self->destroy();
+}
diff --git a/lib-phone/ph-dialer/src/PhDialerSearchController.cpp b/lib-phone/ph-dialer/src/PhDialerSearchController.cpp
new file mode 100644
index 0000000..6ae90fd
--- /dev/null
+++ b/lib-phone/ph-dialer/src/PhDialerSearchController.cpp
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2009-2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "PhDialerSearchController.h"
+#include "PhDialerAddToContactsPopup.h"
+#include "PhDialerResultListPopup.h"
+#include "PhDialerView.h"
+#include "PhDialerPredictiveNumber.h"
+#include "PhDialerPredictiveNumberUtils.h"
+#include "PhDialerLayout.h"
+#include "PhDialerEntry.h"
+#include "PhPath.h"
+#include "PhStrings.h"
+#include "ContactsDebug.h"
+
+#define PREDICTIVE_LAYOUT_EDJ "phone/ph-dialer-predictive.edj"
+
+using namespace Ph::Dialer;
+
+namespace
+{
+ const std::string layoutFilePath = ContactsCommon::getAppEdjePath(PREDICTIVE_LAYOUT_EDJ);
+}
+
+PhDialerSearchController::PhDialerSearchController()
+ : m_View(nullptr),
+ m_PredictiveNumber(new PredictiveNumber()),
+ m_CurrentLayoutType(LayoutType::NONE),
+ m_Layout(nullptr),
+ m_ResultLayout(nullptr)
+{
+ int err = CONTACTS_ERROR_NONE;
+ err = contacts_db_add_changed_cb(_contacts_contact._uri, &PhDialerSearchController::onDbChanged, this);
+ WPWARN(CONTACTS_ERROR_NONE != err,"contacts_db_add_changed_cb() Failed(%d)", err);
+}
+
+PhDialerSearchController::~PhDialerSearchController()
+{
+ int err = CONTACTS_ERROR_NONE;
+ err = contacts_db_remove_changed_cb(_contacts_contact._uri, &PhDialerSearchController::onDbChanged, this);
+ WPWARN(CONTACTS_ERROR_NONE != err,"contacts_db_add_changed_cb() Failed(%d)", err);
+}
+
+void PhDialerSearchController::create(PhDialerView &view)
+{
+ m_View = &view;
+ PhDialerEntry *entry = m_View->getEntry();
+
+ entry->setOnChanged(std::bind(&PhDialerSearchController::onEntryChanged, this, std::placeholders::_1));
+}
+
+void PhDialerSearchController::setLayout(const std::string &number)
+{
+ if(number.empty()) {
+ m_Layout = nullptr;
+ m_CurrentLayoutType = LayoutType::NONE;
+ m_View->setPredictiveLayout(nullptr);
+ } else {
+ if(m_PredictiveNumber->empty()) {
+ setNoContactsLayout();
+ } else {
+ const SearchList &result = *m_PredictiveNumber->getSearchResult();
+ setLayoutWithContacts(*result.front());
+ setResultLayout(m_Layout, result.size());
+ }
+ }
+}
+
+void PhDialerSearchController::onEntryChanged(PhDialerEntry &entry)
+{
+ std::string number(entry.getNumber());
+ m_PredictiveNumber->search(number);
+
+ setLayout(number);
+}
+
+void PhDialerSearchController::setNoContactsLayout()
+{
+ if(m_CurrentLayoutType == LayoutType::NO_CONTACTS) {
+ return;
+ }
+ m_CurrentLayoutType = LayoutType::NO_CONTACTS;
+
+ m_Layout = elm_layout_add(m_View->getEvasObj());
+ elm_layout_file_set(m_Layout, layoutFilePath.c_str(), GROUP_PREDICTIVE_NO_RESULTS);
+ elm_object_part_text_set(m_Layout, PART_TEXT_ADD, PH_KPD_BUTTON_ADD_TO_CONTACTS_ABB2);
+ elm_object_domain_part_text_translatable_set(m_Layout, PART_TEXT_ADD, STRING_PACKAGE, true);
+
+ evas_object_event_callback_add(m_Layout, EVAS_CALLBACK_MOUSE_UP, &createAddToContactsPopup, this);
+
+ m_View->setPredictiveLayout(m_Layout);
+}
+
+void PhDialerSearchController::setLayoutWithContacts(const Ph::Dialer::SearchInfo &info)
+{
+ if(m_CurrentLayoutType != LayoutType::ONE_CONTACT
+ && m_CurrentLayoutType != LayoutType::FEW_CONTACTS) {
+
+ m_CurrentLayoutType = LayoutType::ONE_CONTACT;
+
+ m_Layout = elm_layout_add(m_View->getEvasObj());
+ elm_layout_file_set(m_Layout, layoutFilePath.c_str(), GROUP_PREDICTIVE);
+
+ evas_object_event_callback_add(m_Layout, EVAS_CALLBACK_MOUSE_UP,
+ [](void *data, Evas *e, Evas_Object *obj, void *event_info) {
+ PhDialerSearchController *self = (PhDialerSearchController*)data;
+ const SearchList *result = self->m_PredictiveNumber->getSearchResult();
+ if (result) {
+ SearchInfo &info = *result->front();
+ self->m_View->getEntry()->setNumber(info.getNumber(false));
+ }
+ },
+ this);
+
+ m_View->setPredictiveLayout(m_Layout);
+ }
+
+ if(info.getType() == IT_SPEED_DIAL) {
+ createSpeeddialLayout(m_Layout, info);
+ elm_object_signal_emit(m_Layout, "show,speeddial,icon", "");
+ } else {
+ elm_object_signal_emit(m_Layout, "hide,speeddial,icon", "");
+ }
+
+ fillPredictiveLayout(m_Layout, info);
+}
+
+void PhDialerSearchController::setResultLayout(Evas_Object *parent, size_t count)
+{
+ if(count > 1) {
+ if(m_CurrentLayoutType != LayoutType::FEW_CONTACTS) {
+ m_CurrentLayoutType = LayoutType::FEW_CONTACTS;
+
+ m_ResultLayout = elm_layout_add(parent);
+ elm_layout_file_set(m_ResultLayout, layoutFilePath.c_str(), GROUP_PREDICTIVE_RES_COUNT);
+
+ evas_object_event_callback_add(m_ResultLayout, EVAS_CALLBACK_MOUSE_UP, &showResulListPopup, this);
+ evas_object_propagate_events_set(m_ResultLayout, EINA_FALSE);
+ }
+
+ elm_object_part_text_set(m_ResultLayout, PART_TEXT_COUNT, std::to_string(count).c_str());
+ } else {
+ m_ResultLayout = nullptr;
+ m_CurrentLayoutType = LayoutType::ONE_CONTACT;
+ }
+ elm_object_part_content_set(parent, PART_SWALLOW_RESULTS, m_ResultLayout);
+}
+
+void PhDialerSearchController::createSpeeddialLayout(Evas_Object *parent, const Ph::Dialer::SearchInfo &info)
+{
+ Evas_Object *speeddialLayout = elm_layout_add(parent);
+ elm_layout_file_set(speeddialLayout, layoutFilePath.c_str(), GROUP_SPEEDDIAL_NUMBER);
+ elm_object_part_text_set(speeddialLayout, PART_TEXT_NUMBER, info.getSearchString().c_str());
+
+ elm_object_part_content_set(parent, PART_SWALLOW_SPEEDDIAL, speeddialLayout);
+}
+
+void PhDialerSearchController::fillPredictiveLayout(Evas_Object *layout, const Ph::Dialer::SearchInfo &info)
+{
+ elm_object_part_content_set(layout, PART_SWALLOW_THUMBNAIL,
+ Utils::createThumbnail(layout, info.getId()));
+
+ if(info.getName(false).empty()) {
+ elm_object_part_text_set(layout, PART_TEXT_1_LINE, info.getNumber(true).c_str());
+ elm_object_part_text_set(layout, PART_TEXT_NAME, "");
+ elm_object_part_text_set(layout, PART_TEXT_NUMBER, "");
+ } else {
+ elm_object_part_text_set(layout, PART_TEXT_1_LINE, "");
+ elm_object_part_text_set(layout, PART_TEXT_NAME, info.getName(true).c_str());
+ elm_object_part_text_set(layout, PART_TEXT_NUMBER, info.getNumber(true).c_str());
+ }
+}
+
+void PhDialerSearchController::showResulListPopup(void* data, Evas* e,
+ Evas_Object* obj, void* event_info)
+{
+ PhDialerSearchController *searchController = (PhDialerSearchController*)data;
+ searchController->m_View->attachPopup(
+ new PhDialerResultListPopup(*searchController->m_PredictiveNumber->getSearchResult(), *searchController->m_View->getEntry()));
+}
+
+void PhDialerSearchController::createAddToContactsPopup(void* data, Evas* e,
+ Evas_Object* obj, void* event_info)
+{
+ WPRET_M(!data, "data = NULL");
+ PhDialerSearchController *searchController = (PhDialerSearchController*)data;
+ searchController->m_View->attachPopup(new PhDialerAddToContactsPopup(searchController->m_View->getEntry()->getNumber()));
+}
+
+void PhDialerSearchController::onDbChanged(const char *view_uri, void *data)
+{
+ PhDialerSearchController* controller = (PhDialerSearchController*) data;
+ std::string number(controller->m_View->getEntry()->getNumber());
+ controller->m_PredictiveNumber->searchFromScratch(number);
+ controller->setLayout(number);
+}
diff --git a/lib-phone/ph-dialer/src/PhDialerSpeeddialPopup.cpp b/lib-phone/ph-dialer/src/PhDialerSpeeddialPopup.cpp
new file mode 100644
index 0000000..83fbd52
--- /dev/null
+++ b/lib-phone/ph-dialer/src/PhDialerSpeeddialPopup.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2009-2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "PhDialerSpeeddialPopup.h"
+#include "PhCommon.h"
+
+#include "ContactsDebug.h"
+#include "ContactsAppControl.h"
+#include "ContactsLocalization.h"
+
+#include <contacts.h>
+#include <Elementary.h>
+#include <notification.h>
+
+PhDialerSpeeddialPopup::PhDialerSpeeddialPopup(int speedNumber)
+ : m_SpeedNumber(speedNumber)
+{
+}
+
+Evas_Object *PhDialerSpeeddialPopup::onCreate(Evas_Object* parent, void* param)
+{
+ setTextTranslatable(TEXT_DOMAIN);
+ setTitle("IDS_KPD_HEADER_ASSIGN_AS_SPEED_DIAL_NUMBER_ABB");
+ setContent("IDS_KPD_POP_THERE_IS_NO_CONTACT_ASSIGNED_TO_THIS_SPEED_DIAL_NUMBER_TAP_OK_TO_ASSIGN_ONE_NOW");
+
+ using namespace std::placeholders;
+ addButton("IDS_LOGS_BUTTON_CANCEL_ABB3", nullptr);
+ addButton("IDS_PB_BUTTON_OK_ABB2", std::bind(&PhDialerSpeeddialPopup::onOkPressed, this, _1));
+ return WPopup::onCreate(parent, param);
+}
+
+void PhDialerSpeeddialPopup::onOkPressed(bool *destroyPopup)
+{
+ int err = launchContactPick(APP_CONTROL_DATA_SELECTION_MODE_SINGLE,
+ APP_CONTROL_DATA_TYPE_PHONE,
+ &PhDialerSpeeddialPopup::onPickResult, this);
+ WPRET_M(err != APP_CONTROL_ERROR_NONE, "launchContactPick() failed(0x%x)", err);
+ *destroyPopup = false;
+}
+
+void PhDialerSpeeddialPopup::onPickResult(app_control_h request, app_control_h reply,
+ app_control_result_e result, void *data)
+{
+ PhDialerSpeeddialPopup *popup = (PhDialerSpeeddialPopup*) data;
+
+ char **numberIds = 0;
+ int count = 0;
+ int err = app_control_get_extra_data_array(reply, APP_CONTROL_DATA_SELECTED, &numberIds, &count);
+ WPWARN(err != APP_CONTROL_ERROR_NONE, "app_control_get_extra_data() failed(0x%x)", err);
+ if (numberIds && numberIds[0]) {
+ int numberId = atoi(numberIds[0]);
+ if (numberId > 0) {
+ if (PhCommon::addSpeedDialNumber(popup->m_SpeedNumber, numberId)) {
+ notification_status_message_post(T_("IDS_KPD_TPOP_SPEED_DIAL_NUMBER_ASSIGNED"));
+ } else {
+ notification_status_message_post(T_("IDS_PB_POP_ALREADY_EXISTS_LC"));
+ }
+ }
+ }
+
+ for (int i = 0; i < count; ++i) {
+ free(numberIds[i]);
+ }
+ free(numberIds);
+
+ popup->destroy();
+}
diff --git a/lib-phone/ph-dialer/src/PhDialerView.cpp b/lib-phone/ph-dialer/src/PhDialerView.cpp
new file mode 100644
index 0000000..1a2df0f
--- /dev/null
+++ b/lib-phone/ph-dialer/src/PhDialerView.cpp
@@ -0,0 +1,392 @@
+/*
+ * Copyright (c) 2009-2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "PhDialerView.h"
+#include "PhDialerEntry.h"
+#include "PhDialerKey.h"
+#include "PhDialerLayout.h"
+#include "PhDialerSpeeddialPopup.h"
+#include "PhSpeedDialView.h"
+#include "PhDialerSearchController.h"
+
+#include "ContactsAppControl.h"
+#include "ContactsDebug.h"
+#include "PhStrings.h"
+#include "WMenuPopup.h"
+
+#include <app_control.h>
+#include <contacts.h>
+#include <feedback.h>
+
+#define KEYPAD_ROWS 4
+#define KEYPAD_COLS 3
+
+#define UG_CALL_SETTING "setting-call-efl"
+#define DIALER_LAYOUT_EDJ "phone/ph-dialer-layout.edj"
+
+namespace
+{
+ const std::string layoutFilePath = ContactsCommon::getAppEdjePath(DIALER_LAYOUT_EDJ);
+}
+
+PhDialerView::PhDialerView()
+ : m_Entry(nullptr), m_Controller(nullptr)
+{
+ feedback_initialize();
+}
+
+PhDialerView::~PhDialerView()
+{
+ feedback_deinitialize();
+}
+
+void PhDialerView::setPredictiveLayout(Evas_Object *layout)
+{
+ elm_object_part_content_set(getEvasObj(), PART_SWALLOW_PREDICTIVE, layout);
+}
+
+PhDialerEntry* PhDialerView::getEntry() const
+{
+ return m_Entry;
+}
+
+Evas_Object *PhDialerView::onCreate(Evas_Object *parent, void *viewParam)
+{
+ elm_theme_extension_add(nullptr, ContactsCommon::getAppEdjePath("common/custom_button_styles.edj").c_str());
+
+ Evas_Object *layout = elm_layout_add(parent);
+ Eina_Bool res = elm_layout_file_set(layout, layoutFilePath.c_str(), GROUP_DIALER);
+ WPWARN(res != EINA_TRUE, "elm_layout_file_set() failed");
+
+ m_Entry = new PhDialerEntry();
+ m_Entry->create(layout, nullptr);
+ elm_object_part_content_set(layout, PART_SWALLOW_ENTRY, m_Entry->getEvasObj());
+ elm_object_part_content_set(layout, PART_SWALLOW_KEYPAD, createKeypad(layout));
+ elm_object_part_content_set(layout, PART_SWALLOW_CALL, createCallButton(layout));
+ elm_object_part_content_set(layout, PART_SWALLOW_BACKSPACE, createBackspaceButton(layout));
+
+ m_Controller = new PhDialerSearchController();
+ m_Controller->create(*this);
+
+ m_Entry->setNumber(m_InitialNumber);
+
+ return layout;
+}
+
+void PhDialerView::setNumber(std::string &number)
+{
+ m_InitialNumber = number;
+ if(m_Entry) {
+ m_Entry->setNumber(number);
+ }
+}
+
+void PhDialerView::onPush(Elm_Object_Item *naviItem)
+{
+ enableMoreButton(naviItem, &PhDialerView::onMenuPressed, this);
+}
+
+void PhDialerView::onTabSelect(Elm_Object_Item *naviItem)
+{
+ Evas_Object *conf = getWindow()->getConformantEvasObj();
+ elm_object_signal_emit(conf, "elm,state,virtualkeypad,disable", "");
+ elm_object_signal_emit(conf, "elm,state,clipboard,disable", "");
+
+ enableMoreButton(naviItem, &PhDialerView::onMenuPressed, this);
+}
+
+void PhDialerView::onTabUnselect(Elm_Object_Item *naviItem)
+{
+ Evas_Object *conf = getWindow()->getConformantEvasObj();
+ elm_object_signal_emit(conf, "elm,state,virtualkeypad,enable", "");
+ elm_object_signal_emit(conf, "elm,state,clipboard,enable", "");
+}
+
+bool PhDialerView::onTabPop()
+{
+ return true;
+}
+
+void PhDialerView::onTabScrollStart()
+{
+}
+
+void PhDialerView::onTabScrollStop()
+{
+}
+
+Evas_Object *PhDialerView::createKeypad(Evas_Object *parent)
+{
+ Evas_Object *table = elm_table_add(parent);
+ elm_table_padding_set(table, 2, 2);
+
+ int id = 0;
+ for(int i = 0; i < KEYPAD_ROWS; ++i) {
+ for(int j = 0; j < KEYPAD_COLS; ++j, ++id) {
+ using namespace std::placeholders;
+
+ PhDialerKey *key = new PhDialerKey((PhDialerKey::Id) id);
+ key->create(table, nullptr);
+ key->setOnPressed(std::bind(&PhDialerView::onKeyPressed, this, _1));
+ key->setOnLongpressed(std::bind(&PhDialerView::onKeyLongpressed, this, _1));
+
+ Evas_Object *button = key->getEvasObj();
+ evas_object_size_hint_weight_set(button, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
+ evas_object_size_hint_align_set(button, EVAS_HINT_FILL, EVAS_HINT_FILL);
+ elm_table_pack(table, button, j, i, 1, 1);
+ evas_object_show(button);
+ }
+ }
+
+ return table;
+}
+
+Evas_Object *PhDialerView::createCallButton(Evas_Object *parent)
+{
+ Evas_Object *button = elm_button_add(parent);
+ elm_object_style_set(button, "custom_circle");
+ evas_object_smart_callback_add(button, "clicked",
+ &PhDialerView::onCallPressed, this);
+
+ Evas_Object *edje = elm_layout_edje_get(button);
+ edje_object_color_class_set(edje, "button_normal", BUTTON_CALL_NORMAL, 0, 0, 0, 0, 0, 0, 0, 0);
+ edje_object_color_class_set(edje, "button_pressed", BUTTON_CALL_PRESSED, 0, 0, 0, 0, 0, 0, 0, 0);
+
+ Evas_Object *image = elm_image_add(button);
+ Eina_Bool res = elm_image_file_set(image, layoutFilePath.c_str(), BUTTON_CALL);
+ WPWARN(res != EINA_TRUE, "elm_layout_file_set() failed");
+ elm_object_part_content_set(button, "elm.swallow.content", image);
+
+ return button;
+}
+
+Evas_Object *PhDialerView::createBackspaceButton(Evas_Object *parent)
+{
+ using namespace std::placeholders;
+ WButton *key = new WButton();
+ key->create(parent, nullptr);
+ key->setOnPressed(std::bind(&PhDialerView::onBackspacePressed, this, _1));
+ key->setOnLongpressed(std::bind(&PhDialerView::onBackspaceLongpressed, this, _1));
+
+ Evas_Object *button = key->getEvasObj();
+ elm_object_style_set(button, "transparent");
+ Evas_Object *image = elm_image_add(button);
+ Eina_Bool res = elm_image_file_set(image, layoutFilePath.c_str(), BUTTON_BACKSPACE);
+ WPWARN(res != EINA_TRUE, "elm_layout_file_set() failed");
+ elm_object_part_content_set(button, "elm.swallow.content", image);
+
+ return button;
+}
+
+void PhDialerView::onKeyPressed(WButton &button)
+{
+ PhDialerKey &key = static_cast<PhDialerKey&>(button);
+ m_Entry->insert(key.getValue());
+}
+
+bool PhDialerView::onKeyLongpressed(WButton &button)
+{
+ PhDialerKey &key = static_cast<PhDialerKey&>(button);
+ int id = key.getId();
+
+ if (m_Entry->getNumber().empty()) {
+ if (id >= PhDialerKey::ID_1 && id <= PhDialerKey::ID_9) {
+ launchSpeeddial(key.getValue() - '0');
+ return true;
+ }
+ }
+
+ if (id == PhDialerKey::ID_0) {
+ m_Entry->insert('+');
+ return true;
+ }
+
+ return false;
+}
+
+void PhDialerView::onBackspacePressed(WButton &button)
+{
+ feedback_play(FEEDBACK_PATTERN_KEY_BACK);
+ m_Entry->popBack();
+}
+
+bool PhDialerView::onBackspaceLongpressed(WButton &button)
+{
+ m_Entry->clear();
+ return true;
+}
+
+void PhDialerView::onCallPressed(void *data, Evas_Object *obj, void *event_info)
+{
+ PhDialerView *view = (PhDialerView*) data;
+
+ std::string number = view->m_Entry->getNumber();
+ if (!number.empty()) {
+ launchCall(number);
+ view->m_Entry->clear();
+ } else {
+ view->m_Entry->setNumber(getLastNumber());
+ }
+}
+
+void PhDialerView::onMenuPressed(void *data, Evas_Object *obj, void *event_info)
+{
+ PhDialerView *view = (PhDialerView*) data;
+
+ WMenuPopup *popup = new WMenuPopup();
+ popup->prepare(view->getWindow()->getEvasObj(),
+ view->getNaviframe()->getEvasObj());
+
+ if (!view->m_Entry->getNumber().empty()) {
+ popup->appendItem(PAT_(PH_KPD_BUTTON_SEND_MESSAGE),
+ std::bind(&PhDialerView::onSendMessage, view));
+ popup->appendItem(PAT_(PH_KPD_OPT_ADD_2_SECOND_PAUSE_ABB),
+ std::bind(&PhDialerView::onAddPause, view));
+ popup->appendItem(PAT_(PH_KPD_OPT_ADD_WAIT_ABB),
+ std::bind(&PhDialerView::onAddWait, view));
+ }
+
+ popup->appendItem(PAT_(PH_KPD_OPT_SPEED_DIAL_SETTINGS_ABB2),
+ std::bind(&PhDialerView::onSpeeddialSettings, view));
+ popup->appendItem(PAT_(PH_KPD_OPT_CALL_SETTINGS_ABB),
+ std::bind(&PhDialerView::onCallSettings, view));
+
+ view->attachPopup(popup);
+}
+
+void PhDialerView::onSendMessage()
+{
+ int err = launchMessageComposer("sms:", m_Entry->getNumber().c_str());
+ WPWARN(err != APP_CONTROL_ERROR_NONE, "launchMessageComposer() failed(0x%x)", err);
+}
+
+void PhDialerView::onAddWait()
+{
+ m_Entry->insert(';');
+}
+
+void PhDialerView::onAddPause()
+{
+ m_Entry->insert(',');
+}
+
+void PhDialerView::onSpeeddialSettings()
+{
+ getNaviframe()->push(new PhSpeedDialView(), NULL, NULL);
+}
+
+void PhDialerView::onCallSettings()
+{
+ app_control_h request;
+ app_control_create(&request);
+ app_control_set_app_id(request, UG_CALL_SETTING);
+ app_control_set_launch_mode(request, APP_CONTROL_LAUNCH_MODE_GROUP);
+ int err = app_control_send_launch_request(request, NULL, NULL);
+ WPWARN(err != APP_CONTROL_ERROR_NONE, "app_control_send_launch_request() failed(0x%x)", err);
+ app_control_destroy(request);
+}
+
+void PhDialerView::launchCall(const std::string &number)
+{
+ int err = ::launchCall(number.c_str());
+ WPWARN(err != APP_CONTROL_ERROR_NONE, "launchCall() failed(0x%x)", err);
+}
+
+void PhDialerView::launchSpeeddial(int digit)
+{
+ std::string number = getSpeeddialNumber(digit);
+ if (!number.empty()) {
+ launchCall(number);
+ } else {
+ attachPopup(new PhDialerSpeeddialPopup(digit));
+ }
+}
+
+std::string PhDialerView::getSpeeddialNumber(int digit)
+{
+ std::string number;
+ contacts_filter_h filter = NULL;
+ contacts_query_h query = NULL;
+ contacts_list_h list = NULL;
+
+ contacts_filter_create(_contacts_speeddial._uri, &filter);
+ contacts_filter_add_int(filter, _contacts_speeddial.speeddial_number, CONTACTS_MATCH_EQUAL, digit);
+
+ contacts_query_create(_contacts_speeddial._uri, &query);
+ contacts_query_set_filter(query, filter);
+
+ int err = contacts_db_get_records_with_query(query, 0, 1, &list);
+ WPWARN(err != CONTACTS_ERROR_NONE, "contacts_db_get_records_with_query() failed(0x%x)", err);
+ if (list) {
+ contacts_record_h record = NULL;
+ contacts_list_get_current_record_p(list, &record);
+ if (record) {
+ char *str = NULL;
+ contacts_record_get_str_p(record, _contacts_speeddial.number, &str);
+ if (str) {
+ number = str;
+ }
+ }
+
+ contacts_list_destroy(list, true);
+ }
+
+ contacts_query_destroy(query);
+ contacts_filter_destroy(filter);
+
+ return number;
+}
+
+std::string PhDialerView::getLastNumber()
+{
+ std::string number;
+ contacts_list_h list = NULL;
+ contacts_query_h query = NULL;
+ contacts_filter_h filter = NULL;
+
+ contacts_filter_create(_contacts_person_phone_log._uri, &filter);
+ contacts_filter_add_int(filter, _contacts_person_phone_log.log_type,
+ CONTACTS_MATCH_GREATER_THAN_OR_EQUAL, CONTACTS_PLOG_TYPE_VOICE_INCOMMING);
+ contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_AND);
+ contacts_filter_add_int(filter, _contacts_person_phone_log.log_type,
+ CONTACTS_MATCH_LESS_THAN_OR_EQUAL, CONTACTS_PLOG_TYPE_VIDEO_BLOCKED);
+
+ contacts_query_create(_contacts_person_phone_log._uri, &query);
+ contacts_query_set_filter(query, filter);
+ contacts_query_set_sort(query, _contacts_person_phone_log.log_time, false);
+
+ int err = contacts_db_get_records_with_query(query, 0, 1, &list);
+ WPWARN(err != CONTACTS_ERROR_NONE, "contacts_db_get_records_with_query() failed(0x%x)", err);
+ if (list) {
+ contacts_record_h record = NULL;
+ contacts_list_get_current_record_p(list, &record);
+ if (record) {
+ char *str = NULL;
+ contacts_record_get_str_p(record, _contacts_person_phone_log.address, &str);
+ if (str) {
+ number = str;
+ }
+ }
+
+ contacts_list_destroy(list, true);
+ }
+
+ contacts_query_destroy(query);
+ contacts_filter_destroy(filter);
+
+ return number;
+}
diff --git a/lib-phone/ph-dialer/src/predictive-number/PhDialerPredictiveNumber.cpp b/lib-phone/ph-dialer/src/predictive-number/PhDialerPredictiveNumber.cpp
new file mode 100644
index 0000000..8158e22
--- /dev/null
+++ b/lib-phone/ph-dialer/src/predictive-number/PhDialerPredictiveNumber.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2009-2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "PhDialerPredictiveNumber.h"
+#include "PhDialerPredictiveNumberUtils.h"
+#include "PhDialerSearchInfo.h"
+#include "PhDialerPredictiveNumberTypes.h"
+#include "ContactsUtils.h"
+#include <utility>
+#include <algorithm>
+
+using namespace Ph::Dialer;
+
+namespace
+{
+ typedef contacts_list_h (*ContactListGetter)(char digit);
+
+ ContactListGetter contactListGetters[] = {
+ Utils::getSpeedDial,
+ Utils::getLogList,
+ Utils::getContactListByName,
+ Utils::getContactListByNumber
+ };
+}
+
+PredictiveNumber::PredictiveNumber()
+ :m_LastFoundIndex(-1)
+{}
+
+void PredictiveNumber::search(const std::string &number)
+{
+ if(number.empty()) {
+ clear();
+ } else {
+ chooseSearch(number);
+ }
+
+ m_Number = number;
+}
+
+const SearchList * PredictiveNumber::getSearchResult() const
+{
+ if(!m_PredictiveNumberCache.empty()) {
+ return &m_PredictiveNumberCache.back();
+ }
+
+ return nullptr;
+}
+
+bool Ph::Dialer::PredictiveNumber::empty() const
+{
+ return m_PredictiveNumberCache.empty() || m_PredictiveNumberCache.back().empty();
+}
+
+void PredictiveNumber::distinctLogs(SearchList &searchList)
+{
+ auto logPred = [](PSearchInfo pSearchInfo) -> bool {
+ return pSearchInfo->getType() == IT_LOG;
+ };
+
+ auto logComp = [](PSearchInfo lhs, PSearchInfo rhs) -> bool {
+ return lhs->getSearchString() < rhs->getSearchString();
+ };
+
+ auto eqPred = [](PSearchInfo lhs, PSearchInfo rhs) -> bool {
+ return lhs->getSearchString() == rhs->getSearchString();
+ };
+
+ SearchList::iterator beg = std::find_if(searchList.begin(), searchList.end(), logPred);
+ SearchList::iterator end = std::find_if_not(beg, searchList.end(), logPred);
+
+ if(beg != end) {
+ std::sort(beg, end, logComp);
+ SearchList::iterator itForErase = std::unique(beg, end, eqPred);
+
+ searchList.erase(itForErase, end);
+ }
+}
+
+void PredictiveNumber::firstSearch(const std::string &number)
+{
+ clear();
+
+ SearchList searchList = searchInDB(number);
+
+ if(!searchList.empty()) {
+ distinctLogs(searchList);
+
+ m_PredictiveNumberCache.resize(number.size());
+ m_PredictiveNumberCache.front() = std::move(searchList);
+ m_LastFoundIndex = 0;
+
+ if(number.size() > 1) {
+ if(!searchInCache(m_PredictiveNumberCache.begin(), number)) {
+ clear();
+ }
+ }
+ }
+}
+
+SearchList Ph::Dialer::PredictiveNumber::searchInDB(const std::string &number)
+{
+ SearchList searchList;
+ contacts_record_h record = NULL;
+
+ for(int i = IT_SPEED_DIAL; i < IT_MAX; ++i) {
+ contacts_list_h list = contactListGetters[i](number.front());
+ CONTACTS_LIST_FOREACH(list, record) {
+ SearchInfo searchInfo((InfoType)i, record);
+ if(searchInfo.getType() != IT_NONE) {
+ size_t position = searchInfo.getSearchString().find(number);
+ if (position != std::string::npos) {
+ searchInfo.updateHighlightText(number, position);
+ }
+ searchList.push_back(std::make_shared<SearchInfo>(std::move(searchInfo)));
+ }
+ }
+ contacts_list_destroy(list, true);
+ }
+
+ return searchList;
+}
+
+void PredictiveNumber::chooseSearch(const std::string &number)
+{
+ if(m_Number.empty()) {
+ firstSearch(number);
+ }
+
+ if(!needSearch(number)) {
+ return;
+ }
+
+ m_PredictiveNumberCache.resize(number.size());
+ auto rIt = firstMismatch(number);
+ if(rIt == m_PredictiveNumberCache.rend()) {//Perform initial search
+ firstSearch(number);
+ } else {
+ searchInCache(rIt.base() - 1, number);
+ }
+}
+
+bool PredictiveNumber::searchInCache(Cache::iterator from, const std::string &number)
+{
+ SearchList searchRes;
+ for(PSearchInfo &sInfo : *from) {
+ if(sInfo) {
+ size_t position = sInfo->getSearchString().find(number);
+ if (position != std::string::npos) {
+ sInfo->updateHighlightText(number, position);
+ searchRes.push_back(sInfo);
+ }
+ }
+ }
+
+ if(!searchRes.empty()) {
+ m_LastFoundIndex = m_PredictiveNumberCache.size() - 1;
+ m_PredictiveNumberCache.back() = std::move(searchRes);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+Cache::reverse_iterator PredictiveNumber::firstMismatch(const std::string &number)
+{
+ size_t minSize = std::min(m_Number.size(), number.size());
+ auto itPair = std::mismatch(m_Number.begin(), m_Number.begin() + minSize, number.begin());
+
+ auto rIt = skipEmptyResults(itPair.first - m_Number.begin());
+ return rIt;
+}
+
+Cache::reverse_iterator PredictiveNumber::skipEmptyResults(size_t offset)
+{
+ auto rIt = std::reverse_iterator<Cache::iterator>(m_PredictiveNumberCache.begin() + offset);
+
+ while(rIt != m_PredictiveNumberCache.rend() && rIt->empty()) {
+ ++rIt;
+ }
+
+ return rIt;
+}
+
+void PredictiveNumber::clear()
+{
+ m_PredictiveNumberCache.clear();
+ m_LastFoundIndex = -1;
+}
+
+bool PredictiveNumber::needSearch(const std::string &number)
+{
+ if( number.size() >= m_Number.size()
+ &&(int)(m_PredictiveNumberCache.size() - 1) > m_LastFoundIndex) {
+ return false;
+ }
+ return true;
+}
+
+void PredictiveNumber::searchFromScratch(const std::string& number)
+{
+ if(number.empty()) {
+ clear();
+ } else {
+ firstSearch(number);
+ }
+
+ m_Number = number;
+}
diff --git a/lib-phone/ph-dialer/src/predictive-number/PhDialerPredictiveNumberUtils.cpp b/lib-phone/ph-dialer/src/predictive-number/PhDialerPredictiveNumberUtils.cpp
new file mode 100644
index 0000000..699b87d
--- /dev/null
+++ b/lib-phone/ph-dialer/src/predictive-number/PhDialerPredictiveNumberUtils.cpp
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2009-2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "ContactsThumbnail.h"
+#include "ContactsUtils.h"
+#include "PhDialerPredictiveNumberUtils.h"
+#include "PhDialerLayout.h"
+#include "ContactsDebug.h"
+
+#include <Elementary.h>
+
+using namespace Ph::Dialer;
+using namespace Ph::Dialer::Utils;
+
+namespace
+{
+ const char *mask[] = {
+ "+",
+ "",
+ "abc",
+ "def",
+ "ghi",
+ "jkl",
+ "mno",
+ "pqrs",
+ "tuv",
+ "wxyz"
+ };
+
+ char getDigit(char c)
+ {
+ static const char hash[] = "22233344455566677778889999";
+
+ if(c == '+') {
+ return '0';
+ }
+
+ size_t index = tolower(c) - 'a';
+
+ if(index >= sizeof(hash) - 1) {
+ return '\0';
+ }
+
+ return hash[index];
+ }
+
+ std::string getDigitMask(char digit)
+ {
+ if(digit > '9' || digit < '0') {
+ WERROR("getDigitMask expected digit(0-9) argument, but %c is provided", digit);
+ return "";
+ }
+
+ int index = digit - '0';
+ return mask[index];
+ }
+
+ contacts_filter_h createContactNameFilters(char digit)
+ {
+ std::string mask = getDigitMask(digit);
+ if (mask.empty()) {
+ return NULL;
+ }
+
+ contacts_filter_h filter = NULL;
+ contacts_filter_create(_contacts_contact_number._uri, &filter);
+ bool isFirst = true;
+ for(auto &x : mask) {
+ if(!isFirst) {
+ contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_OR);
+ }
+
+ char str[] = { x, '\0' };
+ contacts_filter_add_str(filter, _contacts_contact_number.display_name, CONTACTS_MATCH_CONTAINS, str);
+ isFirst = false;
+ }
+ return filter;
+ }
+
+ contacts_list_h runQuery(const char *tableUri, contacts_filter_h filter)
+ {
+ contacts_list_h list = NULL;
+ contacts_query_h query = NULL;
+
+ contacts_query_create(tableUri, &query);
+ contacts_query_set_filter(query, filter);
+
+ contacts_db_get_records_with_query(query, 0, 0, &list);
+
+ contacts_query_destroy(query);
+ contacts_filter_destroy(filter);
+
+ return list;
+ }
+
+ std::string getThumbnail(int id)
+ {
+ std::string path;
+ contacts_record_h record = NULL;
+ if(contacts_db_get_record(_contacts_contact._uri, id, &record) == CONTACTS_ERROR_NONE) {
+ char *imgPath = NULL;
+ contacts_record_get_str_p(record, _contacts_contact.image_thumbnail_path, &imgPath);
+ if(imgPath) {
+ path = imgPath;
+ }
+ contacts_record_destroy(record, true);
+ }
+ return path;
+ }
+}
+
+contacts_list_h Ph::Dialer::Utils::getSpeedDial(char number)
+{
+ contacts_filter_h filter = NULL;
+ contacts_filter_create(_contacts_speeddial._uri, &filter);
+ contacts_filter_add_int(filter, _contacts_speeddial.speeddial_number, CONTACTS_MATCH_EQUAL, number - '0');
+
+ contacts_list_h list = runQuery(_contacts_speeddial._uri, filter);
+
+ return list;
+}
+
+contacts_list_h Ph::Dialer::Utils::getLogList(char digit)
+{
+ char number [] = { digit, '\0' };
+ contacts_filter_h filter = NULL;
+ contacts_filter_create(_contacts_phone_log._uri, &filter);
+
+ contacts_filter_add_str(filter, _contacts_phone_log.address, CONTACTS_MATCH_CONTAINS, number);
+ contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_AND);
+ contacts_filter_add_int(filter, _contacts_phone_log.log_type,
+ CONTACTS_MATCH_GREATER_THAN_OR_EQUAL, CONTACTS_PLOG_TYPE_VOICE_INCOMMING);
+ contacts_filter_add_operator(filter, CONTACTS_FILTER_OPERATOR_AND);
+ contacts_filter_add_int(filter, _contacts_phone_log.log_type,
+ CONTACTS_MATCH_LESS_THAN_OR_EQUAL, CONTACTS_PLOG_TYPE_VIDEO_BLOCKED);
+
+ contacts_list_h list = runQuery(_contacts_phone_log._uri, filter);
+
+ contacts_list_h retList = NULL;
+ contacts_list_create(&retList);
+ contacts_record_h record = NULL;
+ CONTACTS_LIST_FOREACH(list, record) {
+ int personId = 0;
+ contacts_record_get_int(record, _contacts_phone_log.person_id, &personId);
+ if(personId == 0) {
+ contacts_list_add(retList, record);
+ } else {
+ contacts_record_destroy(record, true);
+ }
+ }
+ contacts_list_destroy(list, false);
+
+ return retList;
+}
+
+contacts_list_h Ph::Dialer::Utils::getContactListByName(char digit)
+{
+ contacts_query_h query = NULL;
+ contacts_list_h list = NULL;
+ contacts_query_create(_contacts_contact_number._uri, &query);
+ contacts_filter_h filter = createContactNameFilters(digit);
+ if(filter) {
+ contacts_query_set_filter(query, filter);
+ contacts_db_get_records_with_query(query, 0, 0, &list);
+ }
+
+ contacts_filter_destroy(filter);
+ contacts_query_destroy(query);
+ return list;
+}
+
+contacts_list_h Ph::Dialer::Utils::getContactListByNumber(char digit)
+{
+ char number [] = { digit, '\0' };
+ contacts_filter_h filter = NULL;
+ contacts_filter_create(_contacts_contact_number._uri, &filter);
+ contacts_filter_add_str(filter, _contacts_contact_number.number, CONTACTS_MATCH_CONTAINS, number);
+
+ contacts_list_h list = runQuery(_contacts_contact_number._uri, filter);
+
+ return list;
+}
+
+std::string Ph::Dialer::Utils::contactNameToMask(const std::string &name)
+{
+ std::string number;
+ number.reserve(name.size());
+
+ for(auto &x : name) {
+ char digit = getDigit(x);
+ if(digit == '\0') {
+ break;
+ }
+ number.push_back(digit);
+ }
+ return number;
+}
+
+Evas_Object *Ph::Dialer::Utils::createThumbnail(Evas_Object *parent, int contactId)
+{
+ std::string thumbnailPath = getThumbnail(contactId);
+ Evas_Object *thumbnailImage = createThumbnail(parent, THUMBNAIL_98, thumbnailPath.c_str(), true);
+
+ return thumbnailImage;
+}
diff --git a/lib-phone/ph-dialer/src/predictive-number/PhDialerSearchInfo.cpp b/lib-phone/ph-dialer/src/predictive-number/PhDialerSearchInfo.cpp
new file mode 100644
index 0000000..f048090
--- /dev/null
+++ b/lib-phone/ph-dialer/src/predictive-number/PhDialerSearchInfo.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2009-2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "PhDialerSearchInfo.h"
+#include "PhDialerPredictiveNumberUtils.h"
+#include "ContactsCommon.h"
+
+using namespace Ph::Dialer;
+using namespace Ph::Dialer::Utils;
+
+SearchInfo::SearchInfo(InfoType type, const contacts_record_h record)
+ : m_Type(type), m_Id(0), m_SpeedDialId(0)
+{
+ if(record) {
+ if(!fillWithRecord(type, record)) {
+ m_Type = IT_NONE;
+ }
+ }
+}
+
+std::string SearchInfo::getSearchString() const
+{
+ switch(m_Type) {
+ case IT_SPEED_DIAL:
+ return std::string(1, (m_SpeedDialId + '0'));
+ case IT_LOG:
+ case IT_NUMBER:
+ return m_Number;
+ case IT_NAME:
+ return m_MaskedName;
+ case IT_NONE:
+ case IT_MAX:
+ default:
+ return "";
+ }
+}
+
+InfoType SearchInfo::getType() const
+{
+ return m_Type;
+}
+
+int SearchInfo::getId() const
+{
+ return m_Id;
+}
+
+int Ph::Dialer::SearchInfo::getSpeedDialId() const
+{
+ return m_SpeedDialId;
+}
+
+const std::string &Ph::Dialer::SearchInfo::getName(bool isHighlighted) const
+{
+ bool returnHighlight = isHighlighted && (m_Type == IT_NAME) && !m_HighlightedText.empty();
+ return returnHighlight ? m_HighlightedText : m_Name;
+}
+
+const std::string &Ph::Dialer::SearchInfo::getNumber(bool isHighlighted) const
+{
+ bool returnHighlight = isHighlighted && ((m_Type == IT_LOG) || (m_Type == IT_NUMBER)) && !m_HighlightedText.empty();
+ return returnHighlight ? m_HighlightedText : m_Number;
+}
+
+const std::string &Ph::Dialer::SearchInfo::getHighlightedText() const
+{
+ return m_HighlightedText;
+}
+
+bool SearchInfo::updateHighlightText(const std::string searchStr, size_t position)
+{
+ switch(m_Type)
+ {
+ case IT_LOG:
+ case IT_NUMBER:
+ m_HighlightedText = ContactsCommon::highlightTextByPos(m_Number, position, searchStr.size());
+ return true;
+ case IT_NAME:
+ m_HighlightedText = ContactsCommon::highlightTextByPos(m_Name, position, searchStr.size());
+ return true;
+ case IT_NONE:
+ case IT_SPEED_DIAL:
+ case IT_MAX:
+ default:
+ return false;
+ }
+}
+
+bool Ph::Dialer::SearchInfo::fillWithRecord(InfoType type, const contacts_record_h record)
+{
+ switch(type)
+ {
+ case IT_SPEED_DIAL:
+ fillSpeedDial(record);
+ return true;
+ case IT_LOG:
+ fillLog(record);
+ return true;
+ case IT_NAME:
+ case IT_NUMBER:
+ fillContact(type, record);
+ return true;
+ case IT_NONE:
+ case IT_MAX:
+ default:
+ return false;
+ }
+}
+
+void SearchInfo::fillSpeedDial(const contacts_record_h record)
+{
+ char *tempStr = NULL;
+
+ contacts_record_get_int(record, _contacts_speeddial.person_id, &m_Id);
+ contacts_record_get_int(record, _contacts_speeddial.speeddial_number, &m_SpeedDialId);
+ contacts_record_get_str_p(record, _contacts_speeddial.number, &tempStr);
+ m_Number = tempStr;
+ contacts_record_get_str_p(record, _contacts_speeddial.display_name, &tempStr);
+ m_Name = tempStr;
+}
+
+void SearchInfo::fillLog(const contacts_record_h record)
+{
+ char *tempStr = NULL;
+
+ contacts_record_get_int(record, _contacts_phone_log.person_id, &m_Id);
+ contacts_record_get_str_p(record, _contacts_phone_log.address, &tempStr);
+ m_Number = tempStr;
+}
+
+void SearchInfo::fillContact(InfoType type, const contacts_record_h record)
+{
+ char *tempStr = NULL;
+
+ contacts_record_get_int(record, _contacts_contact_number.contact_id, &m_Id);
+ contacts_record_get_str_p(record, _contacts_contact_number.display_name, &tempStr);
+ m_Name = tempStr;
+ contacts_record_get_str_p(record, _contacts_contact_number.number, &tempStr);
+ m_Number = tempStr;
+ if(type == IT_NAME) {
+ m_MaskedName = Utils::contactNameToMask(m_Name);
+ }
+}