--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd.
+ *
+ * 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.
+ *******************************************************************************/
+/**
+ * @file tbt-autofill-view.c
+ * @brief This view provide the Apps tested the autofill functionality.
+ * @author Priya Kohli (priya.kohli@samsung.com)
+ * @date May, 2019
+ * @bug No known bug.
+ * @credit Tizen Autofill framework Example
+ *
+ */
+
+#include "utils/app_module_config.h"
+#ifdef TBT_MODULE_AUTOFILL
+
+#include "utils/logger.h"
+#include "utils/config.h"
+#include "utils/ui-utils.h"
+#include "view/tbt-autofill-view.h"
+#include "view/tbt-common-view.h"
+
+#include <autofill.h>
+
+struct _autofill_view
+{
+ common_view* view;
+ Evas_Object* btn_autofill;
+};
+
+struct _Entry
+{
+ Evas_Object *entry_bg;
+ Evas_Object *entry_obj;
+ autofill_item_h ai_h;
+ autofill_save_item_h si_h;
+};
+typedef struct _Entry Entry;
+static Entry en[2];
+
+static autofill_h g_ah = NULL;
+
+static void _app_destroy_cb(void* this);
+static void save_autofill_view_info(autofill_h ah);
+
+static void connection_status_changed_cb(autofill_h ah, autofill_connection_status_e status, void *user_data)
+{
+ switch (status) {
+ case AUTOFILL_CONNECTION_STATUS_CONNECTED:
+ DBG("connected");
+ break;
+ case AUTOFILL_CONNECTION_STATUS_DISCONNECTED:
+ DBG("disconnected");
+ break;
+ case AUTOFILL_CONNECTION_STATUS_REJECTED:
+ DBG("rejected");
+ break;
+ default:
+ break;
+ }
+}
+
+static bool fill_response_item_cb(autofill_fill_response_item_h item, void *user_data)
+{
+ char *id = NULL;
+ char *value = NULL;
+ char *presentation_text = NULL;
+
+ char *id1 = NULL, *id2 = NULL;
+
+ autofill_item_get_id(en[0].ai_h, &id1);
+ autofill_item_get_id(en[1].ai_h, &id2);
+
+ autofill_fill_response_item_get_id(item, &id);
+ autofill_fill_response_item_get_presentation_text(item, &presentation_text);
+ autofill_fill_response_item_get_value(item, &value);
+
+ DBG("id : %s, value : %s, presentation text : %s", id, value, presentation_text);
+
+ if (id1 && strcmp(id, id1) == 0)
+ elm_object_text_set(en[0].entry_obj, value);/* show last group item */
+ else if (id2 && strcmp(id, id2) == 0)
+ elm_object_text_set(en[1].entry_obj, value);
+
+ if (id)
+ free(id);
+
+ if (value)
+ free(value);
+
+ if (presentation_text)
+ free(presentation_text);
+
+ return true;
+}
+
+static bool fill_response_multi_item_cb(autofill_fill_response_item_h item, void *user_data)
+{
+ char *id = NULL;
+ char *value = NULL;
+ char *presentation_text = NULL;
+ char *id1 = NULL, *id2 = NULL;
+
+ autofill_fill_response_group_h group_h = (autofill_fill_response_group_h)user_data;
+
+ autofill_item_get_id(en[0].ai_h, &id1);
+ autofill_item_get_id(en[1].ai_h, &id2);
+
+ autofill_fill_response_item_get_id(item, &id);
+ autofill_fill_response_item_get_presentation_text(item, &presentation_text);
+ autofill_fill_response_item_get_value(item, &value);
+
+ DBG("id : %s, value : %s, presentation text : %s", id, value, presentation_text);
+
+ if (id)
+ free(id);
+
+ if (value)
+ free(value);
+
+ if (presentation_text)
+ free(presentation_text);
+
+ return true;
+}
+
+static bool fill_response_group_cb(autofill_fill_response_group_h group_h, void *user_data)
+{
+ int count = *(int *)user_data;
+
+ if (count == 1)
+ autofill_fill_response_group_foreach_item(group_h, fill_response_item_cb, NULL);
+ else if (count > 1)
+ autofill_fill_response_group_foreach_item(group_h, fill_response_multi_item_cb, group_h);
+
+ return true;
+}
+
+static void fill_response_received_cb(autofill_h ah, autofill_fill_response_h fill_response, void *data)
+{
+ if (!fill_response)
+ return;
+
+ /* get fill response group count */
+ int count;
+ autofill_fill_response_get_group_count(fill_response, &count);
+ DBG("group count : %d", count);
+
+ autofill_fill_response_foreach_group(fill_response, fill_response_group_cb, &count);
+}
+
+static autofill_view_info_h create_autofill_view_info()
+{
+ autofill_view_info_h vi_h;
+ char *app_id = NULL;
+ app_get_id(&app_id);
+
+ /* create autofill view info */
+ autofill_view_info_create(&vi_h);
+ autofill_view_info_set_app_id(vi_h, app_id);
+ autofill_view_info_set_view_id(vi_h, "login");
+
+ /* append autofill item in autofill view */
+ autofill_view_info_add_item(vi_h, en[0].ai_h);
+ autofill_view_info_add_item(vi_h, en[1].ai_h);
+
+ if (app_id)
+ free(app_id);
+
+ return vi_h;
+}
+
+static void send_fill_request(autofill_h ah)
+{
+ autofill_view_info_h vi_h = create_autofill_view_info();
+
+ /* Set callback function for receiving autofill fill response */
+ autofill_fill_response_set_received_cb(ah, fill_response_received_cb, NULL);
+
+ /* Send request to get autofill fill response */
+ int ret = autofill_fill_request(ah, vi_h);
+ if (ret == AUTOFILL_ERROR_NONE)
+ DBG("Succeeded to request fill");
+ else
+ DBG("Failed to request fill : %d", ret);
+
+ autofill_view_info_destroy(vi_h);
+}
+
+static void delete_input_field(Entry *en)
+{
+ if (!en) return;
+
+ if (en->ai_h) {
+ autofill_item_destroy(en->ai_h);
+ en->ai_h = NULL;
+ }
+
+ if (en->si_h) {
+ autofill_save_item_destroy(en->si_h);
+ en->si_h = NULL;
+ }
+
+ if (en->entry_bg) {
+ evas_object_del(en->entry_bg);
+ en->entry_bg = NULL;
+ }
+
+ if (en->entry_obj) {
+ evas_object_del(en->entry_obj);
+ en->entry_obj = NULL;
+ }
+}
+
+static void entry_del_cb(void *data, Evas *e, Evas_Object *o EINA_UNUSED, void *event_info EINA_UNUSED)
+{
+ Entry *en = data;
+ save_autofill_view_info(g_ah);
+ delete_input_field(en);
+}
+
+static void
+create_input_field(Evas_Object *win, Entry *en, const char *id, const char *label, bool sensitive, autofill_hint_e autofill_hint, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h)
+{
+ if (!en) return;
+
+ // create the background for text input field
+ en->entry_bg = elm_bg_add(win);
+ elm_bg_color_set(en->entry_bg, 200, 200, 200);
+ elm_object_focus_allow_set(en->entry_bg, EINA_TRUE);
+ evas_object_move(en->entry_bg, x, y);
+ evas_object_resize(en->entry_bg, w, h);
+ evas_object_show(en->entry_bg);
+ evas_object_data_set(en->entry_bg, "Entry", en);
+
+ en->entry_obj = elm_entry_add(win);
+ evas_object_move(en->entry_obj, x, y);
+ evas_object_resize(en->entry_obj, w, h);
+ evas_object_show(en->entry_obj);
+
+ // create autofill item
+ autofill_item_create(&en->ai_h);
+ autofill_item_set_autofill_hint(en->ai_h, autofill_hint);
+ autofill_item_set_id(en->ai_h, id);
+ autofill_item_set_label(en->ai_h, label);
+ autofill_item_set_sensitive_data(en->ai_h, sensitive);
+ DBG("en : %p, ai_h : %p\n", &en, en->ai_h);
+
+ // create autofill item for save
+ autofill_save_item_create(&en->si_h);
+ autofill_save_item_set_autofill_hint(en->si_h, autofill_hint);
+ autofill_save_item_set_id(en->si_h, id);
+ autofill_save_item_set_label(en->si_h, label);
+ autofill_save_item_set_sensitive_data(en->si_h, sensitive);
+ DBG("en : %p, si_h : %p\n", &en, en->si_h);
+
+ // register callback
+ evas_object_event_callback_add(en->entry_obj, EVAS_CALLBACK_DEL, entry_del_cb, en);
+}
+
+static void save_autofill_item(Entry *en)
+{
+ const char *str;
+ char *plain_str;
+
+ str = elm_object_text_get(en->entry_obj);
+ DBG("str = %s\n", str);
+ plain_str = elm_entry_markup_to_utf8(str);
+ DBG("plain_str = %s\n", plain_str);
+ autofill_save_item_set_value(en->si_h, plain_str ? plain_str : "");
+
+ if (plain_str)
+ free(plain_str);
+}
+
+static void save_autofill_view_info(autofill_h ah)
+{
+ int ret;
+ char *app_id;
+ autofill_save_view_info_h svi_h = NULL;
+
+ app_get_id(&app_id);
+
+ /* create autofill item for saving */
+ save_autofill_item(&en[0]);
+ save_autofill_item(&en[1]);
+
+ /* create autofill save view info */
+ autofill_save_view_info_create(&svi_h);
+ autofill_save_view_info_set_app_id(svi_h, app_id);
+ autofill_save_view_info_set_view_id(svi_h, "login");
+
+ /* append autofill save item in autofill save view */
+ autofill_save_view_info_add_item(svi_h, en[0].si_h);
+ autofill_save_view_info_add_item(svi_h, en[1].si_h);
+
+ if (app_id)
+ free(app_id);
+
+ /* Send request to save autofill data */
+ ret = autofill_commit(ah, svi_h);
+ if (ret == AUTOFILL_ERROR_NONE)
+ DBG("Succeeded to commit");
+ else
+ DBG("Failed to commit. error code: 0x%X, error message: '%s'", ret, get_error_message(ret));
+
+ autofill_save_view_info_destroy(svi_h);
+}
+
+static void win_focus_out_cb(void *data, Evas_Object *obj, void *event_info)
+{
+ RETM_IF(NULL == g_ah, "g_ah is NULL");
+ save_autofill_view_info(g_ah);
+}
+
+static void autofill_app_launch_button_pressed_cb(void *data, Evas_Object *obj, void *event_info)
+{
+ send_fill_request(g_ah);
+}
+
+static void add_control_layout(autofill_view *this, Evas_Object *parent)
+{
+ RETM_IF(NULL == this, "view is NULL");
+
+ this->btn_autofill = ui_utils_push_button_add(this, parent, "Login with Autofill", autofill_app_launch_button_pressed_cb);
+ elm_object_part_content_set(this->view->layout, "controller_part", this->btn_autofill);
+
+ memset(&en[0], 0, sizeof(en[0]));
+ memset(&en[1], 0, sizeof(en[1]));
+ create_input_field(this->view->layout, &en[0], "id", "ID", false, AUTOFILL_HINT_ID, 40, 150, 640, 60);
+ create_input_field(this->view->layout, &en[1], "password", "Password", true, AUTOFILL_HINT_PASSWORD, 40, 230, 640, 60);
+
+ evas_object_smart_callback_add(parent, "unfocused", win_focus_out_cb, NULL);
+}
+
+autofill_view *autofill_view_add(Evas_Object *navi, tbt_info *tbt_info, Elm_Object_Item *item)
+{
+ RETVM_IF(NULL == navi, NULL, "navi is null");
+
+ autofill_view *this = NULL;
+ this = calloc(1, sizeof(autofill_view));
+ RETVM_IF(!this, NULL, "calloc failed");
+
+ this->view = calloc(1, sizeof(common_view));
+ RETVM_IF(!this->view, NULL, "calloc failed");
+
+
+ tbt_info->layout_group = "autofill_viewer";
+ tbt_info->layout_file = get_edje_path("autofill_viewer.edj");
+
+ common_view_add(navi, tbt_info, item, this->view, _app_destroy_cb, this);
+ RETVM_IF(NULL == this->view, NULL, "navi is null");
+
+ add_control_layout(this, this->view->layout);
+
+ int ret;
+ ret = autofill_create(&g_ah);
+ if (ret == AUTOFILL_ERROR_NONE)
+ DBG("Succeeded to create autofill");
+ else
+ {
+ DBG("Failed to create autofill. error code: 0x%X, error message: '%s'", ret, get_error_message(ret));
+ return this;
+ }
+
+ ret = autofill_connect(g_ah, connection_status_changed_cb, NULL);
+ if (ret == AUTOFILL_ERROR_NONE)
+ DBG("Succeeded to connect");
+ else
+ DBG("Failed to connect. error code: 0x%X, error message: '%s'", ret, get_error_message(ret));
+
+ return this;
+}
+
+static void _app_destroy_cb(void* this)
+{
+ RETM_IF(NULL == this, "data is NULL");
+
+ autofill_view *view = NULL;
+ view = (autofill_view*)this;
+ RETM_IF(NULL == view, "view is NULL");
+
+ RETM_IF(NULL == g_ah, "g_ah is NULL");
+ if (g_ah)
+ save_autofill_view_info(g_ah);
+
+ SAFE_DELETE(view->view);
+ SAFE_DELETE(view);
+}
+
+static void app_terminate(void *data)
+{
+ RETM_IF(NULL == g_ah, "g_ah is NULL");
+ save_autofill_view_info(g_ah);
+ autofill_destroy(g_ah);
+ g_ah = NULL;
+}
+#endif