diff options
Diffstat (limited to 'lib-phone/ph-dialer/src')
-rw-r--r-- | lib-phone/ph-dialer/src/PhDialerAddToContactsPopup.cpp | 98 | ||||
-rw-r--r-- | lib-phone/ph-dialer/src/PhDialerEntry.cpp | 89 | ||||
-rw-r--r-- | lib-phone/ph-dialer/src/PhDialerKey.cpp | 108 | ||||
-rw-r--r-- | lib-phone/ph-dialer/src/PhDialerResultListPopup.cpp | 126 | ||||
-rw-r--r-- | lib-phone/ph-dialer/src/PhDialerSearchController.cpp | 210 | ||||
-rw-r--r-- | lib-phone/ph-dialer/src/PhDialerSpeeddialPopup.cpp | 81 | ||||
-rw-r--r-- | lib-phone/ph-dialer/src/PhDialerView.cpp | 392 | ||||
-rw-r--r-- | lib-phone/ph-dialer/src/predictive-number/PhDialerPredictiveNumber.cpp | 223 | ||||
-rw-r--r-- | lib-phone/ph-dialer/src/predictive-number/PhDialerPredictiveNumberUtils.cpp | 219 | ||||
-rw-r--r-- | lib-phone/ph-dialer/src/predictive-number/PhDialerSearchInfo.cpp | 157 |
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); + } +} |