From: Ji-hoon Lee Date: Fri, 15 Dec 2023 07:10:00 +0000 (+0900) Subject: Sync with latest MMI framework code X-Git-Tag: accepted/tizen/unified/20231219.041318^0 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8b91795db43ad70b595ea904cb0225bdf6fae06f;p=platform%2Fcore%2Fuifw%2Fmmi-framework.git Sync with latest MMI framework code Sync Commit ID : bfc1bf1bdedb2992dd34065fa1ee31de1821b481 Change-Id: I9f9c651ce9c09c9ca090a6ada18293f17ee5dc89 --- diff --git a/capi/meson.build b/capi/meson.build index a3a3de2..6423806 100644 --- a/capi/meson.build +++ b/capi/meson.build @@ -8,10 +8,13 @@ install_headers( 'mmi-node-source.h', 'mmi-node-processor.h', 'mmi-node-logic.h', + 'mmi-node-controller.h', + 'mmi-node-action.h', 'mmi-port.h', 'mmi-signal.h', 'mmi-defines.h', 'mmi-plugin-module.h', 'mmi-plugin-storage.h', 'mmi.h', + 'mmi-config-parser.h', ) diff --git a/capi/mmi-attribute.h b/capi/mmi-attribute.h index f09d947..c4a5205 100644 --- a/capi/mmi-attribute.h +++ b/capi/mmi-attribute.h @@ -20,7 +20,7 @@ #define __TIZEN_UIX_MMI_ATTRIBUTE_H__ -#include +#include "mmi-platform-config.h" #include #include diff --git a/capi/mmi-config-parser.h b/capi/mmi-config-parser.h new file mode 100644 index 0000000..6c3fd31 --- /dev/null +++ b/capi/mmi-config-parser.h @@ -0,0 +1,50 @@ +/* + * Copyright © 2023 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + + +#ifndef __MMI_CONFIG_PARSER_H_ +#define __MMI_CONFIG_PARSER_H_ + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +typedef struct { + float confidence; +} mmi_config_s; + +int mmi_parser_initialize(void); +int mmi_parser_deinitialize(void); +int mmi_parser_get_confidence(float *confidence); + + +#ifdef __cplusplus +} +#endif + +#endif /* __MMI_CONFIG_PARSER_H_ */ diff --git a/capi/mmi-data.h b/capi/mmi-data.h index e1a8b5a..01ee761 100644 --- a/capi/mmi-data.h +++ b/capi/mmi-data.h @@ -20,7 +20,7 @@ #define __TIZEN_UIX_MMI_DATA_H__ -#include +#include "mmi-platform-config.h" #include @@ -49,6 +49,7 @@ typedef enum { MMI_DATA_TYPE_USER_IDENTIFICATION, MMI_DATA_TYPE_AUDIO, MMI_DATA_TYPE_VIDEO, + MMI_DATA_TYPE_COORDINATE, MMI_DATA_TYPE_BOUNDING_BOX, MMI_DATA_TYPE_ARRAY, MMI_DATA_TYPE_STRUCT, @@ -64,12 +65,12 @@ typedef enum { - MMI_DATA_INTEGER data : pointer to a signed integer type - datalen : 4 byte + datalen : 4 bytes description : cast 'data' to a 32-bit signed integer (e.g. int) - MMI_DATA_FLOAT data : pointer to a floating-point type - datalen : 4 byte + datalen : 4 bytes description : cast 'data' to a 32-bit floating-point type (e.g. float) - MMI_DATA_TEXT @@ -112,16 +113,17 @@ typedef enum { } description : video frame data +- MMI_DATA_COORDINATE + data : pointer to an array of 2 signed integers + datalen : 8 bytes + description : data is composed in below order + [ x , y ] + - MMI_DATA_BOUNDING_BOX - data : pointer to json string - datalen : length of the json string - description : data is composed in below json format - { - "x":300, - "y":150, - "w":200, - "h":200 - } + data : pointer to an array of 4 signed integers + datalen : 16 bytes + description : data is composed in below order + [ x , y , w , h ] - MMI_DATA_ARRAY data : pointer to an array of mmi_data_h struct @@ -160,6 +162,10 @@ int mmi_data_create_video(const void *ptr, size_t len, mmi_data_h *data); int mmi_data_create_user_identification(const void *ptr, size_t len, mmi_data_h *data); +int mmi_data_create_coordinate(int x, int y, mmi_data_h *data); + +int mmi_data_create_bounding_box(int x, int y, int w, int h, mmi_data_h *data); + int mmi_data_create_array(mmi_data_h *array_handle); int mmi_data_add_array_element(mmi_data_h array_handle, mmi_data_h element); @@ -184,6 +190,10 @@ int mmi_data_get_video(mmi_data_h data, const void **ptr, size_t *len); int mmi_data_get_user_identification(mmi_data_h data, const void **ptr, size_t *len); +int mmi_data_get_coordinate(mmi_data_h data, int *x, int *y); + +int mmi_data_get_bounding_box(mmi_data_h data, int *x, int *y, int *w, int *h); + int mmi_data_get_array_count(mmi_data_h array, size_t *count); int mmi_data_get_array_element(mmi_data_h array, size_t index, mmi_data_h *element); diff --git a/capi/mmi-error.h b/capi/mmi-error.h index edbf780..3e8bd45 100644 --- a/capi/mmi-error.h +++ b/capi/mmi-error.h @@ -20,7 +20,7 @@ #define __TIZEN_UIX_MMI_ERROR_H__ -#include +#include "mmi-platform-config.h" /** @@ -39,19 +39,16 @@ extern "C" { #endif -#define TIZEN_ERROR_MMI -0x030F0000 - typedef enum { - MMI_ERROR_NONE = TIZEN_ERROR_NONE, /**< Successful */ - MMI_ERROR_OUT_OF_MEMORY = TIZEN_ERROR_OUT_OF_MEMORY, /**< Out of Memory */ - MMI_ERROR_IO_ERROR = TIZEN_ERROR_IO_ERROR, /**< I/O error */ - MMI_ERROR_INVALID_PARAMETER = TIZEN_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ - MMI_ERROR_OUT_OF_NETWORK = TIZEN_ERROR_NETWORK_DOWN, /**< Network is down */ - MMI_ERROR_TIMED_OUT = TIZEN_ERROR_TIMED_OUT, /**< No answer from the daemon */ - MMI_ERROR_PERMISSION_DENIED = TIZEN_ERROR_PERMISSION_DENIED, /**< Permission denied */ - MMI_ERROR_NOT_SUPPORTED = TIZEN_ERROR_NOT_SUPPORTED, /**< MMI NOT supported */ - MMI_ERROR_OPERATION_FAILED = TIZEN_ERROR_MMI | 0x01, /**< Operation failed */ - MMI_ERROR_RESOURCE_BUSY = TIZEN_ERROR_MMI | 0x02, /**< Resource busy */ + MMI_ERROR_NONE = PLATFORM_ERROR_NONE, /**< Successful */ + MMI_ERROR_OUT_OF_MEMORY = PLATFORM_ERROR_OUT_OF_MEMORY, /**< Out of Memory */ + MMI_ERROR_IO_ERROR = PLATFORM_ERROR_IO_ERROR, /**< I/O error */ + MMI_ERROR_INVALID_PARAMETER = PLATFORM_ERROR_INVALID_PARAMETER, /**< Invalid parameter */ + MMI_ERROR_TIMED_OUT = PLATFORM_ERROR_TIMED_OUT, /**< No answer from the daemon */ + MMI_ERROR_PERMISSION_DENIED = PLATFORM_ERROR_PERMISSION_DENIED, /**< Permission denied */ + MMI_ERROR_NOT_SUPPORTED = PLATFORM_ERROR_NOT_SUPPORTED, /**< MMI NOT supported */ + MMI_ERROR_OPERATION_FAILED = PLATFORM_ERROR_OPERATION_FAILED, /**< Operation failed */ + MMI_ERROR_RESOURCE_BUSY = PLATFORM_ERROR_RESOURCE_BUSY, /**< Resource busy */ } mmi_error_e; diff --git a/capi/mmi-node-action.h b/capi/mmi-node-action.h new file mode 100644 index 0000000..69e3020 --- /dev/null +++ b/capi/mmi-node-action.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023 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. + * + */ + + +#ifndef __TIZEN_UIX_MMI_NODE_ACTION_H__ +#define __TIZEN_UIX_MMI_NODE_ACTION_H__ + + + +#include + +/** +* @file mmi-node-action.h +*/ + + +/** +* @addtogroup CAPI_UIX_MMI_MODULE +* @{ +*/ + + +#ifdef __cplusplus +extern "C" { +#endif + + +enum mmi_standard_node_action_type_e { + MMI_STANDARD_NODE_ACTION_TYPE_NONE, + + /* - Description : Emits a mouse event + - Attributes : + - "EVENT" : string + Default : "CLICK" + Description : The type of mouse event to emit + Supported values are : "CLICK", "DOWN", "UP" + - Input Port 1 + Name : "COORDINATE" + Data Type : MMI_DATA_TYPE_COORDINATE + Description : When a coordinate data is received, emits a mouse event + */ + MMI_STANDARD_NODE_ACTION_TYPE_MOUSE_EVENT, + + MMI_STANDARD_NODE_ACTION_TYPE_KEY_EVENT, +}; + +int mmi_standard_node_create_action(mmi_standard_node_action_type_e type, mmi_node_h *node); + +int mmi_standard_node_get_action_type(mmi_node_h node, mmi_standard_node_action_type_e *type); + +int mmi_standard_node_register_action(mmi_standard_node_action_type_e type, mmi_node_callbacks *callbacks, mmi_node_h node); + +#ifdef __cplusplus +} +#endif + + +/** + * @} + */ + + +#endif /* __TIZEN_UIX_MMI_NODE_LOGIC_H__ */ diff --git a/capi/mmi-node-processor.h b/capi/mmi-node-processor.h index 3cd7551..8ff0f15 100644 --- a/capi/mmi-node-processor.h +++ b/capi/mmi-node-processor.h @@ -56,6 +56,17 @@ enum mmi_standard_node_processor_type_e { */ MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR, + /* + - Attributes : None + - Input Port 1 + Name : "VIDEO_IN" + Data Type : MMI_DATA_TYPE_VIDEO + - Output Port 1 + Name : "VIDEO_OUT" + Data Type : MMI_DATA_TYPE_VIDEO + */ + MMI_STANDARD_NODE_PROCESSOR_TYPE_VIDEO_CONVERTER, + /* - Attributes : None - Input Port 1 diff --git a/capi/mmi-node.h b/capi/mmi-node.h index 124ecca..a6ddc09 100644 --- a/capi/mmi-node.h +++ b/capi/mmi-node.h @@ -20,7 +20,7 @@ #define __TIZEN_UIX_MMI_NODE_H__ -#include +#include "mmi-platform-config.h" #include #include @@ -49,6 +49,7 @@ enum mmi_standard_node_type_e { MMI_STANDARD_NODE_TYPE_PROCESSOR, MMI_STANDARD_NODE_TYPE_LOGIC, MMI_STANDARD_NODE_TYPE_CONTROLLER, + MMI_STANDARD_NODE_TYPE_ACTION, }; typedef void* mmi_node_instance_h; diff --git a/capi/mmi-plugin-storage.h b/capi/mmi-plugin-storage.h index b68e22c..336233f 100644 --- a/capi/mmi-plugin-storage.h +++ b/capi/mmi-plugin-storage.h @@ -27,6 +27,7 @@ #include #include #include +#include #include /** diff --git a/capi/mmi-port.h b/capi/mmi-port.h index 2efc3de..23963fb 100644 --- a/capi/mmi-port.h +++ b/capi/mmi-port.h @@ -20,7 +20,7 @@ #define __TIZEN_UIX_MMI_PORT_H__ -#include +#include "mmi-platform-config.h" #include #include diff --git a/capi/mmi-primitive-value.h b/capi/mmi-primitive-value.h index b8b25e8..8679ca8 100644 --- a/capi/mmi-primitive-value.h +++ b/capi/mmi-primitive-value.h @@ -20,7 +20,7 @@ #define __TIZEN_UIX_MMI_PRIMITIVE_VALUE_H__ -#include +#include "mmi-platform-config.h" #include diff --git a/capi/mmi-signal.h b/capi/mmi-signal.h index 3d989ec..7db8613 100644 --- a/capi/mmi-signal.h +++ b/capi/mmi-signal.h @@ -20,7 +20,7 @@ #define __TIZEN_UIX_MMI_SIGNAL_H__ -#include +#include "mmi-platform-config.h" #include #include diff --git a/capi/mmi-workflow.h b/capi/mmi-workflow.h index 148dd3e..862ebb4 100644 --- a/capi/mmi-workflow.h +++ b/capi/mmi-workflow.h @@ -20,7 +20,7 @@ #define __TIZEN_UIX_MMI_WORKFLOW_H__ -#include +#include "mmi-platform-config.h" #include #include @@ -75,6 +75,12 @@ typedef struct { unsigned char *serialized_default_value; } mmi_workflow_attribute_default_value_info_s; +typedef struct { + char signal_name[MMI_NAME_MAX_LENGTH]; + char target_node_name[MMI_NAME_MAX_LENGTH]; + char target_signal_name[MMI_NAME_MAX_LENGTH]; +} mmi_workflow_signal_assignment_info_s; + typedef struct { char output_name[MMI_NAME_MAX_LENGTH]; char from_node_name[MMI_NAME_MAX_LENGTH]; @@ -91,6 +97,8 @@ typedef struct { size_t attribute_assignment_info_count; mmi_workflow_attribute_default_value_info_s *attribute_default_value_infos; size_t attribute_default_value_info_count; + mmi_workflow_signal_assignment_info_s *signal_assignment_infos; + size_t signal_assignment_info_count; mmi_workflow_output_assignment_info_s *output_assignment_infos; size_t output_assignment_info_count; } mmi_workflow_s; @@ -125,7 +133,7 @@ int mmi_workflow_attribute_assign(mmi_workflow_h workflow, const char *attribute int mmi_workflow_attribute_set_default_value(mmi_workflow_h workflow, mmi_attribute_h default_value); /* Assign a signal of a workflow to a signal of a specific node in a workflow prototype */ -int mmi_workflow_signal_assign(mmi_workflow_h workflow, const char *workflow_signal, mmi_node_h node, const char *node_signal); +int mmi_workflow_signal_assign(mmi_workflow_h workflow, const char *signal_name, const char *target_node_name, const char *target_signal_name); /* Assign an output of a workflow to a OUT port of a specific node in a workflow prototype */ /* FIXME: It would be better to use handles instead of names. */ @@ -172,7 +180,7 @@ int mmi_workflow_instance_deactivate(mmi_workflow_instance_h instance); int mmi_workflow_instance_set_attribute(mmi_workflow_instance_h instance, mmi_attribute_h attribute); /* Emit a signal to a workflow instance */ -// int mmi_workflow_instance_signal_emit(mmi_workflow_instance_h instance, mmi_signal_h signal); +int mmi_workflow_instance_emit_signal(mmi_workflow_instance_h instance, mmi_signal_h signal); /* Set a callback function to receive workflow output */ int mmi_workflow_instance_set_output_callback(mmi_workflow_instance_h instance, const char *name, mmi_workflow_output_cb callback, void *user_data); diff --git a/capi/mmi.h b/capi/mmi.h index e3df8d8..06a1cd4 100644 --- a/capi/mmi.h +++ b/capi/mmi.h @@ -18,7 +18,8 @@ #ifndef __MMI_H__ #define __MMI_H__ -#include +#include "mmi-platform-config.h" + #define MMI_API __attribute__ ((visibility("default"))) #include diff --git a/external/magic_enum/magic_enum.hpp b/external/magic_enum/magic_enum.hpp new file mode 100644 index 0000000..a4ea49a --- /dev/null +++ b/external/magic_enum/magic_enum.hpp @@ -0,0 +1,1472 @@ +// __ __ _ ______ _____ +// | \/ | (_) | ____| / ____|_ _ +// | \ / | __ _ __ _ _ ___ | |__ _ __ _ _ _ __ ___ | | _| |_ _| |_ +// | |\/| |/ _` |/ _` | |/ __| | __| | '_ \| | | | '_ ` _ \ | | |_ _|_ _| +// | | | | (_| | (_| | | (__ | |____| | | | |_| | | | | | | | |____|_| |_| +// |_| |_|\__,_|\__, |_|\___| |______|_| |_|\__,_|_| |_| |_| \_____| +// __/ | https://github.com/Neargye/magic_enum +// |___/ version 0.9.5 +// +// Licensed under the MIT License . +// SPDX-License-Identifier: MIT +// Copyright (c) 2019 - 2023 Daniil Goncharov . +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef NEARGYE_MAGIC_ENUM_HPP +#define NEARGYE_MAGIC_ENUM_HPP + +#define MAGIC_ENUM_VERSION_MAJOR 0 +#define MAGIC_ENUM_VERSION_MINOR 9 +#define MAGIC_ENUM_VERSION_PATCH 5 + +#include +#include +#include +#include +#include +#include +#include + +#if defined(MAGIC_ENUM_CONFIG_FILE) +# include MAGIC_ENUM_CONFIG_FILE +#endif + +#if !defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) +# include +#endif +#if !defined(MAGIC_ENUM_USING_ALIAS_STRING) +# include +#endif +#if !defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) +# include +#endif + +#if defined(MAGIC_ENUM_NO_ASSERT) +# define MAGIC_ENUM_ASSERT(...) static_cast(0) +#else +# include +# define MAGIC_ENUM_ASSERT(...) assert((__VA_ARGS__)) +#endif + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wunknown-warning-option" +# pragma clang diagnostic ignored "-Wenum-constexpr-conversion" +# pragma clang diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast('\0')' for char_type = char (common on Linux). +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wmaybe-uninitialized" // May be used uninitialized 'return {};'. +# pragma GCC diagnostic ignored "-Wuseless-cast" // suppresses 'static_cast('\0')' for char_type = char (common on Linux). +#elif defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable : 26495) // Variable 'static_str::chars_' is uninitialized. +# pragma warning(disable : 28020) // Arithmetic overflow: Using operator '-' on a 4 byte value and then casting the result to a 8 byte value. +# pragma warning(disable : 26451) // The expression '0<=_Param_(1)&&_Param_(1)<=1-1' is not true at this call. +# pragma warning(disable : 4514) // Unreferenced inline function has been removed. +#endif + +// Checks magic_enum compiler compatibility. +#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910 || defined(__RESHARPER__) +# undef MAGIC_ENUM_SUPPORTED +# define MAGIC_ENUM_SUPPORTED 1 +#endif + +// Checks magic_enum compiler aliases compatibility. +#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920 +# undef MAGIC_ENUM_SUPPORTED_ALIASES +# define MAGIC_ENUM_SUPPORTED_ALIASES 1 +#endif + +// Enum value must be greater or equals than MAGIC_ENUM_RANGE_MIN. By default MAGIC_ENUM_RANGE_MIN = -128. +// If need another min range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN. +#if !defined(MAGIC_ENUM_RANGE_MIN) +# define MAGIC_ENUM_RANGE_MIN -128 +#endif + +// Enum value must be less or equals than MAGIC_ENUM_RANGE_MAX. By default MAGIC_ENUM_RANGE_MAX = 128. +// If need another max range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MAX. +#if !defined(MAGIC_ENUM_RANGE_MAX) +# define MAGIC_ENUM_RANGE_MAX 127 +#endif + +// Improve ReSharper C++ intellisense performance with builtins, avoiding unnecessary template instantiations. +#if defined(__RESHARPER__) +# undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN +# undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN +# if __RESHARPER__ >= 20230100 +# define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) __rscpp_enumerator_name(V) +# define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) __rscpp_type_name() +# else +# define MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V) nullptr +# define MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(T) nullptr +# endif +#endif + +namespace magic_enum { + +// If need another optional type, define the macro MAGIC_ENUM_USING_ALIAS_OPTIONAL. +#if defined(MAGIC_ENUM_USING_ALIAS_OPTIONAL) +MAGIC_ENUM_USING_ALIAS_OPTIONAL +#else +using std::optional; +#endif + +// If need another string_view type, define the macro MAGIC_ENUM_USING_ALIAS_STRING_VIEW. +#if defined(MAGIC_ENUM_USING_ALIAS_STRING_VIEW) +MAGIC_ENUM_USING_ALIAS_STRING_VIEW +#else +using std::string_view; +#endif + +// If need another string type, define the macro MAGIC_ENUM_USING_ALIAS_STRING. +#if defined(MAGIC_ENUM_USING_ALIAS_STRING) +MAGIC_ENUM_USING_ALIAS_STRING +#else +using std::string; +#endif + +using char_type = string_view::value_type; +static_assert(std::is_same_v, "magic_enum::customize requires same string_view::value_type and string::value_type"); +static_assert([] { + if constexpr (std::is_same_v) { + constexpr const char c[] = "abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|"; + constexpr const wchar_t wc[] = L"abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789|"; + static_assert(std::size(c) == std::size(wc), "magic_enum::customize identifier characters are multichars in wchar_t."); + + for (std::size_t i = 0; i < std::size(c); ++i) { + if (c[i] != wc[i]) { + return false; + } + } + } + return true; +} (), "magic_enum::customize wchar_t is not compatible with ASCII."); + +namespace customize { + +// Enum value must be in range [MAGIC_ENUM_RANGE_MIN, MAGIC_ENUM_RANGE_MAX]. By default MAGIC_ENUM_RANGE_MIN = -128, MAGIC_ENUM_RANGE_MAX = 128. +// If need another range for all enum types by default, redefine the macro MAGIC_ENUM_RANGE_MIN and MAGIC_ENUM_RANGE_MAX. +// If need another range for specific enum type, add specialization enum_range for necessary enum type. +template +struct enum_range { + static_assert(std::is_enum_v, "magic_enum::customize::enum_range requires enum type."); + static constexpr int min = MAGIC_ENUM_RANGE_MIN; + static constexpr int max = MAGIC_ENUM_RANGE_MAX; + static_assert(max > min, "magic_enum::customize::enum_range requires max > min."); +}; + +static_assert(MAGIC_ENUM_RANGE_MAX > MAGIC_ENUM_RANGE_MIN, "MAGIC_ENUM_RANGE_MAX must be greater than MAGIC_ENUM_RANGE_MIN."); +static_assert((MAGIC_ENUM_RANGE_MAX - MAGIC_ENUM_RANGE_MIN) < (std::numeric_limits::max)(), "MAGIC_ENUM_RANGE must be less than UINT16_MAX."); + +namespace detail { + +enum class customize_tag { + default_tag, + invalid_tag, + custom_tag +}; + +} // namespace magic_enum::customize::detail + +class customize_t : public std::pair { + public: + constexpr customize_t(string_view srt) : std::pair{detail::customize_tag::custom_tag, srt} {} + constexpr customize_t(const char_type* srt) : customize_t{string_view{srt}} {} + constexpr customize_t(detail::customize_tag tag) : std::pair{tag, string_view{}} { + MAGIC_ENUM_ASSERT(tag != detail::customize_tag::custom_tag); + } +}; + +// Default customize. +inline constexpr auto default_tag = customize_t{detail::customize_tag::default_tag}; +// Invalid customize. +inline constexpr auto invalid_tag = customize_t{detail::customize_tag::invalid_tag}; + +// If need custom names for enum, add specialization enum_name for necessary enum type. +template +constexpr customize_t enum_name(E) noexcept { + return default_tag; +} + +// If need custom type name for enum, add specialization enum_type_name for necessary enum type. +template +constexpr customize_t enum_type_name() noexcept { + return default_tag; +} + +} // namespace magic_enum::customize + +namespace detail { + +template +struct supported +#if defined(MAGIC_ENUM_SUPPORTED) && MAGIC_ENUM_SUPPORTED || defined(MAGIC_ENUM_NO_CHECK_SUPPORT) + : std::true_type {}; +#else + : std::false_type {}; +#endif + +template , std::enable_if_t, int> = 0> +using enum_constant = std::integral_constant; + +template +inline constexpr bool always_false_v = false; + +template +struct has_is_flags : std::false_type {}; + +template +struct has_is_flags::is_flags)>> : std::bool_constant::is_flags)>>> {}; + +template +struct range_min : std::integral_constant {}; + +template +struct range_min::min)>> : std::integral_constant::min), customize::enum_range::min> {}; + +template +struct range_max : std::integral_constant {}; + +template +struct range_max::max)>> : std::integral_constant::max), customize::enum_range::max> {}; + +struct str_view { + const char* str_ = nullptr; + std::size_t size_ = 0; +}; + +template +class static_str { + public: + constexpr explicit static_str(str_view str) noexcept : static_str{str.str_, std::make_integer_sequence{}} { + MAGIC_ENUM_ASSERT(str.size_ == N); + } + + constexpr explicit static_str(string_view str) noexcept : static_str{str.data(), std::make_integer_sequence{}} { + MAGIC_ENUM_ASSERT(str.size() == N); + } + + constexpr const char_type* data() const noexcept { return chars_; } + + constexpr std::uint16_t size() const noexcept { return N; } + + constexpr operator string_view() const noexcept { return {data(), size()}; } + + private: + template + constexpr static_str(const char* str, std::integer_sequence) noexcept : chars_{static_cast(str[I])..., static_cast('\0')} {} + + template + constexpr static_str(string_view str, std::integer_sequence) noexcept : chars_{str[I]..., static_cast('\0')} {} + + char_type chars_[static_cast(N) + 1]; +}; + +template <> +class static_str<0> { + public: + constexpr explicit static_str() = default; + + constexpr explicit static_str(str_view) noexcept {} + + constexpr explicit static_str(string_view) noexcept {} + + constexpr const char_type* data() const noexcept { return nullptr; } + + constexpr std::uint16_t size() const noexcept { return 0; } + + constexpr operator string_view() const noexcept { return {}; } +}; + +template > +class case_insensitive { + static constexpr char_type to_lower(char_type c) noexcept { + return (c >= static_cast('A') && c <= static_cast('Z')) ? static_cast(c + (static_cast('a') - static_cast('A'))) : c; + } + + public: + template + constexpr auto operator()(L lhs, R rhs) const noexcept -> std::enable_if_t, char_type> && std::is_same_v, char_type>, bool> { + return Op{}(to_lower(lhs), to_lower(rhs)); + } +}; + +constexpr std::size_t find(string_view str, char_type c) noexcept { +#if defined(__clang__) && __clang_major__ < 9 && defined(__GLIBCXX__) || defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) +// https://stackoverflow.com/questions/56484834/constexpr-stdstring-viewfind-last-of-doesnt-work-on-clang-8-with-libstdc +// https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html + constexpr bool workaround = true; +#else + constexpr bool workaround = false; +#endif + + if constexpr (workaround) { + for (std::size_t i = 0; i < str.size(); ++i) { + if (str[i] == c) { + return i; + } + } + + return string_view::npos; + } else { + return str.find(c); + } +} + +template +constexpr bool is_default_predicate() noexcept { + return std::is_same_v, std::equal_to> || + std::is_same_v, std::equal_to<>>; +} + +template +constexpr bool is_nothrow_invocable() { + return is_default_predicate() || + std::is_nothrow_invocable_r_v; +} + +template +constexpr bool cmp_equal(string_view lhs, string_view rhs, [[maybe_unused]] BinaryPredicate&& p) noexcept(is_nothrow_invocable()) { +#if defined(_MSC_VER) && _MSC_VER < 1920 && !defined(__clang__) + // https://developercommunity.visualstudio.com/content/problem/360432/vs20178-regression-c-failed-in-test.html + // https://developercommunity.visualstudio.com/content/problem/232218/c-constexpr-string-view.html + constexpr bool workaround = true; +#else + constexpr bool workaround = false; +#endif + + if constexpr (!is_default_predicate() || workaround) { + if (lhs.size() != rhs.size()) { + return false; + } + + const auto size = lhs.size(); + for (std::size_t i = 0; i < size; ++i) { + if (!p(lhs[i], rhs[i])) { + return false; + } + } + + return true; + } else { + return lhs == rhs; + } +} + +template +constexpr bool cmp_less(L lhs, R rhs) noexcept { + static_assert(std::is_integral_v && std::is_integral_v, "magic_enum::detail::cmp_less requires integral type."); + + if constexpr (std::is_signed_v == std::is_signed_v) { + // If same signedness (both signed or both unsigned). + return lhs < rhs; + } else if constexpr (std::is_same_v) { // bool special case + return static_cast(lhs) < rhs; + } else if constexpr (std::is_same_v) { // bool special case + return lhs < static_cast(rhs); + } else if constexpr (std::is_signed_v) { + // If 'right' is negative, then result is 'false', otherwise cast & compare. + return rhs > 0 && lhs < static_cast>(rhs); + } else { + // If 'left' is negative, then result is 'true', otherwise cast & compare. + return lhs < 0 || static_cast>(lhs) < rhs; + } +} + +template +constexpr I log2(I value) noexcept { + static_assert(std::is_integral_v, "magic_enum::detail::log2 requires integral type."); + + if constexpr (std::is_same_v) { // bool special case + return MAGIC_ENUM_ASSERT(false), value; + } else { + auto ret = I{0}; + for (; value > I{1}; value >>= I{1}, ++ret) {} + + return ret; + } +} + +#if defined(__cpp_lib_array_constexpr) && __cpp_lib_array_constexpr >= 201603L +# define MAGIC_ENUM_ARRAY_CONSTEXPR 1 +#else +template +constexpr std::array, N> to_array(T (&a)[N], std::index_sequence) noexcept { + return {{a[I]...}}; +} +#endif + +template +inline constexpr bool is_enum_v = std::is_enum_v && std::is_same_v>; + +template +constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); + + if constexpr (supported::value) { +#if defined(MAGIC_ENUM_GET_TYPE_NAME_BUILTIN) + constexpr auto name_ptr = MAGIC_ENUM_GET_TYPE_NAME_BUILTIN(E); + constexpr auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{}; +#elif defined(__clang__) + str_view name; + if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) { + static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__."); + return str_view{}; + } else { + name.size_ = sizeof(__PRETTY_FUNCTION__) - 36; + name.str_ = __PRETTY_FUNCTION__ + 34; + } +#elif defined(__GNUC__) + auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1}; + if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) { + static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__."); + return str_view{}; + } else if (name.str_[name.size_ - 1] == ']') { + name.size_ -= 50; + name.str_ += 49; + } else { + name.size_ -= 40; + name.str_ += 37; + } +#elif defined(_MSC_VER) + // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284). + str_view name; + name.str_ = __FUNCSIG__; + name.str_ += 40; + name.size_ += sizeof(__FUNCSIG__) - 57; +#else + auto name = str_view{}; +#endif + std::size_t p = 0; + for (std::size_t i = name.size_; i > 0; --i) { + if (name.str_[i] == ':') { + p = i + 1; + break; + } + } + if (p > 0) { + name.size_ -= p; + name.str_ += p; + } + return name; + } else { + return str_view{}; // Unsupported compiler or Invalid customize. + } +} + +template +constexpr auto type_name() noexcept { + [[maybe_unused]] constexpr auto custom = customize::enum_type_name(); + static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type."); + if constexpr (custom.first == customize::detail::customize_tag::custom_tag) { + constexpr auto name = custom.second; + static_assert(!name.empty(), "magic_enum::customize requires not empty string."); + return static_str{name}; + } else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) { + return static_str<0>{}; + } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) { + constexpr auto name = n(); + return static_str{name}; + } else { + static_assert(always_false_v, "magic_enum::customize invalid."); + } +} + +template +inline constexpr auto type_name_v = type_name(); + +template +constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); + + if constexpr (supported::value) { +#if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN) + constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V); + auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{}; +#elif defined(__clang__) + str_view name; + if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) { + static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__."); + return str_view{}; + } else { + name.size_ = sizeof(__PRETTY_FUNCTION__) - 36; + name.str_ = __PRETTY_FUNCTION__ + 34; + } + if (name.size_ > 22 && name.str_[0] == '(' && name.str_[1] == 'a' && name.str_[10] == ' ' && name.str_[22] == ':') { + name.size_ -= 23; + name.str_ += 23; + } + if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) { + name = str_view{}; + } +#elif defined(__GNUC__) + auto name = str_view{__PRETTY_FUNCTION__, sizeof(__PRETTY_FUNCTION__) - 1}; + if constexpr (sizeof(__PRETTY_FUNCTION__) == sizeof(__FUNCTION__)) { + static_assert(always_false_v, "magic_enum::detail::n requires __PRETTY_FUNCTION__."); + return str_view{}; + } else if (name.str_[name.size_ - 1] == ']') { + name.size_ -= 55; + name.str_ += 54; + } else { + name.size_ -= 40; + name.str_ += 37; + } + if (name.str_[0] == '(') { + name = str_view{}; + } +#elif defined(_MSC_VER) + str_view name; + if ((__FUNCSIG__[5] == '_' && __FUNCSIG__[35] != '(') || (__FUNCSIG__[5] == 'c' && __FUNCSIG__[41] != '(')) { + // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284). + name.str_ = __FUNCSIG__; + name.str_ += 35; + name.size_ = sizeof(__FUNCSIG__) - 52; + } +#else + auto name = str_view{}; +#endif + std::size_t p = 0; + for (std::size_t i = name.size_; i > 0; --i) { + if (name.str_[i] == ':') { + p = i + 1; + break; + } + } + if (p > 0) { + name.size_ -= p; + name.str_ += p; + } + return name; + } else { + return str_view{}; // Unsupported compiler or Invalid customize. + } +} + +#if defined(_MSC_VER) && !defined(__clang__) && _MSC_VER < 1920 +# define MAGIC_ENUM_VS_2017_WORKAROUND 1 +#endif + +#if defined(MAGIC_ENUM_VS_2017_WORKAROUND) +template +constexpr auto n() noexcept { + static_assert(is_enum_v, "magic_enum::detail::n requires enum type."); + +# if defined(MAGIC_ENUM_GET_ENUM_NAME_BUILTIN) + constexpr auto name_ptr = MAGIC_ENUM_GET_ENUM_NAME_BUILTIN(V); + auto name = name_ptr ? str_view{name_ptr, std::char_traits::length(name_ptr)} : str_view{}; +# else + // CLI/C++ workaround (see https://github.com/Neargye/magic_enum/issues/284). + str_view name; + name.str_ = __FUNCSIG__; + name.size_ = sizeof(__FUNCSIG__) - 17; + std::size_t p = 0; + for (std::size_t i = name.size_; i > 0; --i) { + if (name.str_[i] == ',' || name.str_[i] == ':') { + p = i + 1; + break; + } + } + if (p > 0) { + name.size_ -= p; + name.str_ += p; + } + if (name.str_[0] == '(' || name.str_[0] == '-' || (name.str_[0] >= '0' && name.str_[0] <= '9')) { + name = str_view{}; + } + return name; +# endif +} +#endif + +template +constexpr auto enum_name() noexcept { + [[maybe_unused]] constexpr auto custom = customize::enum_name(V); + static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type."); + if constexpr (custom.first == customize::detail::customize_tag::custom_tag) { + constexpr auto name = custom.second; + static_assert(!name.empty(), "magic_enum::customize requires not empty string."); + return static_str{name}; + } else if constexpr (custom.first == customize::detail::customize_tag::invalid_tag) { + return static_str<0>{}; + } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) { +#if defined(MAGIC_ENUM_VS_2017_WORKAROUND) + constexpr auto name = n(); +#else + constexpr auto name = n(); +#endif + return static_str{name}; + } else { + static_assert(always_false_v, "magic_enum::customize invalid."); + } +} + +template +inline constexpr auto enum_name_v = enum_name(); + +template +constexpr bool is_valid() noexcept { +#if defined(__clang__) && __clang_major__ >= 16 + // https://reviews.llvm.org/D130058, https://reviews.llvm.org/D131307 + constexpr E v = __builtin_bit_cast(E, V); +#else + constexpr E v = static_cast(V); +#endif + [[maybe_unused]] constexpr auto custom = customize::enum_name(v); + static_assert(std::is_same_v, customize::customize_t>, "magic_enum::customize requires customize_t type."); + if constexpr (custom.first == customize::detail::customize_tag::custom_tag) { + constexpr auto name = custom.second; + static_assert(!name.empty(), "magic_enum::customize requires not empty string."); + return name.size() != 0; + } else if constexpr (custom.first == customize::detail::customize_tag::default_tag) { +#if defined(MAGIC_ENUM_VS_2017_WORKAROUND) + return n().size_ != 0; +#else + return n().size_ != 0; +#endif + } else { + return false; + } +} + +enum class enum_subtype { + common, + flags +}; + +template > +constexpr U ualue(std::size_t i) noexcept { + if constexpr (std::is_same_v) { // bool special case + static_assert(O == 0, "magic_enum::detail::ualue requires valid offset."); + + return static_cast(i); + } else if constexpr (S == enum_subtype::flags) { + return static_cast(U{1} << static_cast(static_cast(i) + O)); + } else { + return static_cast(static_cast(i) + O); + } +} + +template > +constexpr E value(std::size_t i) noexcept { + return static_cast(ualue(i)); +} + +template > +constexpr int reflected_min() noexcept { + if constexpr (S == enum_subtype::flags) { + return 0; + } else { + constexpr auto lhs = range_min::value; + constexpr auto rhs = (std::numeric_limits::min)(); + + if constexpr (cmp_less(rhs, lhs)) { + return lhs; + } else { + return rhs; + } + } +} + +template > +constexpr int reflected_max() noexcept { + if constexpr (S == enum_subtype::flags) { + return std::numeric_limits::digits - 1; + } else { + constexpr auto lhs = range_max::value; + constexpr auto rhs = (std::numeric_limits::max)(); + + if constexpr (cmp_less(lhs, rhs)) { + return lhs; + } else { + return rhs; + } + } +} + +#define MAGIC_ENUM_FOR_EACH_256(T) \ + T( 0)T( 1)T( 2)T( 3)T( 4)T( 5)T( 6)T( 7)T( 8)T( 9)T( 10)T( 11)T( 12)T( 13)T( 14)T( 15)T( 16)T( 17)T( 18)T( 19)T( 20)T( 21)T( 22)T( 23)T( 24)T( 25)T( 26)T( 27)T( 28)T( 29)T( 30)T( 31) \ + T( 32)T( 33)T( 34)T( 35)T( 36)T( 37)T( 38)T( 39)T( 40)T( 41)T( 42)T( 43)T( 44)T( 45)T( 46)T( 47)T( 48)T( 49)T( 50)T( 51)T( 52)T( 53)T( 54)T( 55)T( 56)T( 57)T( 58)T( 59)T( 60)T( 61)T( 62)T( 63) \ + T( 64)T( 65)T( 66)T( 67)T( 68)T( 69)T( 70)T( 71)T( 72)T( 73)T( 74)T( 75)T( 76)T( 77)T( 78)T( 79)T( 80)T( 81)T( 82)T( 83)T( 84)T( 85)T( 86)T( 87)T( 88)T( 89)T( 90)T( 91)T( 92)T( 93)T( 94)T( 95) \ + T( 96)T( 97)T( 98)T( 99)T(100)T(101)T(102)T(103)T(104)T(105)T(106)T(107)T(108)T(109)T(110)T(111)T(112)T(113)T(114)T(115)T(116)T(117)T(118)T(119)T(120)T(121)T(122)T(123)T(124)T(125)T(126)T(127) \ + T(128)T(129)T(130)T(131)T(132)T(133)T(134)T(135)T(136)T(137)T(138)T(139)T(140)T(141)T(142)T(143)T(144)T(145)T(146)T(147)T(148)T(149)T(150)T(151)T(152)T(153)T(154)T(155)T(156)T(157)T(158)T(159) \ + T(160)T(161)T(162)T(163)T(164)T(165)T(166)T(167)T(168)T(169)T(170)T(171)T(172)T(173)T(174)T(175)T(176)T(177)T(178)T(179)T(180)T(181)T(182)T(183)T(184)T(185)T(186)T(187)T(188)T(189)T(190)T(191) \ + T(192)T(193)T(194)T(195)T(196)T(197)T(198)T(199)T(200)T(201)T(202)T(203)T(204)T(205)T(206)T(207)T(208)T(209)T(210)T(211)T(212)T(213)T(214)T(215)T(216)T(217)T(218)T(219)T(220)T(221)T(222)T(223) \ + T(224)T(225)T(226)T(227)T(228)T(229)T(230)T(231)T(232)T(233)T(234)T(235)T(236)T(237)T(238)T(239)T(240)T(241)T(242)T(243)T(244)T(245)T(246)T(247)T(248)T(249)T(250)T(251)T(252)T(253)T(254)T(255) + +template +constexpr void valid_count(bool* valid, std::size_t& count) noexcept { +#define MAGIC_ENUM_V(O) \ + if constexpr ((I + O) < Size) { \ + if constexpr (is_valid(I + O)>()) { \ + valid[I + O] = true; \ + ++count; \ + } \ + } + + MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_V) + + if constexpr ((I + 256) < Size) { + valid_count(valid, count); + } +#undef MAGIC_ENUM_V +} + +template +struct valid_count_t { + std::size_t count = 0; + bool valid[N] = {}; +}; + +template +constexpr auto valid_count() noexcept { + valid_count_t vc; + valid_count(vc.valid, vc.count); + return vc; +} + +template +constexpr auto values() noexcept { + constexpr auto vc = valid_count(); + + if constexpr (vc.count > 0) { +#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR) + std::array values = {}; +#else + E values[vc.count] = {}; +#endif + for (std::size_t i = 0, v = 0; v < vc.count; ++i) { + if (vc.valid[i]) { + values[v++] = value(i); + } + } +#if defined(MAGIC_ENUM_ARRAY_CONSTEXPR) + return values; +#else + return to_array(values, std::make_index_sequence{}); +#endif + } else { + return std::array{}; + } +} + +template > +constexpr auto values() noexcept { + constexpr auto min = reflected_min(); + constexpr auto max = reflected_max(); + constexpr auto range_size = max - min + 1; + static_assert(range_size > 0, "magic_enum::enum_range requires valid size."); + static_assert(range_size < (std::numeric_limits::max)(), "magic_enum::enum_range requires valid size."); + + return values(); +} + +template > +constexpr enum_subtype subtype(std::true_type) noexcept { + if constexpr (std::is_same_v) { // bool special case + return enum_subtype::common; + } else if constexpr (has_is_flags::value) { + return customize::enum_range::is_flags ? enum_subtype::flags : enum_subtype::common; + } else { +#if defined(MAGIC_ENUM_AUTO_IS_FLAGS) + constexpr auto flags_values = values(); + constexpr auto default_values = values(); + if (flags_values.size() == 0 || default_values.size() > flags_values.size()) { + return enum_subtype::common; + } + for (std::size_t i = 0; i < default_values.size(); ++i) { + const auto v = static_cast(default_values[i]); + if (v != 0 && (v & (v - 1)) != 0) { + return enum_subtype::common; + } + } + return enum_subtype::flags; +#else + return enum_subtype::common; +#endif + } +} + +template +constexpr enum_subtype subtype(std::false_type) noexcept { + // For non-enum type return default common subtype. + return enum_subtype::common; +} + +template > +inline constexpr auto subtype_v = subtype(std::is_enum{}); + +template +inline constexpr auto values_v = values(); + +template > +using values_t = decltype((values_v)); + +template +inline constexpr auto count_v = values_v.size(); + +template > +inline constexpr auto min_v = (count_v > 0) ? static_cast(values_v.front()) : U{0}; + +template > +inline constexpr auto max_v = (count_v > 0) ? static_cast(values_v.back()) : U{0}; + +template +constexpr auto names(std::index_sequence) noexcept { + constexpr auto names = std::array{{enum_name_v[I]>...}}; + return names; +} + +template +inline constexpr auto names_v = names(std::make_index_sequence>{}); + +template > +using names_t = decltype((names_v)); + +template +constexpr auto entries(std::index_sequence) noexcept { + constexpr auto entries = std::array, sizeof...(I)>{{{values_v[I], enum_name_v[I]>}...}}; + return entries; +} + +template +inline constexpr auto entries_v = entries(std::make_index_sequence>{}); + +template > +using entries_t = decltype((entries_v)); + +template > +constexpr bool is_sparse() noexcept { + if constexpr (count_v == 0) { + return false; + } else if constexpr (std::is_same_v) { // bool special case + return false; + } else { + constexpr auto max = (S == enum_subtype::flags) ? log2(max_v) : max_v; + constexpr auto min = (S == enum_subtype::flags) ? log2(min_v) : min_v; + constexpr auto range_size = max - min + 1; + + return range_size != count_v; + } +} + +template > +inline constexpr bool is_sparse_v = is_sparse(); + +template > +constexpr U values_ors() noexcept { + static_assert(S == enum_subtype::flags, "magic_enum::detail::values_ors requires valid subtype."); + + auto ors = U{0}; + for (std::size_t i = 0; i < count_v; ++i) { + ors |= static_cast(values_v[i]); + } + + return ors; +} + +template +struct enable_if_enum {}; + +template +struct enable_if_enum { + using type = R; + static_assert(supported::value, "magic_enum unsupported compiler (https://github.com/Neargye/magic_enum#compiler-compatibility)."); +}; + +template , typename D = std::decay_t> +using enable_if_t = typename enable_if_enum && std::is_invocable_r_v, R>::type; + +template >, int> = 0> +using enum_concept = T; + +template > +struct is_scoped_enum : std::false_type {}; + +template +struct is_scoped_enum : std::bool_constant>> {}; + +template > +struct is_unscoped_enum : std::false_type {}; + +template +struct is_unscoped_enum : std::bool_constant>> {}; + +template >> +struct underlying_type {}; + +template +struct underlying_type : std::underlying_type> {}; + +#if defined(MAGIC_ENUM_ENABLE_HASH) || defined(MAGIC_ENUM_ENABLE_HASH_SWITCH) + +template +struct constexpr_hash_t; + +template +struct constexpr_hash_t>> { + constexpr auto operator()(Value value) const noexcept { + using U = typename underlying_type::type; + if constexpr (std::is_same_v) { // bool special case + return static_cast(value); + } else { + return static_cast(value); + } + } + using secondary_hash = constexpr_hash_t; +}; + +template +struct constexpr_hash_t>> { + static constexpr std::uint32_t crc_table[256] { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, + 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, + 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, + 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, + 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, + 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, + 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, + 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, + 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, + 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, + 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, + 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, + 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, + 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, + 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, + 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, + 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, + 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, + 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, + 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, + 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, + 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, + 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, + 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, + 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, + 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL + }; + constexpr std::uint32_t operator()(string_view value) const noexcept { + auto crc = static_cast(0xffffffffL); + for (const auto c : value) { + crc = (crc >> 8) ^ crc_table[(crc ^ static_cast(c)) & 0xff]; + } + return crc ^ 0xffffffffL; + } + + struct secondary_hash { + constexpr std::uint32_t operator()(string_view value) const noexcept { + auto acc = static_cast(2166136261ULL); + for (const auto c : value) { + acc = ((acc ^ static_cast(c)) * static_cast(16777619ULL)) & (std::numeric_limits::max)(); + } + return static_cast(acc); + } + }; +}; + +template +inline constexpr Hash hash_v{}; + +template +constexpr auto calculate_cases(std::size_t Page) noexcept { + constexpr std::array values = *GlobValues; + constexpr std::size_t size = values.size(); + + using switch_t = std::invoke_result_t; + static_assert(std::is_integral_v && !std::is_same_v); + const std::size_t values_to = (std::min)(static_cast(256), size - Page); + + std::array result{}; + auto fill = result.begin(); + { + auto first = values.begin() + static_cast(Page); + auto last = values.begin() + static_cast(Page + values_to); + while (first != last) { + *fill++ = hash_v(*first++); + } + } + + // dead cases, try to avoid case collisions + for (switch_t last_value = result[values_to - 1]; fill != result.end() && last_value != (std::numeric_limits::max)(); *fill++ = ++last_value) { + } + + { + auto it = result.begin(); + auto last_value = (std::numeric_limits::min)(); + for (; fill != result.end(); *fill++ = last_value++) { + while (last_value == *it) { + ++last_value, ++it; + } + } + } + + return result; +} + +template +constexpr R invoke_r(F&& f, Args&&... args) noexcept(std::is_nothrow_invocable_r_v) { + if constexpr (std::is_void_v) { + std::forward(f)(std::forward(args)...); + } else { + return static_cast(std::forward(f)(std::forward(args)...)); + } +} + +enum class case_call_t { + index, + value +}; + +template +inline constexpr auto default_result_type_lambda = []() noexcept(std::is_nothrow_default_constructible_v) { return T{}; }; + +template <> +inline constexpr auto default_result_type_lambda = []() noexcept {}; + +template +constexpr bool has_duplicate() noexcept { + using value_t = std::decay_t; + using hash_value_t = std::invoke_result_t; + std::arraysize()> hashes{}; + std::size_t size = 0; + for (auto elem : *Arr) { + hashes[size] = hash_v(elem); + for (auto i = size++; i > 0; --i) { + if (hashes[i] < hashes[i - 1]) { + auto tmp = hashes[i]; + hashes[i] = hashes[i - 1]; + hashes[i - 1] = tmp; + } else if (hashes[i] == hashes[i - 1]) { + return false; + } else { + break; + } + } + } + return true; +} + +#define MAGIC_ENUM_CASE(val) \ + case cases[val]: \ + if constexpr ((val) + Page < size) { \ + if (!pred(values[val + Page], searched)) { \ + break; \ + } \ + if constexpr (CallValue == case_call_t::index) { \ + if constexpr (std::is_invocable_r_v>) { \ + return detail::invoke_r(std::forward(lambda), std::integral_constant{}); \ + } else if constexpr (std::is_invocable_v>) { \ + MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \ + } \ + } else if constexpr (CallValue == case_call_t::value) { \ + if constexpr (std::is_invocable_r_v>) { \ + return detail::invoke_r(std::forward(lambda), enum_constant{}); \ + } else if constexpr (std::is_invocable_r_v>) { \ + MAGIC_ENUM_ASSERT(false && "magic_enum::detail::constexpr_switch wrong result type."); \ + } \ + } \ + break; \ + } else [[fallthrough]]; + +template ::value_type>, + typename BinaryPredicate = std::equal_to<>, + typename Lambda, + typename ResultGetterType> +constexpr decltype(auto) constexpr_switch( + Lambda&& lambda, + typename std::decay_t::value_type searched, + ResultGetterType&& def, + BinaryPredicate&& pred = {}) { + using result_t = std::invoke_result_t; + using hash_t = std::conditional_t(), Hash, typename Hash::secondary_hash>; + static_assert(has_duplicate(), "magic_enum::detail::constexpr_switch duplicated hash found, please report it: https://github.com/Neargye/magic_enum/issues."); + constexpr std::array values = *GlobValues; + constexpr std::size_t size = values.size(); + constexpr std::array cases = calculate_cases(Page); + + switch (hash_v(searched)) { + MAGIC_ENUM_FOR_EACH_256(MAGIC_ENUM_CASE) + default: + if constexpr (size > 256 + Page) { + return constexpr_switch(std::forward(lambda), searched, std::forward(def)); + } + break; + } + return def(); +} + +#undef MAGIC_ENUM_CASE + +#endif + +} // namespace magic_enum::detail + +// Checks is magic_enum supported compiler. +inline constexpr bool is_magic_enum_supported = detail::supported::value; + +template +using Enum = detail::enum_concept; + +// Checks whether T is an Unscoped enumeration type. +// Provides the member constant value which is equal to true, if T is an [Unscoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Unscoped_enumeration) type. Otherwise, value is equal to false. +template +struct is_unscoped_enum : detail::is_unscoped_enum {}; + +template +inline constexpr bool is_unscoped_enum_v = is_unscoped_enum::value; + +// Checks whether T is an Scoped enumeration type. +// Provides the member constant value which is equal to true, if T is an [Scoped enumeration](https://en.cppreference.com/w/cpp/language/enum#Scoped_enumerations) type. Otherwise, value is equal to false. +template +struct is_scoped_enum : detail::is_scoped_enum {}; + +template +inline constexpr bool is_scoped_enum_v = is_scoped_enum::value; + +// If T is a complete enumeration type, provides a member typedef type that names the underlying type of T. +// Otherwise, if T is not an enumeration type, there is no member type. Otherwise (T is an incomplete enumeration type), the program is ill-formed. +template +struct underlying_type : detail::underlying_type {}; + +template +using underlying_type_t = typename underlying_type::type; + +template +using enum_constant = detail::enum_constant; + +// Returns type name of enum. +template +[[nodiscard]] constexpr auto enum_type_name() noexcept -> detail::enable_if_t { + constexpr string_view name = detail::type_name_v>; + static_assert(!name.empty(), "magic_enum::enum_type_name enum type does not have a name."); + + return name; +} + +// Returns number of enum values. +template > +[[nodiscard]] constexpr auto enum_count() noexcept -> detail::enable_if_t { + return detail::count_v, S>; +} + +// Returns enum value at specified index. +// No bounds checking is performed: the behavior is undefined if index >= number of enum values. +template > +[[nodiscard]] constexpr auto enum_value(std::size_t index) noexcept -> detail::enable_if_t> { + using D = std::decay_t; + + if constexpr (detail::is_sparse_v) { + return MAGIC_ENUM_ASSERT(index < detail::count_v), detail::values_v[index]; + } else { + constexpr auto min = (S == detail::enum_subtype::flags) ? detail::log2(detail::min_v) : detail::min_v; + + return MAGIC_ENUM_ASSERT(index < detail::count_v), detail::value(index); + } +} + +// Returns enum value at specified index. +template > +[[nodiscard]] constexpr auto enum_value() noexcept -> detail::enable_if_t> { + using D = std::decay_t; + static_assert(I < detail::count_v, "magic_enum::enum_value out of range."); + + return enum_value(I); +} + +// Returns std::array with enum values, sorted by enum value. +template > +[[nodiscard]] constexpr auto enum_values() noexcept -> detail::enable_if_t> { + return detail::values_v, S>; +} + +// Returns integer value from enum value. +template +[[nodiscard]] constexpr auto enum_integer(E value) noexcept -> detail::enable_if_t> { + return static_cast>(value); +} + +// Returns underlying value from enum value. +template +[[nodiscard]] constexpr auto enum_underlying(E value) noexcept -> detail::enable_if_t> { + return static_cast>(value); +} + +// Obtains index in enum values from enum value. +// Returns optional with index. +template > +[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t> { + using D = std::decay_t; + using U = underlying_type_t; + + if constexpr (detail::count_v == 0) { + static_cast(value); + return {}; // Empty enum. + } else if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { +#if defined(MAGIC_ENUM_ENABLE_HASH) + return detail::constexpr_switch<&detail::values_v, detail::case_call_t::index>( + [](std::size_t i) { return optional{i}; }, + value, + detail::default_result_type_lambda>); +#else + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (enum_value(i) == value) { + return i; + } + } + return {}; // Invalid value or out of range. +#endif + } else { + const auto v = static_cast(value); + if (v >= detail::min_v && v <= detail::max_v) { + return static_cast(v - detail::min_v); + } + return {}; // Invalid value or out of range. + } +} + +// Obtains index in enum values from enum value. +// Returns optional with index. +template +[[nodiscard]] constexpr auto enum_index(E value) noexcept -> detail::enable_if_t> { + using D = std::decay_t; + + return enum_index(value); +} + +// Obtains index in enum values from static storage enum variable. +template >> +[[nodiscard]] constexpr auto enum_index() noexcept -> detail::enable_if_t { + constexpr auto index = enum_index, S>(V); + static_assert(index, "magic_enum::enum_index enum value does not have a index."); + + return *index; +} + +// Returns name from static storage enum variable. +// This version is much lighter on the compile times and is not restricted to the enum_range limitation. +template +[[nodiscard]] constexpr auto enum_name() noexcept -> detail::enable_if_t { + constexpr string_view name = detail::enum_name_v, V>; + static_assert(!name.empty(), "magic_enum::enum_name enum value does not have a name."); + + return name; +} + +// Returns name from enum value. +// If enum value does not have name or value out of range, returns empty string. +template > +[[nodiscard]] constexpr auto enum_name(E value) noexcept -> detail::enable_if_t { + using D = std::decay_t; + + if (const auto i = enum_index(value)) { + return detail::names_v[*i]; + } + return {}; +} + +// Returns name from enum value. +// If enum value does not have name or value out of range, returns empty string. +template +[[nodiscard]] constexpr auto enum_name(E value) -> detail::enable_if_t { + using D = std::decay_t; + + return enum_name(value); +} + +// Returns std::array with names, sorted by enum value. +template > +[[nodiscard]] constexpr auto enum_names() noexcept -> detail::enable_if_t> { + return detail::names_v, S>; +} + +// Returns std::array with pairs (value, name), sorted by enum value. +template > +[[nodiscard]] constexpr auto enum_entries() noexcept -> detail::enable_if_t> { + return detail::entries_v, S>; +} + +// Allows you to write magic_enum::enum_cast("bar", magic_enum::case_insensitive); +inline constexpr auto case_insensitive = detail::case_insensitive<>{}; + +// Obtains enum value from integer value. +// Returns optional with enum value. +template > +[[nodiscard]] constexpr auto enum_cast(underlying_type_t value) noexcept -> detail::enable_if_t>> { + using D = std::decay_t; + + if constexpr (detail::count_v == 0) { + static_cast(value); + return {}; // Empty enum. + } else { + if constexpr (detail::is_sparse_v || (S == detail::enum_subtype::flags)) { +#if defined(MAGIC_ENUM_ENABLE_HASH) + return detail::constexpr_switch<&detail::values_v, detail::case_call_t::value>( + [](D v) { return optional{v}; }, + static_cast(value), + detail::default_result_type_lambda>); +#else + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (value == static_cast>(enum_value(i))) { + return static_cast(value); + } + } + return {}; // Invalid value or out of range. +#endif + } else { + if (value >= detail::min_v && value <= detail::max_v) { + return static_cast(value); + } + return {}; // Invalid value or out of range. + } + } +} + +// Obtains enum value from name. +// Returns optional with enum value. +template , typename BinaryPredicate = std::equal_to<>> +[[nodiscard]] constexpr auto enum_cast(string_view value, [[maybe_unused]] BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t>, BinaryPredicate> { + using D = std::decay_t; + + if constexpr (detail::count_v == 0) { + static_cast(value); + return {}; // Empty enum. +#if defined(MAGIC_ENUM_ENABLE_HASH) + } else if constexpr (detail::is_default_predicate()) { + return detail::constexpr_switch<&detail::names_v, detail::case_call_t::index>( + [](std::size_t i) { return optional{detail::values_v[i]}; }, + value, + detail::default_result_type_lambda>, + [&p](string_view lhs, string_view rhs) { return detail::cmp_equal(lhs, rhs, p); }); +#endif + } else { + for (std::size_t i = 0; i < detail::count_v; ++i) { + if (detail::cmp_equal(value, detail::names_v[i], p)) { + return enum_value(i); + } + } + return {}; // Invalid value or out of range. + } +} + +// Checks whether enum contains value with such value. +template > +[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t { + using D = std::decay_t; + using U = underlying_type_t; + + return static_cast(enum_cast(static_cast(value))); +} + +// Checks whether enum contains value with such value. +template +[[nodiscard]] constexpr auto enum_contains(E value) noexcept -> detail::enable_if_t { + using D = std::decay_t; + using U = underlying_type_t; + + return static_cast(enum_cast(static_cast(value))); +} + +// Checks whether enum contains value with such integer value. +template > +[[nodiscard]] constexpr auto enum_contains(underlying_type_t value) noexcept -> detail::enable_if_t { + using D = std::decay_t; + + return static_cast(enum_cast(value)); +} + +// Checks whether enum contains enumerator with such name. +template , typename BinaryPredicate = std::equal_to<>> +[[nodiscard]] constexpr auto enum_contains(string_view value, BinaryPredicate p = {}) noexcept(detail::is_nothrow_invocable()) -> detail::enable_if_t { + using D = std::decay_t; + + return static_cast(enum_cast(value, std::move(p))); +} + +template +inline constexpr auto as_flags = AsFlags ? detail::enum_subtype::flags : detail::enum_subtype::common; + +template +inline constexpr auto as_common = AsFlags ? detail::enum_subtype::common : detail::enum_subtype::flags; + +namespace bitwise_operators { + +template = 0> +constexpr E operator~(E rhs) noexcept { + return static_cast(~static_cast>(rhs)); +} + +template = 0> +constexpr E operator|(E lhs, E rhs) noexcept { + return static_cast(static_cast>(lhs) | static_cast>(rhs)); +} + +template = 0> +constexpr E operator&(E lhs, E rhs) noexcept { + return static_cast(static_cast>(lhs) & static_cast>(rhs)); +} + +template = 0> +constexpr E operator^(E lhs, E rhs) noexcept { + return static_cast(static_cast>(lhs) ^ static_cast>(rhs)); +} + +template = 0> +constexpr E& operator|=(E& lhs, E rhs) noexcept { + return lhs = (lhs | rhs); +} + +template = 0> +constexpr E& operator&=(E& lhs, E rhs) noexcept { + return lhs = (lhs & rhs); +} + +template = 0> +constexpr E& operator^=(E& lhs, E rhs) noexcept { + return lhs = (lhs ^ rhs); +} + +} // namespace magic_enum::bitwise_operators + +} // namespace magic_enum + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER) +# pragma warning(pop) +#endif + +#undef MAGIC_ENUM_GET_ENUM_NAME_BUILTIN +#undef MAGIC_ENUM_GET_TYPE_NAME_BUILTIN +#undef MAGIC_ENUM_VS_2017_WORKAROUND +#undef MAGIC_ENUM_ARRAY_CONSTEXPR +#undef MAGIC_ENUM_FOR_EACH_256 + +#endif // NEARGYE_MAGIC_ENUM_HPP diff --git a/meson.build b/meson.build index 7818836..9920cdb 100644 --- a/meson.build +++ b/meson.build @@ -6,6 +6,9 @@ project( default_options : ['b_pie=true', 'cpp_std=c++17'] ) +# Here we read variables from platform-specific meson file +subdir('platform') + mmi_version = meson.project_version().split('.') mmi_prefix = get_option('prefix') mmi_prefix_bindir = join_paths(mmi_prefix, get_option('bindir')) @@ -13,9 +16,17 @@ mmi_prefix_libdir = join_paths(mmi_prefix, get_option('libdir')) mmi_prefix_plugindir = join_paths(mmi_prefix, get_option('datadir'), 'mmi', 'plugins') mmi_prefix_scriptdir = join_paths(mmi_prefix, get_option('datadir'), 'mmi', 'scripts') +mmi_extra_flags = ''.join(['-DMMI_INSTALL_PREFIX="', mmi_prefix, '"']) +add_global_arguments(mmi_extra_flags, language : ['c', 'cpp']) + pkgconfig = import('pkgconfig') subdir('capi') subdir('src') -subdir('plugins') subdir('tests') +subdir('plugins') + +foreach platform_specific_sub_directory : mmi_platform_specific_sub_directories + message('Platform Specific Sub Directory : ' + platform_specific_sub_directory) + subdir(platform_specific_sub_directory) +endforeach diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..6d1f29a --- /dev/null +++ b/meson_options.txt @@ -0,0 +1 @@ +option('platform_option', type : 'string', value : 'linux', description : 'An option for specifying target platform') diff --git a/packaging/mmi.spec b/packaging/mmi.spec index 84f31e4..2495414 100644 --- a/packaging/mmi.spec +++ b/packaging/mmi.spec @@ -1,5 +1,3 @@ -%define USE_GCOV 0 - Name: mmi Version: 2.0.1 Release: 0 @@ -18,18 +16,17 @@ BuildRequires: pkgconfig(glib-2.0) BuildRequires: pkgconfig(dlog) BuildRequires: pkgconfig(rpc-port) BuildRequires: pkgconfig(ecore) -BuildRequires: pkgconfig(capi-media-audio-io) -BuildRequires: pkgconfig(capi-media-sound-manager) -BuildRequires: pkgconfig(capi-media-camera) -BuildRequires: pkgconfig(libaurum) BuildRequires: pkgconfig(vconf) -BuildRequires: pkgconfig(json-glib-1.0) -BuildRequires: pkgconfig(capi-media-vision) -BuildRequires: pkgconfig(capi-media-image-util) -BuildRequires: pkgconfig(opencv) +BuildRequires: pkgconfig(libxml-2.0) + #Build dependencies for tests BuildRequires: pkgconfig(gmock) +%if 0%{?gcov:1} +BuildRequires: lcov +BuildRequires: zip +%endif + %description MMI(Multi-modal Interaction) Framework @@ -53,6 +50,13 @@ Requires: pkgconfig(rpc-port) %description devel Development package for MMI Framework +%if 0%{?gcov:1} +%package gcov +Summary: MMI Framework (gcov) +%description gcov +MMI Framework gcov objects +%endif + %package tests Summary: Testcases for MMI Framework Group: System/Libraries @@ -70,7 +74,7 @@ tidlc -s -l C -i tidl/mmi.tidl -o mmi_stub mv mmi_stub.* src/mmi-manager %build -%if "%{USE_GCOV}" == "1" +%if 0%{?gcov:1} CFLAGS+=" -fprofile-arcs -ftest-coverage -DTIZEN_TEST_GCOV" CXXFLAGS+=" -fprofile-arcs -ftest-coverage -DTIZEN_TEST_GCOV" LDFLAGS+=" -lgcov" @@ -81,17 +85,47 @@ meson setup --prefix=/usr \ --libdir %{_libdir} \ --datadir %{_datadir} \ builddir +meson configure -Dplatform_option=tizen builddir ninja -C builddir all %install DESTDIR=%{buildroot} ninja -C builddir install +%if 0%{?gcov:1} +builddir=$(basename $PWD) +gcno_obj_dir=%{buildroot}%{_datadir}/gcov/obj/%{name}/"$builddir" +mkdir -p "$gcno_obj_dir" +find ./builddir/tests/ -name '*.gcno' -exec rm {} \; +find ./builddir/plugins/ -name '*.gcno' -exec rm {} \; +find ./builddir/src/mmi-cli/ -name '*.gcno' -exec rm {} \; +find . -name '*proxy*.gcno' -exec rm {} \; +find . -name '*_stub*.gcno' -exec rm {} \; +find . -name '*tidl*.gcno' -exec rm {} \; +find . -name '*-port-instance*.gcno' -exec rm {} \; +find . -name 'mmi-data-gateway*.gcno' -exec rm {} \; +find . -name 'mmi-node-controller*.gcno' -exec rm {} \; +find . -name 'mmi-signal*.gcno' -exec rm {} \; +find . -name 'mmi-workflow-script*.gcno' -exec rm {} \; +find . -name 'mmi-plugin*.gcno' -exec rm {} \; +find . -name 'mmi-workflow-output-event*.gcno' -exec rm {} \; +find ./builddir/meson-private/ -name '*.gcno' -exec rm {} \; +find . -name '*.gcno' -exec cp --parents '{}' "$gcno_obj_dir" ';' +%endif + %check %if "%{_mmi_test_enable}" == "true" ninja -C builddir test +%if 0%{?gcov:1} +lcov -c --ignore-errors graph --no-external -q -d . -o gcov.info +genhtml gcov.info +%endif %endif -%post -p /sbin/ldconfig +%post +/sbin/ldconfig +echo %{_bindir}/mmi-manager +chsmack -e "System" %{_bindir}/mmi-manager + %postun -p /sbin/ldconfig %files @@ -108,7 +142,6 @@ ninja -C builddir test %license COPYING %{_datadir}/mmi/plugins/*.so* %{_datadir}/mmi/scripts/*.mws -%{_datadir}/face_recognition/* %files cli %manifest %{name}.manifest @@ -116,6 +149,7 @@ ninja -C builddir test %license COPYING %{_bindir}/mmi-cli %{_bindir}/mmi-cli-node-tester +#%{TZ_SYS_RO_SHARE}/mmi/configs/mmi-config.xml %files devel %manifest %{name}.manifest @@ -124,9 +158,13 @@ ninja -C builddir test %{_includedir}/mmi*.h %{_libdir}/pkgconfig/* +%if 0%{?gcov:1} +%files gcov +%{_datadir}/gcov/obj/* +%endif + %files tests %defattr(-,root,root,-) %license COPYING %{_bindir}/mmi-tests %{_bindir}/mmi-manager-tests - diff --git a/platform/linux/meson.build b/platform/linux/meson.build new file mode 100644 index 0000000..15842f3 --- /dev/null +++ b/platform/linux/meson.build @@ -0,0 +1,11 @@ +mmi_platform = 'linux' + +mmi_platform_specific_dependencies = ['ecore-ipc'] +mmi_platform_specific_client_files = ['mmi-ipc-ecore.cpp'] +mmi_platform_specific_manager_files = ['mmi-ipc-ecore.cpp'] +mmi_platform_specific_sub_directories = [] +mmi_platform_specific_include_directory = 'platform/linux' + +install_headers( + 'mmi-platform-config.h' + ) diff --git a/platform/linux/mmi-platform-config.h b/platform/linux/mmi-platform-config.h new file mode 100644 index 0000000..5c06d5c --- /dev/null +++ b/platform/linux/mmi-platform-config.h @@ -0,0 +1,63 @@ +#pragma once + +#include +#include + +#define EXPORT_API +static char *get_error_message(int err) { return "Unknown"; } + +#define MMI_DEFAULT_CONFIG "/usr/local/mmi/configs/mmi-config.xml" + +#define MMI_LOG(fmt, ...) \ + do { \ + printf("%s: %s(%d) > " fmt "\n", \ + strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__, \ + __func__, __LINE__, \ + ##__VA_ARGS__); \ + } \ + while (0); + +#ifndef _E +#define _E LOGE +#endif + +#ifndef _D +#define _D LOGD +#endif + +#ifndef _I +#define _I LOGI +#endif + +#ifndef _W +#define _W LOGW +#endif + +#ifndef LOGE +#define LOGE MMI_LOG +#endif + +#ifndef LOGD +#define LOGD MMI_LOG +#endif + +#ifndef LOGI +#define LOGI MMI_LOG +#endif + +#ifndef LOGW +#define LOGW MMI_LOG +#endif + +#define PLATFORM_ERROR_MMI -0x030F0000 + +#define PLATFORM_ERROR_NONE (0) +#define PLATFORM_ERROR_OUT_OF_MEMORY (-1) +#define PLATFORM_ERROR_IO_ERROR (-2) +#define PLATFORM_ERROR_INVALID_PARAMETER (-3) +#define PLATFORM_ERROR_OUT_OF_NETWORK (-4) +#define PLATFORM_ERROR_TIMED_OUT (-5) +#define PLATFORM_ERROR_PERMISSION_DENIED (-6) +#define PLATFORM_ERROR_NOT_SUPPORTED (-7) +#define PLATFORM_ERROR_OPERATION_FAILED (-8) +#define PLATFORM_ERROR_RESOURCE_BUSY (-9) diff --git a/platform/meson.build b/platform/meson.build new file mode 100644 index 0000000..409bafc --- /dev/null +++ b/platform/meson.build @@ -0,0 +1,2 @@ +mmi_platform_option = get_option('platform_option') +subdir(mmi_platform_option) diff --git a/platform/tizen/meson.build b/platform/tizen/meson.build new file mode 100644 index 0000000..9f08faf --- /dev/null +++ b/platform/tizen/meson.build @@ -0,0 +1,11 @@ +mmi_platform = 'tizen' + +mmi_platform_specific_dependencies = ['bundle', 'rpc-port', 'dlog', 'libtzplatform-config'] +mmi_platform_specific_client_files = ['mmi_proxy.c', 'mmi-ipc-tidl.cpp'] +mmi_platform_specific_manager_files = ['mmi_stub.c', 'mmi-ipc-tidl.cpp'] +mmi_platform_specific_sub_directories = [] +mmi_platform_specific_include_directory = 'platform/tizen' + +install_headers( + 'mmi-platform-config.h' + ) diff --git a/platform/tizen/mmi-platform-config.h b/platform/tizen/mmi-platform-config.h new file mode 100644 index 0000000..8c0bc9a --- /dev/null +++ b/platform/tizen/mmi-platform-config.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include + +#define MMI_DEFAULT_CONFIG tzplatform_mkpath(tzplatform_getid("TZ_SYS_RO_SHARE"), "/mmi/configs/mmi-config.xml") + +#define TIZEN_ERROR_MMI -0x030F0000 + +#define PLATFORM_ERROR_NONE (TIZEN_ERROR_NONE) +#define PLATFORM_ERROR_OUT_OF_MEMORY (TIZEN_ERROR_OUT_OF_MEMORY) +#define PLATFORM_ERROR_IO_ERROR (TIZEN_ERROR_IO_ERROR) +#define PLATFORM_ERROR_INVALID_PARAMETER (TIZEN_ERROR_INVALID_PARAMETER) +#define PLATFORM_ERROR_OUT_OF_NETWORK (TIZEN_ERROR_NETWORK_DOWN) +#define PLATFORM_ERROR_TIMED_OUT (TIZEN_ERROR_TIMED_OUT) +#define PLATFORM_ERROR_PERMISSION_DENIED (TIZEN_ERROR_PERMISSION_DENIED) +#define PLATFORM_ERROR_NOT_SUPPORTED (TIZEN_ERROR_NOT_SUPPORTED) +#define PLATFORM_ERROR_OPERATION_FAILED (TIZEN_ERROR_MMI | 0x01) +#define PLATFORM_ERROR_RESOURCE_BUSY (TIZEN_ERROR_MMI | 0x02) + +#ifndef _E +#define _E LOGE +#endif + +#ifndef _D +#define _D LOGD +#endif + +#ifndef _I +#define _I LOGI +#endif + +#ifndef _W +#define _W LOGW +#endif + diff --git a/plugins/meson.build b/plugins/meson.build index c7ea24c..bef0dc0 100644 --- a/plugins/meson.build +++ b/plugins/meson.build @@ -1,2 +1 @@ -subdir('nodes') subdir('workflows') diff --git a/plugins/nodes/camera/meson.build b/plugins/nodes/camera/meson.build deleted file mode 100644 index add475c..0000000 --- a/plugins/nodes/camera/meson.build +++ /dev/null @@ -1,27 +0,0 @@ -mmi_module_camera_library_srcs = [ - 'mmi-module-camera.cpp', - 'mmi-module-camera-preview.cpp', - 'mmi-module-camera-preview.h', - ] - -dlog_dep = dependency('dlog', method : 'pkg-config') -camera_dep = dependency('capi-media-camera', method : 'pkg-config') - -mmi_module_camera_deps = [ - mmi_declared_dep, - dlog_dep, - camera_dep, - ] - -mmi_module_camera_include_dirs = include_directories( - '.', - '../../../capi/', - ) - -mmi_module_camera_library = library('mmi_module_camera', - mmi_module_camera_library_srcs, - include_directories : [ mmi_module_camera_include_dirs ], - dependencies : [mmi_module_camera_deps], - install_dir : mmi_prefix_plugindir, - install : true - ) diff --git a/plugins/nodes/camera/mmi-module-camera-preview.cpp b/plugins/nodes/camera/mmi-module-camera-preview.cpp deleted file mode 100644 index bdc4a30..0000000 --- a/plugins/nodes/camera/mmi-module-camera-preview.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Copyright (c) 2023 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 -#include "mmi-module-camera-preview.h" - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MMI-MODULE-CAMERA" - -int Camera::frame_num = 0; - -Camera::Camera() -{ -} - -Camera::~Camera() -{ -} - -int Camera::initialize() -{ - if (CAMERA_ERROR_NONE != camera_create(CAMERA_DEVICE_CAMERA0, &m_camera)) { - _E("[Camera] Fail to create camera"); - return MMI_ERROR_OPERATION_FAILED; - } - - if (CAMERA_ERROR_NONE != camera_set_display(m_camera, CAMERA_DISPLAY_TYPE_NONE, NULL)){ - _E("[Camera] Fail to set display"); - return MMI_ERROR_OPERATION_FAILED; - } - - camera_set_preview_format(m_camera, CAMERA_PIXEL_FORMAT_I420); - camera_set_preview_resolution(m_camera, 640, 480); - camera_attr_set_preview_fps(m_camera, CAMERA_ATTR_FPS_15); - camera_set_state_changed_cb(m_camera, _camera_state_changed_cb, this); - camera_set_preview_cb(m_camera, _camera_preview_cb, this); - - return MMI_ERROR_NONE; -} - -int Camera::deinitialize() -{ - - camera_unset_preview_cb(m_camera); - - if (CAMERA_ERROR_NONE != camera_destroy(m_camera)) { - _E("[Camera] Fail to distroy camera"); - return MMI_ERROR_OPERATION_FAILED; - } - return MMI_ERROR_NONE; -} - -int Camera::start() -{ - int width = 0; - int height = 0; - camera_attr_fps_e fps; - - _D("Camera::start()"); - - if (CAMERA_ERROR_NONE != camera_start_preview(m_camera)) { - _E("[Camera] Fail to start preview"); - return MMI_ERROR_OPERATION_FAILED; - } - - camera_attr_get_preview_fps(m_camera, &fps); - camera_get_preview_resolution(m_camera, &width, &height); - - _I("camera info -> fps :%d, width : %d, height : %d", fps, width, height); - - return MMI_ERROR_NONE; -} - -int Camera::stop() -{ - _D("Camera::stop()"); - - if (CAMERA_ERROR_NONE != camera_stop_preview(m_camera)) { - _E("[Camera] Fail to stop preview"); - return MMI_ERROR_OPERATION_FAILED; - } - - return MMI_ERROR_NONE; -} - -void Camera::set_preview_callback(camera_data_callback callback) -{ - m_camera_callback = callback; -} - -void Camera::set_node_instance(mmi_node_instance_h node_instance) -{ - m_node_instance = node_instance; -} - -void Camera::_camera_preview_cb(camera_preview_data_s *frame, void *user_data) -{ - int size = 0; - unsigned long timestamp = 0; - unsigned char *pData = nullptr; - - Camera *camera = static_cast(user_data); - camera_attr_get_preview_frame_timestamp(camera->m_camera, ×tamp); - - switch (frame->format) { - case CAMERA_PIXEL_FORMAT_NV12: - _D("NV12 p[%p,%p], size[%u,%u]", frame->data.double_plane.y, frame->data.double_plane.uv, - frame->data.double_plane.y_size, frame->data.double_plane.uv_size); - pData = frame->data.double_plane.y; - size = frame->data.double_plane.y_size + frame->data.double_plane.uv_size; - - break; - case CAMERA_PIXEL_FORMAT_I420: - _D("I420 p[%p,%p,%p], size[%u,%u,%u]", frame->data.triple_plane.y, frame->data.triple_plane.u, frame->data.triple_plane.v, - frame->data.triple_plane.y_size, frame->data.triple_plane.u_size, frame->data.triple_plane.v_size); - pData = frame->data.triple_plane.y; - size = frame->data.triple_plane.y_size + frame->data.triple_plane.u_size + frame->data.triple_plane.v_size; - - break; - default: - _E("invalid format : %u", frame->format); - break; - - } - Camera::frame_num++; - - if (camera->m_camera_callback && (Camera::frame_num % 3 == 0) && pData) { - camera->m_camera_callback(pData, size, timestamp, camera->m_node_instance); - } -} - diff --git a/plugins/nodes/camera/mmi-module-camera-preview.h b/plugins/nodes/camera/mmi-module-camera-preview.h deleted file mode 100644 index 17ba9d1..0000000 --- a/plugins/nodes/camera/mmi-module-camera-preview.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2023 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. - * - */ - -#pragma once - -#include -#include - -#include -#include - -using camera_data_callback = std::function; - -class Camera { -public: - static int frame_num; - - Camera(); - ~Camera(); - - int initialize(); - int deinitialize(); - int start(); - int stop(); - - void set_preview_callback(camera_data_callback callback); - void set_node_instance(mmi_node_instance_h node_instance); - - static void _camera_state_changed_cb(camera_state_e previous, camera_state_e current, bool by_policy, void *user_data) - { - _D("camera state changed %d -> %d", previous, current); - } - - static void _camera_interrupted_cb(camera_policy_e policy, camera_state_e previous, camera_state_e current, - void *user_data) - { - _D("camera interrupted callback called[state %d -> %d, policy %d]", previous, current, policy); - } - -private: - camera_h m_camera{nullptr}; - camera_data_callback m_camera_callback{nullptr}; - mmi_node_instance_h m_node_instance{nullptr}; - static void _camera_preview_cb(camera_preview_data_s *frame, void *user_data); -}; diff --git a/plugins/nodes/camera/mmi-module-camera.cpp b/plugins/nodes/camera/mmi-module-camera.cpp deleted file mode 100644 index 9ecea3a..0000000 --- a/plugins/nodes/camera/mmi-module-camera.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include -#include -#include -#include - -#include -#include -#include -#include "mmi-module-camera-preview.h" - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MMI-MODULE-CAMERA" - -static std::map g_camera_map; - -void feed_preview_callback(void *data, size_t size, unsigned long timestamp, void *user_data) -{ - mmi_node_instance_h instance = (mmi_node_instance_h)user_data; - mmi_port_instance_h port_instance = nullptr; - mmi_data_h output_data = nullptr; - - mmi_node_instance_find_port(instance, MMI_PORT_TYPE_OUT, "VIDEO", &port_instance); - mmi_data_create_video(data, size, &output_data); - mmi_port_instance_generate_output(port_instance, output_data); - mmi_data_destroy(output_data); - _D("frame num : %d, timestamp : %lu", Camera::frame_num, timestamp); -} - -static int node_initialized_cb(mmi_node_instance_h instance) -{ - _D("[Camera] Node initialize callback is called for %p", instance); - - if (nullptr == instance) { - _E("[Camera] node instance is null"); - return MMI_ERROR_INVALID_PARAMETER; - } - Camera *camera = new(std::nothrow) Camera(); - if (nullptr == camera) { - _E("[ERROR] Failed to create instance"); - return MMI_ERROR_OUT_OF_MEMORY; - } - - camera->initialize(); - camera->set_node_instance(instance); - camera->set_preview_callback(feed_preview_callback); - g_camera_map.insert(std::pair(instance, camera)); - - return MMI_ERROR_NONE; -} - -static int node_deinitialized_cb(mmi_node_instance_h instance) -{ - _D("[Camera] Node deinitialize callback is called for %p", instance); - if (nullptr == instance) { - _E("[Camera] node instance is null"); - return MMI_ERROR_INVALID_PARAMETER; - } - - try { - Camera *camera = g_camera_map[instance]; - camera->deinitialize(); - g_camera_map.erase(instance); - delete camera; - } catch (std::out_of_range &e) { - _E("[Camera] failed to find recorder instance"); - return MMI_ERROR_INVALID_PARAMETER; - } - - return MMI_ERROR_NONE; -} - -static int node_attribute_set_cb(mmi_node_instance_h instance, mmi_attribute_h attribute) -{ - _D("Node attribute set callback is called for %p", instance); - - if (nullptr == instance) { - _E("[CAMERA] node instance is null"); - return MMI_ERROR_INVALID_PARAMETER; - } - - if (nullptr == attribute) { - _E("[Camera] attribute is null"); - return MMI_ERROR_INVALID_PARAMETER; - } - - // TODO: set attribute "UNFOCUSED_ONLY" - - return MMI_ERROR_NONE; -} - -static int node_activated_cb(mmi_node_instance_h instance) -{ - _D("[Camera] Node activate callback is called for %p", instance); - - if (nullptr == instance) { - _E("[Camera] node instance is null"); - return MMI_ERROR_INVALID_PARAMETER; - } - - try { - Camera *camera = g_camera_map[instance]; - camera->start(); - } catch (std::out_of_range &e) { - _E("[Camera] failed to find recorder instance"); - return MMI_ERROR_INVALID_PARAMETER; - } - - return MMI_ERROR_NONE; -} - -static int node_deactivated_cb(mmi_node_instance_h instance) -{ - _D("[Camera] Node deactivate callback is called for %p", instance); - - if (nullptr == instance) { - _E("[Camera] node instance is null"); - return MMI_ERROR_INVALID_PARAMETER; - } - - try { - Camera *camera = g_camera_map[instance]; - camera->stop(); - } catch (std::out_of_range &e) { - _E("[Camera] failed to find recorder instance"); - return MMI_ERROR_INVALID_PARAMETER; - } - - return MMI_ERROR_NONE; -} - -static int node_signal_received_cb(mmi_node_instance_h instance, mmi_signal_h signal) -{ - _D("Node signal received callback is called for %p", instance); - return MMI_ERROR_NONE; -} - -static int port_output_format_requested_cb(mmi_port_instance_h instance, const char *format) { - _D("Port output format request callback is called for %p", instance); - return MMI_ERROR_NONE; -} - -// TODO: It must be determined how to receive input data from the client -static int port_input_data_received_cb(mmi_port_instance_h instance, mmi_data_h data) { - _D("Port input data callback is called for %p", instance); - return MMI_ERROR_NONE; -} - -extern "C" { - - EXPORT_API void mmi_plugin_module_get_node_list() - { - mmi_node_callbacks node_callbacks { - node_initialized_cb, - node_deinitialized_cb, - node_attribute_set_cb, - node_activated_cb, - node_deactivated_cb, - node_signal_received_cb - }; - - mmi_port_callbacks camera_port_callbacks { - port_output_format_requested_cb, - port_input_data_received_cb - }; - - mmi_port_h camera_port = nullptr; - mmi_port_create(&camera_port); - mmi_port_set_name(camera_port, "VIDEO"); - mmi_port_set_type(camera_port, MMI_PORT_TYPE_OUT); - mmi_port_set_data_type(camera_port, MMI_DATA_TYPE_VIDEO); - mmi_port_set_callbacks(camera_port, camera_port_callbacks); - - mmi_node_h camera_node = nullptr; - mmi_standard_node_create_source(MMI_STANDARD_NODE_SOURCE_TYPE_CAMERA, &camera_node); - mmi_node_add_port(camera_node, camera_port); - mmi_node_set_callbacks(camera_node, node_callbacks); - - mmi_node_register(camera_node); - - mmi_node_destroy(camera_node); - } - -} // extern "C" diff --git a/plugins/nodes/face-recognition/data/recognizerInfo.json b/plugins/nodes/face-recognition/data/recognizerInfo.json deleted file mode 100644 index dc7ba76..0000000 --- a/plugins/nodes/face-recognition/data/recognizerInfo.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "maxFaceCount": 2, - "faceInfo": [ - { - "faceId": "test4", - "faceName": "test4", - "enrollFilePath": "/usr/share/face_recognition/enroll/soo_1.jpg" - }, - { - "faceId": "test2", - "faceName": "test2", - "enrollFilePath": "/usr/share/face_recognition/enroll/soo_4.jpg" - } - ] -} \ No newline at end of file diff --git a/plugins/nodes/face-recognition/meson.build b/plugins/nodes/face-recognition/meson.build deleted file mode 100644 index 6e48678..0000000 --- a/plugins/nodes/face-recognition/meson.build +++ /dev/null @@ -1,37 +0,0 @@ -mmi_module_fr_library_srcs = [ - 'mmi-module-fr.cpp', - 'mmi-module-fr-data-manager.h', - 'mmi-module-fr-data-manager.cpp' - ] - -dlog_dep = dependency('dlog', method : 'pkg-config') -ecore_dep = dependency('ecore', method : 'pkg-config') -json_dep = dependency('json-glib-1.0', method : 'pkg-config') -media_vision_dep = dependency('capi-media-vision', method : 'pkg-config') -image_util_dep = dependency('capi-media-image-util', method : 'pkg-config') -opencv_dep = dependency('opencv', method : 'pkg-config') - -mmi_module_fr_deps = [ - mmi_declared_dep, - dlog_dep, - ecore_dep, - json_dep, - media_vision_dep, - image_util_dep, - opencv_dep, - ] - -mmi_module_fr_include_dirs = include_directories( - '.', - '../../../capi/', - ) - -mmi_module_fr_library = library('mmi_module_fr', - mmi_module_fr_library_srcs, - include_directories : [ mmi_module_fr_include_dirs ], - dependencies : [mmi_module_fr_deps], - install_dir : mmi_prefix_plugindir, - install : true - ) - -install_data('data/recognizerInfo.json', install_dir : '/usr/share/face_recognition/') diff --git a/plugins/nodes/face-recognition/mmi-module-fr-data-manager.cpp b/plugins/nodes/face-recognition/mmi-module-fr-data-manager.cpp deleted file mode 100644 index 10b5f8c..0000000 --- a/plugins/nodes/face-recognition/mmi-module-fr-data-manager.cpp +++ /dev/null @@ -1,234 +0,0 @@ -/* - * Copyright (c) 2023 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. - * - */ - -// FIXME: temporary module for testing -// FIXME: remove this module after register/recognize fw/app is ready -#include -#include - -#include "mmi-module-fr-data-manager.h" - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MMI-MODULE-FACE-RECOGNITION" - -DataManager::DataManager() -{ - m_info_file_path = std::string("/usr/share/face_recognition/recognizerInfo.json"); - m_mutex = new(std::nothrow) std::mutex(); - if (nullptr == m_mutex) { - _E("[FR DATAMGR] Failed to create mutex"); - return; - } - load_info(); -} - -DataManager::~DataManager() -{ - delete m_mutex; - m_mutex = nullptr; -} - -void DataManager::load_info() -{ - _D("[FR DATAMGR] load info "); - std::lock_guard lock(*m_mutex); - - JsonParser *parser = nullptr; - parser = json_parser_new(); - if (nullptr == parser) { - _E("[FR DATAMGR] Failed to create json parser"); - return; - } - - GError *error = nullptr; - if (!json_parser_load_from_file(parser, m_info_file_path.c_str(), &error)) { - _E("[FR DATAMGR] Failed to load json file: %s", error->message); - g_error_free(error); - return; - } - - JsonObject *recognizer_info = json_node_get_object(json_parser_get_root(parser)); - if (nullptr == recognizer_info) { - _E("[FR DATAMGR] Failed to get root object"); - g_object_unref(parser); - parser = nullptr; - return; - } - - m_max_face_count = json_object_get_int_member(recognizer_info, "maxFaceCount"); - _D("[FR DATAMGR] max face count is %d", m_max_face_count); - - JsonArray *face_info = json_object_get_array_member(recognizer_info, "faceInfo"); - if (nullptr == face_info) { - _E("[FR DATAMGR] Failed to get faceInfo object"); - g_object_unref(parser); - parser = nullptr; - return; - } - - for (int i = 0; i < json_array_get_length(face_info); i++) { - JsonObject *face = json_array_get_object_element(face_info, i); - if (nullptr == face) { - _E("[FR DATAMGR] Failed to get face object"); - g_object_unref(parser); - parser = nullptr; - return; - } - - const gchar *id = json_object_get_string_member(face, "faceId"); - const gchar *name = json_object_get_string_member(face, "faceName"); - const gchar *file_path = json_object_get_string_member(face, "enrollFilePath"); - - FaceInfo info; - info.id = std::string(id); - info.name = std::string(name); - info.file_path = std::string(file_path); - _D("[FR DATAMGR] face info: id: %s, name: %s, file_path: %s", info.id.c_str(), info.name.c_str(), info.file_path.c_str()); - m_face_list.push_back(info); - } - - g_object_unref(parser); - parser = nullptr; -} - -void DataManager::save_info() -{ - _D("[FR DATAMGR] save info"); - std::lock_guard lock(*m_mutex); - JsonBuilder *builder = json_builder_new(); - - json_builder_begin_object(builder); - - json_builder_set_member_name(builder, "maxFaceCount"); - json_builder_add_int_value(builder, m_max_face_count); - - json_builder_set_member_name(builder, "faceInfo"); - - json_builder_begin_array(builder); - for (int i = 0; i < m_face_list.size(); i++) { - json_builder_begin_object(builder); - json_builder_set_member_name(builder, "faceId"); - json_builder_add_string_value(builder, m_face_list[i].id.c_str()); - json_builder_set_member_name(builder, "faceName"); - json_builder_add_string_value(builder, m_face_list[i].name.c_str()); - json_builder_set_member_name(builder, "enrollFilePath"); - json_builder_add_string_value(builder, m_face_list[i].file_path.c_str()); - json_builder_end_object(builder); - } - json_builder_end_array(builder); - - json_builder_end_object(builder); - - JsonGenerator *generator = json_generator_new(); - json_generator_set_root(generator, json_builder_get_root(builder)); - json_generator_set_pretty(generator, TRUE); - - // save file and check return value - gboolean ret = json_generator_to_file(generator, m_info_file_path.c_str(), NULL); - if (FALSE == ret) { - _E("[FR DATAMGR] Failed to save json file"); - } - - if (builder) { - g_object_unref(builder); - builder = nullptr; - } - if (generator) { - g_object_unref(generator); - generator = nullptr; - } -} - -void DataManager::add_face(FaceInfo info) -{ - _D("[FR DATAMGR] add face info"); - { - std::lock_guard lock(*m_mutex); - m_face_list.push_back(info); - for (auto &i : m_face_list) { - _D("[FR DATAMGR] face info: id: %s, name: %s, model: %s", i.id.c_str(), i.name.c_str(), i.file_path.c_str()); - } - } - - save_info(); -} - -void DataManager::delete_face(std::string id) -{ - _D("[FR DATAMGR] delete face info"); - { - std::lock_guard lock(*m_mutex); - for (int i = 0; i < m_face_list.size(); i++) { - if (m_face_list[i].id == id) { - m_face_list.erase(m_face_list.begin() + i); - break; - } - } - } - save_info(); -} - -void DataManager::update_face(FaceInfo info) -{ - _D("[FR DATAMGR] update face info"); - { - std::lock_guard lock(*m_mutex); - for (int i = 0; i < m_face_list.size(); i++) { - if (m_face_list[i].id == info.id) { - m_face_list[i].name = info.name; - m_face_list[i].file_path = info.file_path; - break; - } - } - } - - save_info(); -} - -int DataManager::get_face_count() -{ - _D("[FR DATAMGR] get face count"); - std::lock_guard lock(*m_mutex); - int count = m_face_list.size(); - return count; -} - -FaceInfo DataManager::get_face_info(std::string id) -{ - _D("[FR DATAMGR] get face info"); - std::lock_guard lock(*m_mutex); - FaceInfo info; - for (int i = 0; i < m_face_list.size(); i++) { - if (m_face_list[i].id == id) { - info = m_face_list[i]; - break; - } - } - - return info; -} - -std::vector DataManager::get_face_list() -{ - _D("[FR DATAMGR] get face list"); - std::lock_guard lock(*m_mutex); - - std::vector list = m_face_list; - return list; -} diff --git a/plugins/nodes/face-recognition/mmi-module-fr-data-manager.h b/plugins/nodes/face-recognition/mmi-module-fr-data-manager.h deleted file mode 100644 index 000de19..0000000 --- a/plugins/nodes/face-recognition/mmi-module-fr-data-manager.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2023 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. - * - */ - -#pragma once - -#include -#include -#include - -struct FaceInfo { - std::string id; - std::string name; - std::string file_path; -}; - -class DataManager { -private: - void load_info(); - void save_info(); - -public: - DataManager(); - ~DataManager(); - static DataManager& get_instance() { - static DataManager instance; - return instance; - } - - std::vector get_face_list(); - FaceInfo get_face_info(std::string id); - int get_face_count(); - void add_face(FaceInfo info); - void delete_face(std::string id); - void update_face(FaceInfo info); - -private: - static DataManager m_instance; - std::vector m_face_list; - int m_max_face_count{0}; - std::string m_info_file_path{}; - std::mutex* m_mutex{nullptr}; -}; diff --git a/plugins/nodes/face-recognition/mmi-module-fr.cpp b/plugins/nodes/face-recognition/mmi-module-fr.cpp deleted file mode 100644 index 0266f6a..0000000 --- a/plugins/nodes/face-recognition/mmi-module-fr.cpp +++ /dev/null @@ -1,595 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include "mv_face_recognition_internal.h" -#include - -#include -#include - -#include -#include -#include -#include - -#include "mmi-module-fr-data-manager.h" - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MMI-MODULE-FACE-RECOGNITION" - -#define FRAME_WIDTH 640 -#define FRAME_HEIGHT 480 - -static const char *INPUT_PORT_NAME_VIDEO = "VIDEO"; -static const char *OUTPUT_PORT_NAME_MATCHED_FACES = "MATCHED_FACES"; -static const char *OUTPUT_RESULT_ELEMENT_NODE = "fromNode"; -static const char *OUTPUT_RESULT_NODE_NAME = "FACE_RECOGNITION"; -static const char *OUTPUT_RESULT_ELEMENT_CANDIDATE = "recognizedCandidates"; - -static mv_face_recognition_h g_face_recog_h = nullptr; -static DataManager *g_data_manager = nullptr; - -struct _facedata_s -{ - unsigned char *id; - unsigned int width; - unsigned int height; - unsigned int channel; - unsigned int size; - unsigned char *data; -}; - -typedef struct _facedata_s facedata_s; -static std::map g_registered_faces_map; -static std::map g_input_port_to_instance_map; - -int register_face_from_file(const char *file_path, const char *file_name) -{ - unsigned char *data_buffer = NULL; - size_t buffer_size = 0; - unsigned int width = FRAME_WIDTH; - unsigned int height = FRAME_HEIGHT; - image_util_decode_h img_decoder = NULL; - image_util_image_h decoded_img = NULL; - mv_source_h mv_src = NULL; - image_util_colorspace_e colorspace; - - int ret = -1; - - /* Get image from filepath, Decode image and Fill the image data to mv_source handle */ - ret = image_util_decode_create(&img_decoder); - if (ret != IMAGE_UTIL_ERROR_NONE) { - _E("[FR] Fail to cretae image decoder"); - return MMI_ERROR_OUT_OF_MEMORY; - } - - ret = image_util_decode_set_input_path(img_decoder, file_path); - if (ret != IMAGE_UTIL_ERROR_NONE) { - _E("[FR] Fail to set input path"); - image_util_decode_destroy(img_decoder); - return MMI_ERROR_OPERATION_FAILED; - } - - ret = image_util_decode_set_colorspace(img_decoder, IMAGE_UTIL_COLORSPACE_RGB888); - if (ret != IMAGE_UTIL_ERROR_NONE) { - _E("[FR] Fail to image_util_decode_set_colorspace"); - image_util_decode_destroy(img_decoder); - return MMI_ERROR_OPERATION_FAILED; - } - - ret = image_util_decode_set_output_buffer(img_decoder, &data_buffer); - if (ret != IMAGE_UTIL_ERROR_NONE) { - _E("[FR] Fail to set output buffer"); - image_util_decode_destroy(img_decoder); - return MMI_ERROR_OPERATION_FAILED; - } - - ret = image_util_decode_run2(img_decoder, &decoded_img); - if (ret != IMAGE_UTIL_ERROR_NONE) { - _E("[FR] Fail to run decoder"); - image_util_decode_destroy(img_decoder); - return MMI_ERROR_OPERATION_FAILED; - } - - ret = image_util_get_image(decoded_img, &width, &height, &colorspace, &data_buffer, &buffer_size); - if (ret != IMAGE_UTIL_ERROR_NONE) { - _E("[FR] Fail to get image (%d)", ret); - image_util_decode_destroy(img_decoder); - image_util_destroy_image(decoded_img); - return MMI_ERROR_OPERATION_FAILED; - } - - ret = image_util_destroy_image(decoded_img); - if (ret != IMAGE_UTIL_ERROR_NONE) { - _E("[FR] Fail to destroy image (%d)", ret); - image_util_decode_destroy(img_decoder); - return MMI_ERROR_OPERATION_FAILED; - } - - ret = image_util_decode_destroy(img_decoder); - if (ret != IMAGE_UTIL_ERROR_NONE) { - _E("[FR] Fail to destroy decoder"); - return MMI_ERROR_OPERATION_FAILED; - } - - ret = mv_create_source(&mv_src); - if (ret != MEDIA_VISION_ERROR_NONE) { - _E("[FR] Fail to create mv source"); - return MMI_ERROR_OUT_OF_MEMORY; - } - ret = mv_source_fill_by_buffer(mv_src, data_buffer, (unsigned int)buffer_size, - (unsigned int)width, (unsigned int)height, MEDIA_VISION_COLORSPACE_RGB888); - if (ret != MEDIA_VISION_ERROR_NONE) { - free(data_buffer); - _E("[FR] Fail to fill mv source by buffer"); - mv_destroy_source(mv_src); - return MMI_ERROR_OPERATION_FAILED; - } - - ret = mv_face_recognition_register(g_face_recog_h, mv_src, file_name); - if (ret != MEDIA_VISION_ERROR_NONE) { - _E("Fail to register the detected face = %d", ret); - if (ret == MEDIA_VISION_ERROR_INVALID_PARAMETER) - _E("Fail to register the detected face = %d(MEDIA_VISION_ERROR_INVALID_PARAMETER)", ret); - else if (ret == MEDIA_VISION_ERROR_INVALID_OPERATION) - _E("Fail to register the detected face = %d(MEDIA_VISION_ERROR_INVALID_OPERATION)", ret); - else if (ret == MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT) - _E("Fail to register the detected face = %d(MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT)", ret); - else if (ret == MEDIA_VISION_ERROR_OUT_OF_MEMORY) - _E("Fail to register the detected face = %d(MEDIA_VISION_ERROR_OUT_OF_MEMORY)", ret); - else if (ret == MEDIA_VISION_ERROR_INTERNAL) - _E("Fail to register the detected face = %d(MEDIA_VISION_ERROR_INTERNAL)", ret); - - mv_destroy_source(mv_src); - - return MMI_ERROR_OPERATION_FAILED; - } - - mv_destroy_source(mv_src); - - return MMI_ERROR_NONE; -} - -int register_faces(void) -{ - std::vector face_list = g_data_manager->get_face_list(); - for (auto it = face_list.begin(); it != face_list.end(); it++) { - std::string face_id = it->id; - std::string face_name = it->name; - std::string face_file_path = it->file_path; - - register_face_from_file(face_file_path.c_str(), face_name.c_str()); - } - - return MMI_ERROR_NONE; -} - -int unregister_faces(void) -{ - int ret = -1; - std::vector face_list = g_data_manager->get_face_list(); - for (auto it = face_list.begin(); it != face_list.end(); it++) { - std::string face_name = it->name; - - ret = mv_face_recognition_unregister(g_face_recog_h, face_name.c_str()); - if (ret != MEDIA_VISION_ERROR_NONE) { - _E("Fail to unregister the detected face = %d", ret); - if (ret == MEDIA_VISION_ERROR_INVALID_PARAMETER) - _E("Fail to unregister the detected face = %d(MEDIA_VISION_ERROR_INVALID_PARAMETER)", ret); - else if (ret == MEDIA_VISION_ERROR_INVALID_OPERATION) - _E("Fail to unregister the detected face = %d(MEDIA_VISION_ERROR_INVALID_OPERATION)", ret); - else if (ret == MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT) - _E("Fail to unregister the detected face = %d(MEDIA_VISION_ERROR_NOT_SUPPORTED_FORMAT)", ret); - else if (ret == MEDIA_VISION_ERROR_OUT_OF_MEMORY) - _E("Fail to unregister the detected face = %d(MEDIA_VISION_ERROR_OUT_OF_MEMORY)", ret); - else if (ret == MEDIA_VISION_ERROR_INTERNAL) - _E("Fail to unregister the detected face = %d(MEDIA_VISION_ERROR_INTERNAL)", ret); - } - } - - _D("[FR] Finish to unregister faces"); - - return MMI_ERROR_NONE; -} - -static int node_initialized_cb(mmi_node_instance_h instance) -{ - _D("[FR] Node initialize callback is called for %p", instance); - if (nullptr == instance) { - _E("[FR] Instance is null. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - mmi_port_instance_h input_port = nullptr; - mmi_node_instance_find_port(instance, MMI_PORT_TYPE_IN, INPUT_PORT_NAME_VIDEO, &input_port); - if (nullptr == input_port) { - _E("[FR] Input port(video) is null. %p", input_port); - return MMI_ERROR_OPERATION_FAILED; - } - - g_input_port_to_instance_map[input_port] = instance; - _D("[FR] Input port is found. %p", input_port); - - try { - /* TODO: initialize face recognition */ - int ret = -1; - if (nullptr == g_face_recog_h) { - ret = mv_face_recognition_create(&g_face_recog_h); - if (MEDIA_VISION_ERROR_NONE != ret || nullptr == g_face_recog_h) { - _E("[FR] Fail to create face recognition handle"); - throw ret; - } - } - - ret = mv_face_recognition_prepare(g_face_recog_h); - if (MEDIA_VISION_ERROR_NONE != ret) { - _E("[FR] Fail to prepare face recognition handle"); - throw ret; - } - - /* register facial images */ - g_data_manager = new DataManager(); - ret = register_faces(); - } catch (std::bad_alloc &e) { - _E("[FR] Fail to allocate memory. %s", e.what()); - return MMI_ERROR_OUT_OF_MEMORY; - } catch (std::exception &e) { - _E("[FR] Fail to initialize face recognition. %s", e.what()); - return MMI_ERROR_OPERATION_FAILED; - } catch (int e) { - _E("[FR] Fail to initialize face recognition (%d)", e); - return MMI_ERROR_OPERATION_FAILED; - } - - return MMI_ERROR_NONE; -} - -static int node_deinitialized_cb(mmi_node_instance_h instance) -{ - _D("[FR] Node deinitialize callback is called for %p", instance); - if (nullptr == instance) { - _E("[FR] Instance is null. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - mmi_port_instance_h input_port = nullptr; - mmi_node_instance_find_port(instance, MMI_PORT_TYPE_IN, INPUT_PORT_NAME_VIDEO, &input_port); - if (nullptr == input_port) { - _E("[FR] Input port is null. %p", input_port); - return MMI_ERROR_OPERATION_FAILED; - } - - g_input_port_to_instance_map.erase(input_port); - - /* TODO: deinitialize face recognition */ - unregister_faces(); - - delete g_data_manager; - - if (nullptr != g_face_recog_h) { - mv_face_recognition_destroy(g_face_recog_h); - g_face_recog_h = nullptr; - } - - - return MMI_ERROR_NONE; -} - -static int node_attribute_set_cb(mmi_node_instance_h instance, mmi_attribute_h attribute) -{ - _D("[FR] Node attribute set callback is called for %p", instance); - return MMI_ERROR_NONE; -} - -static int node_activated_cb(mmi_node_instance_h instance) -{ - _D("[FR] Node activate callback is called for %p", instance); - if (nullptr == instance) { - _E("[FR] Instance is null. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - _D("[FR] Node activate callback is finished for %p", instance); - - - return MMI_ERROR_NONE; -} - -static int node_deactivated_cb(mmi_node_instance_h instance) -{ - _D("[FR] Node deactivate callback is called for %p", instance); - if (nullptr == instance) { - _E("[FR] Instance is null. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - _D("[FR] Node deactivate callback is finished for %p", instance); - - - return MMI_ERROR_NONE; -} - -static int node_signal_received_cb(mmi_node_instance_h instance, mmi_signal_h signal) -{ - _D("[FR] Node signal received callback is called for %p", instance); - return MMI_ERROR_NONE; -} - -static int port_output_format_requested_cb(mmi_port_instance_h instance, const char *format) -{ - _D("[FR] Port output format request callback is called for %p", instance); - return MMI_ERROR_NONE; -} - -static void set_float_to_struct(mmi_data_h struct_data, const char *name, float value) -{ - mmi_data_h data = nullptr; - mmi_data_create_float(value, &data); - mmi_data_set_struct_element(struct_data, name, data); -} - -static void set_text_to_struct(mmi_data_h struct_data, const char *name, const char *value) -{ - mmi_data_h data = nullptr; - mmi_data_create_text(value, &data); - mmi_data_set_struct_element(struct_data, name, data); -} - -static void add_array_element(mmi_data_h array_data, const char *id, const char *name, float confidence) -{ - mmi_data_h struct_data = nullptr; - mmi_data_create_struct(&struct_data); - if (nullptr == struct_data) { - _E("[FR] Fail to create struct data"); - return ; - } - - set_text_to_struct(struct_data, "id", id); - set_text_to_struct(struct_data, "name", name); - set_float_to_struct(struct_data, "confidence", confidence); - - mmi_data_add_array_element(array_data, struct_data); -} - -static int port_input_data_received_cb(mmi_port_instance_h instance, mmi_data_h data) -{ - /* Video input will be received. Recognize input data. */ - _D("[FR] Port input data callback is called for %p", instance); - - auto iterator = g_input_port_to_instance_map.find(instance); - if (g_input_port_to_instance_map.end() == iterator) { - _E("[FR] Fail to find proper node instance. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - auto node_instance = iterator->second; // a value of a map (first = a key of a map) - _D("[FR] Node instance is %p", node_instance); - - - const void *ptr = nullptr; - size_t len = 0; - int ret = 0; - - if (mmi_data_get_video(data, &ptr, &len) != MMI_ERROR_NONE) { - _E("[FR] Failed to get video data"); - return MMI_ERROR_INVALID_PARAMETER; - } - - _D("[FR] Video input data callback is called: %p %zu", node_instance, len); - - /* TODO: check video format... currently, use fixed values */ - /* current video format : I420 */ - unsigned char *data_buffer = NULL; - size_t buffer_size = 0; - image_util_image_h img_src = NULL; - image_util_image_h img_dst = NULL; - unsigned int width = FRAME_WIDTH; - unsigned int height = FRAME_HEIGHT; - transformation_h transform_h; - - ret = image_util_create_image(width, height, IMAGE_UTIL_COLORSPACE_I420, (const unsigned char *)ptr, len, &img_src); - if (ret != IMAGE_UTIL_ERROR_NONE) { - _E("[FR] Fail to create image (%d)", ret); - return MMI_ERROR_OUT_OF_MEMORY; - } - - ret = image_util_transform_create(&transform_h); - if (IMAGE_UTIL_ERROR_NONE != ret) { - _E("[FR] Fail to create image util transform handle"); - image_util_destroy_image(img_src); - return MMI_ERROR_OUT_OF_MEMORY; - } - - ret = image_util_transform_set_colorspace(transform_h, IMAGE_UTIL_COLORSPACE_RGB888); - if (ret != IMAGE_UTIL_ERROR_NONE) { - _E("[FR] Fail to set colorspace(%d)", ret); - image_util_destroy_image(img_src); - image_util_transform_destroy(transform_h); - return MMI_ERROR_OPERATION_FAILED; - } - - ret = image_util_transform_run2(transform_h, img_src, &img_dst); // img_src: YUYV image, img_dst: RGB888 image - if (ret != IMAGE_UTIL_ERROR_NONE) { - _E("[FR] Fail to transform image (%d)", ret); - image_util_destroy_image(img_src); - image_util_transform_destroy(transform_h); - return MMI_ERROR_OPERATION_FAILED; - } - - if (nullptr != transform_h) { - image_util_transform_destroy(transform_h); - transform_h = nullptr; - } - - /* get image data */ - image_util_colorspace_e colorspace; - unsigned int converted_width; - unsigned int converted_height; - unsigned char *image; // RGB888로 변환된 image - size_t image_size; - - ret = image_util_get_image(img_dst, &converted_width, &converted_height, &colorspace, &image, &image_size); - if (ret != IMAGE_UTIL_ERROR_NONE) { - _E("[FR] Fail to get image (%d)", ret); - image_util_destroy_image(img_src); - image_util_destroy_image(img_dst); - return MMI_ERROR_OPERATION_FAILED; - } - - ret = image_util_destroy_image(img_src); - if (ret != IMAGE_UTIL_ERROR_NONE) { - _E("[FR] Fail to destroy image(src) (%d)", ret); - return MMI_ERROR_OPERATION_FAILED; - } - ret = image_util_destroy_image(img_dst); - if (ret != IMAGE_UTIL_ERROR_NONE) { - _E("[FR] Fail to destroy image(dst) (%d)", ret); - return MMI_ERROR_OPERATION_FAILED; - } - - - mv_source_h source; - mv_colorspace_e src_color = MEDIA_VISION_COLORSPACE_RGB888; - - /* TODO: recognize face */ - ret = mv_create_source(&source); - if (MEDIA_VISION_ERROR_NONE != ret) { - _E("[FR ERROR] Fail to create source"); - return MMI_ERROR_OUT_OF_MEMORY; - } - - ret = mv_source_fill_by_buffer(source, (unsigned char *)image, image_size, converted_width, converted_height, src_color); - if (MEDIA_VISION_ERROR_NONE != ret) { - _E("[FR ERROR] Fail to fill source by buffer"); - mv_destroy_source(source); - return MMI_ERROR_OPERATION_FAILED; - } - - ret = mv_face_recognition_inference(g_face_recog_h, source); - if (MEDIA_VISION_ERROR_NONE != ret) { - _W("[FR ERROR] Fail to inference. ret(%d)", ret); - // mv_destroy_source(source); - // return MMI_ERROR_OPERATION_FAILED; - } - - const char *out_label = NULL; - ret = mv_face_recognition_get_label(g_face_recog_h, &out_label); - if (MEDIA_VISION_ERROR_NONE != ret) { - _E("[FR ERROR] Fail to get label"); - mv_destroy_source(source); - return MMI_ERROR_OPERATION_FAILED; - } else { - _I("[FR Result] recognized label(%s)", out_label); - } - - - /* TODO: generate result struct to output port */ - mmi_port_instance_h output_port_instance = nullptr; - mmi_node_instance_find_port(node_instance, MMI_PORT_TYPE_OUT, OUTPUT_PORT_NAME_MATCHED_FACES, &output_port_instance); - if (nullptr == output_port_instance) { - _E("[FR] Fail to get matched faces port from node. %p", node_instance); - return MMI_ERROR_OPERATION_FAILED; - } - - mmi_data_h result_data = nullptr; - mmi_data_create_struct(&result_data); - if (nullptr == result_data) { - _E("[FR] Fail to create result data"); - return MMI_ERROR_OUT_OF_MEMORY; - } - mmi_data_h elem_data = nullptr; - mmi_data_create_text(OUTPUT_RESULT_NODE_NAME, &elem_data); - mmi_data_set_struct_element(result_data, OUTPUT_RESULT_ELEMENT_NODE, elem_data); - - mmi_data_h result_array_data = nullptr; - mmi_data_create_array(&result_array_data); - if (nullptr == result_array_data) { - _E("[FR] Fail to create result array data"); - mmi_data_destroy(result_data); - return MMI_ERROR_OUT_OF_MEMORY; - } - - const float out_confidence = 0.0; - size_t num_of_confidences = 0; - const float *out_confidences = nullptr; - ret = mv_face_recognition_get_confidence(g_face_recog_h, &out_confidences, &num_of_confidences); - if (MEDIA_VISION_ERROR_NONE == ret) { - _D("[FR] Success to get confidences"); - const char *label; - for (int i = 0 ; i < num_of_confidences ; i++) { - mv_face_recognition_get_label_with_index(g_face_recog_h, i, &label); - _D("[%d] label(%s), confidence(%lf)", i, label, out_confidences[i] + 1.35f); - add_array_element(result_array_data, label, label, out_confidences[i] + 1.35f); - } - } - - mmi_data_set_struct_element(result_data, OUTPUT_RESULT_ELEMENT_CANDIDATE, result_array_data); - - // TODO: call "mmi_data_add_array_element()" ?? - - ret = mmi_port_instance_generate_output(output_port_instance, result_data); - if (MMI_ERROR_NONE != ret) { - _E("[FR] Fail to generate output. %d", ret); - } - - mmi_data_destroy(result_data); - mv_destroy_source(source); - - return MMI_ERROR_NONE; -} - -extern "C" { - - EXPORT_API void mmi_plugin_module_get_node_list() - { - mmi_node_callbacks node_callbacks { - node_initialized_cb, - node_deinitialized_cb, - node_attribute_set_cb, - node_activated_cb, - node_deactivated_cb, - node_signal_received_cb - }; - - mmi_port_callbacks video_port_callbacks { - port_output_format_requested_cb, - port_input_data_received_cb - }; - - mmi_port_h fr_video_port = nullptr; - mmi_port_create(&fr_video_port); - mmi_port_set_name(fr_video_port, INPUT_PORT_NAME_VIDEO); - mmi_port_set_type(fr_video_port, MMI_PORT_TYPE_IN); - mmi_port_set_data_type(fr_video_port, MMI_DATA_TYPE_VIDEO); - mmi_port_set_callbacks(fr_video_port, video_port_callbacks); - - mmi_port_h fr_matched_faces_port = nullptr; - mmi_port_create(&fr_matched_faces_port); - mmi_port_set_name(fr_matched_faces_port, OUTPUT_PORT_NAME_MATCHED_FACES); - mmi_port_set_type(fr_matched_faces_port, MMI_PORT_TYPE_OUT); - mmi_port_set_data_type(fr_matched_faces_port, MMI_DATA_TYPE_STRUCT); - // mmi_port_set_data_type(fr_matched_faces_port, MMI_DATA_TYPE_BOUNDING_BOX); // bounding box type? - - /* Callbacks for OUT ports are not needed for now */ - - mmi_node_h fr_node = nullptr; - mmi_standard_node_create_processor(MMI_STANDARD_NODE_PROCESSOR_TYPE_FACE_RECOGNITION, &fr_node); - mmi_node_add_port(fr_node, fr_video_port); - mmi_node_add_port(fr_node, fr_matched_faces_port); - mmi_node_set_callbacks(fr_node, node_callbacks); - mmi_node_register(fr_node); - - mmi_node_destroy(fr_node); - } - -} // extern "C" diff --git a/plugins/nodes/face-recognition/mv_face_recognition_internal.h b/plugins/nodes/face-recognition/mv_face_recognition_internal.h deleted file mode 100644 index bf0f362..0000000 --- a/plugins/nodes/face-recognition/mv_face_recognition_internal.h +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright (c) 2023 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. - */ - -#ifndef __TIZEN_MEDIAVISION_MV_FACE_RECOGNITION_INTERNAL_H__ -#define __TIZEN_MEDIAVISION_MV_FACE_RECOGNITION_INTERNAL_H__ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/** - * @internal - * @brief Gets confidences after a given face image is recognized. - * @details Use this function to get the confidences calling @ref mv_face_recognition_inference(). - * - * @since_tizen 8.0 - * - * @remarks The @a num_of_confidences and @a confidences must NOT be released using free() - * - * @param[in] handle The handle to the face recognition object. - * @param[out] confidences The array pointer to the confidence table which contains a confidence value of each class. - * This function returns memory pointer containing actual confidence values to @a confidences. - * And please note that @a confidences is valid only while handle is alive. - * @param[out] num_of_confidences A number of confidences to the classes registered. - * - * @return @c 0 on success, otherwise a negative error value - * @retval #MEDIA_VISION_ERROR_NONE Successful - * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #MEDIA_VISION_ERROR_INVALID_OPERATION Invalid operation - * - * @pre Request an inference by calling @ref mv_face_recognition_inference() - */ -int mv_face_recognition_get_confidence(mv_face_recognition_h handle, const float **confidences, - size_t *num_of_confidences); - -/** - * @internal - * @brief Gets a label name corresponding to a given index. - * @details Use this function to get the label name calling @ref mv_face_recognition_get_confidence(). - * - * @since_tizen 8.0 - * - * @remarks The @a num_of_confidences and @a confidences must NOT be released using free() - * - * @param[in] handle The handle to the face recognition object. - * @param[in] index A label index pointing to the offset of label file. - * @param[out] label The array pointer for the label name to be stored. - * This function returns memory pointer containing actual label string to @a label. - * So do not free @a label. And please note that @a label is valid only while handle is alive. - * - * @return @c 0 on success, otherwise a negative error value - * @retval #MEDIA_VISION_ERROR_NONE Successful - * @retval #MEDIA_VISION_ERROR_INVALID_PARAMETER Invalid parameter - * @retval #MEDIA_VISION_ERROR_INVALID_OPERATION Invalid operation - * - * @pre Request an inference by calling @ref mv_face_recognition_get_confidence() - */ -int mv_face_recognition_get_label_with_index(mv_face_recognition_h handle, const unsigned int index, - const char **label); - -/** - * @} - */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* __TIZEN_MEDIAVISION_MV_FACE_RECOGNITION_INTERNAL_H__ */ diff --git a/plugins/nodes/match/meson.build b/plugins/nodes/match/meson.build deleted file mode 100644 index 8331078..0000000 --- a/plugins/nodes/match/meson.build +++ /dev/null @@ -1,27 +0,0 @@ -mmi_module_match_library_srcs = [ - 'mmi-module-match.cpp', - 'mmi-module-match-text-candidates.h', - 'mmi-module-match-text-candidates.cpp', - ] - -dlog_dep = dependency('dlog', method : 'pkg-config') -ecore_dep = dependency('ecore', method : 'pkg-config') - -mmi_module_match_deps = [ - mmi_declared_dep, - dlog_dep, - ecore_dep, - ] - -mmi_module_match_include_dirs = include_directories( - '.', - '../../../capi/', - ) - -mmi_module_match_library = library('mmi_module_match', - mmi_module_match_library_srcs, - include_directories : [ mmi_module_match_include_dirs ], - dependencies : [mmi_module_match_deps], - install_dir : mmi_prefix_plugindir, - install : true - ) diff --git a/plugins/nodes/match/mmi-module-match-text-candidates.cpp b/plugins/nodes/match/mmi-module-match-text-candidates.cpp deleted file mode 100644 index db19c9c..0000000 --- a/plugins/nodes/match/mmi-module-match-text-candidates.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2023 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 - -#include - -#include "mmi-module-match-text-candidates.h" - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MMI-MODULE-MATCH" - - -using namespace std; - - -TextCandidates::TextCandidates() -{ - _I("[MATCH] Construct TextCandidates"); - m_candidates.clear(); -} - -TextCandidates::~TextCandidates() -{ - _I("[MATCH] Destruct TextCandidates"); - m_candidates.clear(); -} - -void TextCandidates::append_candidate(const char *candidate) -{ - if (nullptr == candidate) { - _W("[MATCH] Candidate text is null. Skip appending"); - return; - } - - _I("[MATCH] Append candidate(%s)", candidate); - m_candidates.push_back(candidate); - _D("[MATCH] The current number of candidates (%zu)", m_candidates.size()); -} - -bool TextCandidates::is_exist(const char *candidate) -{ - _I("[MATCH] Is candidate exist. candidate(%s)", candidate); - - auto element = std::find(m_candidates.begin(), m_candidates.end(), candidate); - if (element == m_candidates.end()) { - _E("[MATCH] There no matched command"); - return false; - } - - _I("[MATCH] Success To find candidate(%s)", candidate); - return true; -} - -void TextCandidates::clear_candidates() -{ - _I("[MATCH] Clear current candidates"); - m_candidates.clear(); -} - diff --git a/plugins/nodes/match/mmi-module-match-text-candidates.h b/plugins/nodes/match/mmi-module-match-text-candidates.h deleted file mode 100644 index a9b015f..0000000 --- a/plugins/nodes/match/mmi-module-match-text-candidates.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2023 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. - * - */ - - -#ifndef __MMI_MODULE_MATCH_TEXT_CANDIDATES_H__ -#define __MMI_MODULE_MATCH_TEXT_CANDIDATES_H__ - - -#include -#include - - -class TextCandidates { -public: - TextCandidates(); - ~TextCandidates(); - - void append_candidate(const char *candidate); - bool is_exist(const char *candidate); - void clear_candidates(); - -private: - std::vector m_candidates; -}; - -#endif /* __MMI_MODULE_MATCH_TEXT_CANDIDATES_H__ */ diff --git a/plugins/nodes/match/mmi-module-match.cpp b/plugins/nodes/match/mmi-module-match.cpp deleted file mode 100644 index bd76346..0000000 --- a/plugins/nodes/match/mmi-module-match.cpp +++ /dev/null @@ -1,302 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -#include "mmi-module-match-text-candidates.h" - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MMI-MODULE-MATCH" - - -static const char *INPUT_PORT_NAME_TEXT = "TEXT"; -static const char *OUTPUT_PORT_NAME_MATCHED_CANDIDATE = "MATCHED_CANDIDATE"; -static const char *OUTPUT_PORT_NAME_REJECTED = "REJECTED"; -static const char *ATTRIBUTE_NAME_CANDIDATES = "CANDIDATES"; - - -static std::map> g_node_to_text_candidates_map; -static std::map g_input_port_to_node_map; - - -static int node_initialized_cb(mmi_node_instance_h instance) -{ - _D("[MATCH] Node initialize callback is called for %p", instance); - if (nullptr == instance) { - _E("[MATCH] Instance is null. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - mmi_port_instance_h input_port = nullptr; - mmi_node_instance_find_port(instance, MMI_PORT_TYPE_IN, INPUT_PORT_NAME_TEXT, &input_port); - if (nullptr == input_port) { - _E("[MATCH] Fail to get port from node. %p", instance); - return MMI_ERROR_OPERATION_FAILED; - } - - g_input_port_to_node_map[input_port] = instance; - - try { - auto text_candidates = std::make_shared(); - g_node_to_text_candidates_map[instance] = text_candidates; - } catch (std::bad_alloc &e) { - _E("[MATCH] Fail to allocate memory for node instance. %p", instance); - return MMI_ERROR_OUT_OF_MEMORY; - } - - return MMI_ERROR_NONE; -} - -static bool is_node_instance_valid(mmi_node_instance_h instance) -{ - if (nullptr == instance) { - _E("[MATCH] Node instance is null %p", instance); - return false; - } - - auto iterator = g_node_to_text_candidates_map.find(instance); - if (iterator == g_node_to_text_candidates_map.end()) { - _E("[MATCH] No instance %p", instance); - return false; - } - - return true; -} - -static int node_deinitialized_cb(mmi_node_instance_h instance) -{ - _D("[MATCH] Node deinitialize callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[MATCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - mmi_port_instance_h input_port = nullptr; - mmi_node_instance_find_port(instance, MMI_PORT_TYPE_IN, INPUT_PORT_NAME_TEXT, &input_port); - if (nullptr == input_port) { - _E("[MATCH] Fail to get port from node. %p", instance); - return MMI_ERROR_OPERATION_FAILED; - } - - g_input_port_to_node_map.erase(input_port); - g_node_to_text_candidates_map.erase(instance); - - return MMI_ERROR_NONE; -} - -static int node_attribute_set_cb(mmi_node_instance_h instance, mmi_attribute_h attribute) -{ - _D("[MATCH] Node attribute set callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[MATCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - char *name = nullptr; - mmi_attribute_get_name(attribute, &name); - if (nullptr == name) { - _E("[MATCH] Fail to get attribute name"); - return MMI_ERROR_INVALID_PARAMETER; - } - - std::string attribute_name(name); - free(name); - name = nullptr; - - if (0 != attribute_name.compare(ATTRIBUTE_NAME_CANDIDATES)) { - _E("[MATCH] Attribute name is not same as expected one. (%s)", attribute_name.c_str()); - return MMI_ERROR_INVALID_PARAMETER; - } - - mmi_primitive_value_h value = nullptr; - mmi_primitive_value_type_e type = MMI_PRIMITIVE_VALUE_TYPE_INT; - mmi_attribute_get_value(attribute, &value); - mmi_primitive_value_get_type(value, &type); - if (MMI_PRIMITIVE_VALUE_TYPE_ARRAY != type) { - mmi_primitive_value_destroy(value); - _E("[MATCH] Invalid type of attribute : %d", type); - return MMI_ERROR_INVALID_PARAMETER; - } - - size_t count = 0; - mmi_primitive_value_get_array_count(value, &count); - - auto text_candidates = g_node_to_text_candidates_map[instance]; - text_candidates->clear_candidates(); - - for (size_t i = 0; i < count; i++) { - mmi_primitive_value_h element = nullptr; - mmi_primitive_value_get_array_element(value, i, &element); - - mmi_primitive_value_type_e element_type; - mmi_primitive_value_get_type(element, &element_type); - - if (MMI_PRIMITIVE_VALUE_TYPE_STRING != element_type) { - mmi_primitive_value_destroy(value); - _E("[MATCH] Invalid element type of attribute : %d", element_type); - return MMI_ERROR_INVALID_PARAMETER; - } - - const char *element_value = nullptr; - if (MMI_ERROR_NONE == mmi_primitive_value_get_string(element, &element_value)) { - _D("[MATCH] Attribute value : %zu %s", i, element_value); - text_candidates->append_candidate(element_value); - } - } - mmi_primitive_value_destroy(value); - - return MMI_ERROR_NONE; -} - -static int node_activated_cb(mmi_node_instance_h instance) -{ - _D("[MATCH] Node activate callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[MATCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - return MMI_ERROR_NONE; -} - -static int node_deactivated_cb(mmi_node_instance_h instance) -{ - _D("[MATCH] Node deactivate callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[MATCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - return MMI_ERROR_NONE; -} - -static int node_signal_received_cb(mmi_node_instance_h instance, mmi_signal_h signal) -{ - _D("[MATCH] Node signal received callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[MATCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - return MMI_ERROR_NONE; -} - -static int port_output_format_requested_cb(mmi_port_instance_h instance, const char *format) -{ - _D("[MATCH] Port output format request callback is called for %p", instance); - - return MMI_ERROR_NONE; -} - -static int generate_output(mmi_node_instance_h instance, const char *output_name, mmi_data_h data) -{ - mmi_port_instance_h output_port = nullptr; - mmi_node_instance_find_port(instance, MMI_PORT_TYPE_OUT, output_name, &output_port); - if (nullptr == output_port) { - _E("[MATCH] Fail to get output port. %p", instance); - return MMI_ERROR_OPERATION_FAILED; - } - - int ret = mmi_port_instance_generate_output(output_port, data); - if (MMI_ERROR_NONE != ret) { - _E("[MATCH] Fail to generate output. error(%d / %s)", ret, get_error_message(ret)); - return ret; - } - - return MMI_ERROR_NONE; -} - -static int port_input_data_received_cb(mmi_port_instance_h instance, mmi_data_h data) -{ - _D("[MATCH] Text input data callback is called: %p", instance); - auto iterator = g_input_port_to_node_map.find(instance); - if (iterator == g_input_port_to_node_map.end()) { - _E("[MATCH] Fail to find proper node instance. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - auto node_instance = iterator->second; - if (false == is_node_instance_valid(node_instance)) { - _E("[MATCH] Node instance is not valid. %p", node_instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - const char *text = nullptr; - mmi_data_get_text(data, &text); - if (nullptr == text) { - _E("[MATCH] Fail to get text from data"); - return MMI_ERROR_INVALID_PARAMETER; - } - - int ret = MMI_ERROR_NONE; - auto text_candidates = g_node_to_text_candidates_map[node_instance]; - if (text_candidates->is_exist(text)) { - ret = generate_output(node_instance, OUTPUT_PORT_NAME_MATCHED_CANDIDATE, data); - } else { - ret = generate_output(node_instance, OUTPUT_PORT_NAME_REJECTED, data); - } - - if (MMI_ERROR_NONE != ret) { - _E("[MATCH] Fail to generate output"); - return ret; - } - - return MMI_ERROR_NONE; -} - - -extern "C" { - - EXPORT_API void mmi_plugin_module_get_node_list() - { - mmi_node_callbacks node_callbacks { - node_initialized_cb, - node_deinitialized_cb, - node_attribute_set_cb, - node_activated_cb, - node_deactivated_cb, - node_signal_received_cb - }; - - mmi_port_callbacks text_port_callbacks { - port_output_format_requested_cb, - port_input_data_received_cb - }; - - mmi_port_h match_text_port = nullptr; - mmi_port_create(&match_text_port); - mmi_port_set_name(match_text_port, INPUT_PORT_NAME_TEXT); - mmi_port_set_type(match_text_port, MMI_PORT_TYPE_IN); - mmi_port_set_data_type(match_text_port, MMI_DATA_TYPE_TEXT); - mmi_port_set_callbacks(match_text_port, text_port_callbacks); - - mmi_port_h match_candidate_port = nullptr; - mmi_port_create(&match_candidate_port); - mmi_port_set_name(match_candidate_port, OUTPUT_PORT_NAME_MATCHED_CANDIDATE); - mmi_port_set_type(match_candidate_port, MMI_PORT_TYPE_OUT); - mmi_port_set_data_type(match_candidate_port, MMI_DATA_TYPE_TEXT); - - mmi_port_h match_rejected_port = nullptr; - mmi_port_create(&match_rejected_port); - mmi_port_set_name(match_rejected_port, OUTPUT_PORT_NAME_REJECTED); - mmi_port_set_type(match_rejected_port, MMI_PORT_TYPE_OUT); - mmi_port_set_data_type(match_rejected_port, MMI_DATA_TYPE_TEXT); - /* Callbacks for OUT ports are not needed for now */ - - mmi_node_h match_node = nullptr; - mmi_standard_node_create_logic(MMI_STANDARD_NODE_LOGIC_TYPE_FIXED_STRING_MATCH, &match_node); - mmi_node_add_port(match_node, match_text_port); - mmi_node_add_port(match_node, match_candidate_port); - mmi_node_add_port(match_node, match_rejected_port); - mmi_node_set_callbacks(match_node, node_callbacks); - mmi_node_register(match_node); - - mmi_node_destroy(match_node); - } - -} // extern "C" diff --git a/plugins/nodes/meson.build b/plugins/nodes/meson.build deleted file mode 100755 index 9e13383..0000000 --- a/plugins/nodes/meson.build +++ /dev/null @@ -1,6 +0,0 @@ -subdir('mic') -subdir('camera') -subdir('match') -subdir('regex-match') -subdir('face-recognition') -subdir('voice-touch') diff --git a/plugins/nodes/mic/meson.build b/plugins/nodes/mic/meson.build deleted file mode 100644 index b01fe78..0000000 --- a/plugins/nodes/mic/meson.build +++ /dev/null @@ -1,31 +0,0 @@ -mmi_module_mic_library_srcs = [ - 'mmi-module-mic.cpp', - 'mmi-module-mic-recorder.cpp', - 'mmi-module-mic-recorder.h', - ] - -dlog_dep = dependency('dlog', method : 'pkg-config') -ecore_dep = dependency('ecore', method : 'pkg-config') -audio_dep = dependency('capi-media-audio-io', method : 'pkg-config') -sound_manager_dep = dependency('capi-media-sound-manager', method : 'pkg-config') - -mmi_module_mic_deps = [ - mmi_declared_dep, - dlog_dep, - ecore_dep, - audio_dep, - sound_manager_dep, - ] - -mmi_module_mic_include_dirs = include_directories( - '.', - '../../../capi/', - ) - -mmi_module_mic_library = library('mmi_module_mic', - mmi_module_mic_library_srcs, - include_directories : [ mmi_module_mic_include_dirs ], - dependencies : [mmi_module_mic_deps], - install_dir : mmi_prefix_plugindir, - install : true - ) diff --git a/plugins/nodes/mic/mmi-module-mic-recorder.cpp b/plugins/nodes/mic/mmi-module-mic-recorder.cpp deleted file mode 100644 index 800bf7a..0000000 --- a/plugins/nodes/mic/mmi-module-mic-recorder.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2023 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 -#include -#include - -#include "mmi-module-mic-recorder.h" - -#define BUFFER_LENGTH 640 - -Recorder::Recorder() -{ -} - -Recorder::~Recorder() -{ -} - -int Recorder::initialize() -{ - if (0 != sound_manager_create_stream_information(SOUND_STREAM_TYPE_VOICE_RECOGNITION, NULL, NULL, &m_stream_info)) { - _E("[Recorder] Fail to create stream info"); - return MMI_ERROR_OPERATION_FAILED; - } - - int ret = AUDIO_IO_ERROR_NONE; - ret = audio_in_create(16000, AUDIO_CHANNEL_MONO, AUDIO_SAMPLE_TYPE_S16_LE, &m_audio_in); - if (ret != AUDIO_IO_ERROR_NONE) { - _E("[Recorder] audio_in_create() failed with error code %d", ret); - return MMI_ERROR_OPERATION_FAILED; - } - - return MMI_ERROR_NONE; -} - -int Recorder::deinitialize() -{ - int ret = AUDIO_IO_ERROR_NONE; - ret = audio_in_destroy(m_audio_in); - if (AUDIO_IO_ERROR_NONE != ret) { - _E("[Recorder] audio_in_destroy() failed with error code %d", ret); - return MMI_ERROR_OPERATION_FAILED; - } - - if (0 != sound_manager_destroy_stream_information(m_stream_info)) { - _E("[Recorder] Fail to destroy stream info"); - return MMI_ERROR_OPERATION_FAILED; - } - - return MMI_ERROR_NONE; -} - -int Recorder::start() -{ - _D("Recorder::start()"); - - if (nullptr == m_audio_callback) { - _E("[Recorder] callback not set"); - return MMI_ERROR_OPERATION_FAILED; - } - - int ret = AUDIO_IO_ERROR_NONE; - - ret = audio_in_set_sound_stream_info(m_audio_in, m_stream_info); - if (AUDIO_IO_ERROR_NONE != ret) { - _E("[Recorder] audio_in_set_sound_stream_info() failed with error code %d", ret); - return MMI_ERROR_OPERATION_FAILED; - } - - ret = audio_in_prepare(m_audio_in); - if (AUDIO_IO_ERROR_NONE != ret) { - _E("[Recorder] audio_in_prepare() failed with error code %d", ret); - return MMI_ERROR_OPERATION_FAILED; - } - - if (nullptr != m_timer) { - ecore_timer_del(m_timer); - m_timer = nullptr; - } - - m_timer = ecore_timer_add(0.0, audio_in_callback, this); - if (nullptr == m_timer) { - _E("[Recorder] ecore_timer_add() failed"); - stop(); - return MMI_ERROR_OPERATION_FAILED; - } - - return MMI_ERROR_NONE; -} - -int Recorder::stop() -{ - _D("Recorder::stop()"); - - int ret = AUDIO_IO_ERROR_NONE; - - ret = audio_in_flush(m_audio_in); - if (AUDIO_IO_ERROR_NONE != ret) { - _E("[Recorder] audio_in_flush() failed with error code %d", ret); - return MMI_ERROR_OPERATION_FAILED; - } - - ret = audio_in_unprepare(m_audio_in); - if (AUDIO_IO_ERROR_NONE != ret) { - _E("[Recorder] audio_in_unprepare() failed with error code %d", ret); - return MMI_ERROR_OPERATION_FAILED; - } - - if (nullptr != m_timer) { - ecore_timer_del(m_timer); - m_timer = nullptr; - } - - return MMI_ERROR_NONE; -} - -void Recorder::set_feed_audio_callback(audio_data_callback callback) -{ - m_audio_callback = callback; -} - -void Recorder::set_node_instance(mmi_node_instance_h node_instance) -{ - m_node_instance = node_instance; -} - -Eina_Bool Recorder::audio_in_callback(void *user_data) -{ - Recorder *recorder = static_cast(user_data); - int read_byte = -1; - static char buffer[BUFFER_LENGTH]; - - read_byte = audio_in_read(recorder->m_audio_in, buffer, BUFFER_LENGTH); - - if (0 > read_byte) { - _E("audio_in_read() failed with error code %d", read_byte); - return EINA_FALSE; - } - - if (recorder->m_audio_callback) { - recorder->m_audio_callback(buffer, (size_t)read_byte, recorder->m_node_instance); - } - - return EINA_TRUE; -} diff --git a/plugins/nodes/mic/mmi-module-mic-recorder.h b/plugins/nodes/mic/mmi-module-mic-recorder.h deleted file mode 100644 index 44fd953..0000000 --- a/plugins/nodes/mic/mmi-module-mic-recorder.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2023 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. - * - */ - -#pragma once - -#include - -#include -#include -#include - -#include - -using audio_data_callback = std::function; - -class Recorder { -public: - Recorder(); - ~Recorder(); - - int initialize(); - int deinitialize(); - int start(); - int stop(); - - void set_feed_audio_callback(audio_data_callback callback); - void set_node_instance(mmi_node_instance_h node_instance); - - static Eina_Bool audio_in_callback(void *data); - -private: - audio_in_h m_audio_in{nullptr}; - sound_stream_info_h m_stream_info{nullptr}; - audio_data_callback m_audio_callback{nullptr}; - mmi_node_instance_h m_node_instance{nullptr}; - - Ecore_Timer *m_timer{nullptr}; -}; diff --git a/plugins/nodes/mic/mmi-module-mic.cpp b/plugins/nodes/mic/mmi-module-mic.cpp deleted file mode 100644 index a81ae8a..0000000 --- a/plugins/nodes/mic/mmi-module-mic.cpp +++ /dev/null @@ -1,210 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -#include "mmi-module-mic-recorder.h" - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MMI-MODULE-MIC" - -static const char *OUTPUT_PORT_NAME_AUDIO = "AUDIO"; - -static std::map g_recorder_map; - -static char pcm_dump_file_name[128] = {'\0',}; -static FILE* pcm_dump_fp = nullptr; -static int g_cnt = 0; -static size_t buffer_size = 0; - -void feed_audio_callback(void *data, size_t len, void *user_data) -{ - _D("[MIC] feed_audio_callback is called, size: %zu", len); - - mmi_node_instance_h instance = (mmi_node_instance_h)user_data; - - mmi_port_instance_h port_instance = nullptr; - mmi_node_instance_find_port(instance, MMI_PORT_TYPE_OUT, OUTPUT_PORT_NAME_AUDIO, &port_instance); - - mmi_data_h output_data = nullptr; - - - if (pcm_dump_fp) { - buffer_size += len; - fwrite(data, 1, len, pcm_dump_fp); - } - - mmi_data_create_audio(data, len, &output_data); - - mmi_port_instance_generate_output(port_instance, output_data); - - mmi_data_destroy(output_data); -} - -static int node_initialized_cb(mmi_node_instance_h instance) -{ - _D("[MIC] Node initialize callback is called for %p", instance); - if (nullptr == instance) { - _E("[MIC] node instance is null"); - return MMI_ERROR_INVALID_PARAMETER; - } - - Recorder *recorder = new Recorder(); - recorder->initialize(); - recorder->set_node_instance(instance); - recorder->set_feed_audio_callback(feed_audio_callback); - g_recorder_map.insert(std::pair(instance, recorder)); - - return MMI_ERROR_NONE; -} - -static int node_deinitialized_cb(mmi_node_instance_h instance) -{ - _D("[MIC] Node deinitialize callback is called for %p", instance); - if (nullptr == instance) { - _E("[MIC] node instance is null"); - return MMI_ERROR_INVALID_PARAMETER; - } - - try { - Recorder *recorder = g_recorder_map[instance]; - recorder->deinitialize(); - g_recorder_map.erase(instance); - delete recorder; - } catch (std::out_of_range &e) { - _E("[MIC] failed to find recorder instance"); - return MMI_ERROR_INVALID_PARAMETER; - } - - return MMI_ERROR_NONE; -} - -static int node_attribute_set_cb(mmi_node_instance_h instance, mmi_attribute_h attribute) -{ - _D("Node attribute set callback is called for %p", instance); - if (nullptr == instance) { - _E("[MIC] node instance is null"); - return MMI_ERROR_INVALID_PARAMETER; - } - - if (nullptr == attribute) { - _E("[MIC] attribute is null"); - return MMI_ERROR_INVALID_PARAMETER; - } - - // TODO: set attribute "UNFOCUSED_ONLY" - - return MMI_ERROR_NONE; -} - -static int node_activated_cb(mmi_node_instance_h instance) -{ - _D("[MIC] Node activate callback is called for %p", instance); - if (nullptr == instance) { - _E("[MIC] node instance is null"); - return MMI_ERROR_INVALID_PARAMETER; - } - - try { - Recorder *recorder = g_recorder_map[instance]; - recorder->start(); - } catch (std::out_of_range &e) { - _E("[MIC] failed to find recorder instance"); - return MMI_ERROR_INVALID_PARAMETER; - } - - snprintf(pcm_dump_file_name, sizeof(pcm_dump_file_name), "/tmp/mmi_mic_node_%d_%d", getpid(), g_cnt); - g_cnt++; - - pcm_dump_fp = fopen(pcm_dump_file_name, "wb+x"); - if (!pcm_dump_fp) { - _E("[SPEAKER RECOGNITION] File not found!"); - return -1; - } - buffer_size = 0; - - return MMI_ERROR_NONE; -} - -static int node_deactivated_cb(mmi_node_instance_h instance) -{ - _D("[MIC] Node deactivate callback is called for %p", instance); - if (nullptr == instance) { - _E("[MIC] node instance is null"); - return MMI_ERROR_INVALID_PARAMETER; - } - - try { - Recorder *recorder = g_recorder_map[instance]; - recorder->stop(); - } catch (std::out_of_range &e) { - _E("[MIC] failed to find recorder instance"); - return MMI_ERROR_INVALID_PARAMETER; - } - - if (pcm_dump_fp) - fclose(pcm_dump_fp); - pcm_dump_fp = nullptr; - buffer_size = 0; - - return MMI_ERROR_NONE; -} - -static int node_signal_received_cb(mmi_node_instance_h instance, mmi_signal_h signal) -{ - _D("Node signal received callback is called for %p", instance); - return MMI_ERROR_NONE; -} - -static int port_output_format_requested_cb(mmi_port_instance_h instance, const char *format) { - _D("Port output format request callback is called for %p", instance); - return MMI_ERROR_NONE; -} - -// TODO: It must be determined how to receive input data from the client -static int port_input_data_received_cb(mmi_port_instance_h instance, mmi_data_h data) { - _D("Port input data callback is called for %p", instance); - return MMI_ERROR_NONE; -} - -extern "C" { - - EXPORT_API void mmi_plugin_module_get_node_list() - { - mmi_node_callbacks node_callbacks { - node_initialized_cb, - node_deinitialized_cb, - node_attribute_set_cb, - node_activated_cb, - node_deactivated_cb, - node_signal_received_cb - }; - - mmi_port_callbacks audio_port_callbacks { - port_output_format_requested_cb, - port_input_data_received_cb - }; - - mmi_port_h mic_audio_port = nullptr; - mmi_port_create(&mic_audio_port); - mmi_port_set_name(mic_audio_port, "AUDIO"); - mmi_port_set_type(mic_audio_port, MMI_PORT_TYPE_OUT); - mmi_port_set_data_type(mic_audio_port, MMI_DATA_TYPE_AUDIO); - mmi_port_set_callbacks(mic_audio_port, audio_port_callbacks); - - mmi_node_h mic_node = nullptr; - mmi_standard_node_create_source(MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT, &mic_node); - mmi_node_add_port(mic_node, mic_audio_port); - mmi_node_set_callbacks(mic_node, node_callbacks); - - mmi_node_register(mic_node); - - mmi_node_destroy(mic_node); - } - -} // extern "C" diff --git a/plugins/nodes/regex-match/meson.build b/plugins/nodes/regex-match/meson.build deleted file mode 100644 index f214608..0000000 --- a/plugins/nodes/regex-match/meson.build +++ /dev/null @@ -1,27 +0,0 @@ -mmi_module_regex_match_library_srcs = [ - 'mmi-module-regex-match.cpp', - 'mmi-module-regex-match-regex-candidates.h', - 'mmi-module-regex-match-regex-candidates.cpp', - ] - -dlog_dep = dependency('dlog', method : 'pkg-config') -ecore_dep = dependency('ecore', method : 'pkg-config') - -mmi_module_regex_match_deps = [ - mmi_declared_dep, - dlog_dep, - ecore_dep, - ] - -mmi_module_regex_match_include_dirs = include_directories( - '.', - '../../../capi/', - ) - -mmi_module_regex_match_library = library('mmi_module_regex_match', - mmi_module_regex_match_library_srcs, - include_directories : [ mmi_module_regex_match_include_dirs ], - dependencies : [mmi_module_regex_match_deps], - install_dir : mmi_prefix_plugindir, - install : true - ) diff --git a/plugins/nodes/regex-match/mmi-module-regex-match-regex-candidates.cpp b/plugins/nodes/regex-match/mmi-module-regex-match-regex-candidates.cpp deleted file mode 100644 index ada0376..0000000 --- a/plugins/nodes/regex-match/mmi-module-regex-match-regex-candidates.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (c) 2023 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 - -#include "mmi-module-regex-match-regex-candidates.h" - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MMI-MODULE-REGEX-MATCH" - - -RegExCandidates::RegExCandidates() -{ - _I("[REGEX MATCH] Construct RegExCandidates"); - m_candidates.clear(); -} - -RegExCandidates::~RegExCandidates() -{ - _I("[REGEX MATCH] Destruct RegExCandidates"); - m_candidates.clear(); -} - -void RegExCandidates::append_candidate(const char *regex_name, const char *regex_pattern) -{ - if (nullptr == regex_name ||nullptr == regex_pattern) { - _W("[REGEX MATCH] Regex name or pattern is null. Skip appending"); - return; - } - - _I("[REGEX MATCH] Append candidate(%s/%s)", regex_pattern, regex_name); - m_candidates.push_back(std::make_pair(std::regex(regex_pattern), std::string(regex_name))); - _D("[REGEX MATCH] The current number of candidates (%zu)", m_candidates.size()); -} - -std::optional RegExCandidates::find_matched_candidate(const char *text) -{ - if (nullptr == text) { - _E("[REGEX MATCH] text is null."); - return std::nullopt; - } - - _I("[REGEX MATCH] Find matched candidate. text(%s)", text); - - try { - for (auto &candidate : m_candidates) { - auto ®ex = candidate.first; - if (std::regex_match(text, regex)) { - _I("Result : text(%s), result(%s)", text, candidate.second.c_str()); - return candidate.second; - } - } - } catch (std::exception &e) { - _E("Exception occurs. (%s)", e.what()); - return std::nullopt; - } - - _E("[REGEX MATCH] There no matched candidate"); - return std::nullopt; -} - -void RegExCandidates::clear_candidates() -{ - _I("[REGEX MATCH] Clear current candidates"); - m_candidates.clear(); -} - diff --git a/plugins/nodes/regex-match/mmi-module-regex-match-regex-candidates.h b/plugins/nodes/regex-match/mmi-module-regex-match-regex-candidates.h deleted file mode 100644 index 9eed260..0000000 --- a/plugins/nodes/regex-match/mmi-module-regex-match-regex-candidates.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2023 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. - * - */ - - -#ifndef __MMI_MODULE_REGEX_MATCH_REGEX_CANDIDATES_H__ -#define __MMI_MODULE_REGEX_MATCH_REGEX_CANDIDATES_H__ - - -#include -#include -#include -#include - -class RegExCandidates { -public: - RegExCandidates(); - ~RegExCandidates(); - - void append_candidate(const char *regex_name, const char *regex_pattern); - std::optional find_matched_candidate(const char *text); - void clear_candidates(); - -private: - std::vector> m_candidates; -}; - -#endif /* __MMI_MODULE_REGEX_MATCH_REGEX_CANDIDATES_H__ */ diff --git a/plugins/nodes/regex-match/mmi-module-regex-match.cpp b/plugins/nodes/regex-match/mmi-module-regex-match.cpp deleted file mode 100644 index e110148..0000000 --- a/plugins/nodes/regex-match/mmi-module-regex-match.cpp +++ /dev/null @@ -1,308 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -#include "mmi-module-regex-match-regex-candidates.h" - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MMI-MODULE-REGEX-MATCH" - - -static const char *INPUT_PORT_NAME_TEXT = "TEXT"; -static const char *OUTPUT_PORT_NAME_MATCHED_CANDIDATE = "MATCHED_CANDIDATE"; -static const char *OUTPUT_PORT_NAME_REJECTED = "REJECTED"; -static const char *ATTRIBUTE_NAME_CANDIDATES = "CANDIDATES"; - - -static std::map> g_node_to_regex_candidates_map; -static std::map g_input_port_to_node_map; - - -static int node_initialized_cb(mmi_node_instance_h instance) -{ - _D("[REGEX MATCH] Node initialize callback is called for %p", instance); - if (nullptr == instance) { - _E("[REGEX MATCH] Instance is null. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - mmi_port_instance_h input_port = nullptr; - mmi_node_instance_find_port(instance, MMI_PORT_TYPE_IN, INPUT_PORT_NAME_TEXT, &input_port); - if (nullptr == input_port) { - _E("[REGEX MATCH] Fail to get port from node. %p", instance); - return MMI_ERROR_OPERATION_FAILED; - } - - g_input_port_to_node_map[input_port] = instance; - - try { - auto text_candidates = std::make_shared(); - g_node_to_regex_candidates_map[instance] = text_candidates; - } catch (std::bad_alloc &e) { - _E("[REGEX MATCH] Fail to allocate memory for node instance. %p", instance); - return MMI_ERROR_OUT_OF_MEMORY; - } - - return MMI_ERROR_NONE; -} - -static bool is_node_instance_valid(mmi_node_instance_h instance) -{ - if (nullptr == instance) { - _E("[REGEX MATCH] Node instance is null %p", instance); - return false; - } - - auto iterator = g_node_to_regex_candidates_map.find(instance); - if (iterator == g_node_to_regex_candidates_map.end()) { - _E("[REGEX MATCH] No instance %p", instance); - return false; - } - - return true; -} - -static int node_deinitialized_cb(mmi_node_instance_h instance) -{ - _D("[REGEX MATCH] Node deinitialize callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[REGEX MATCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - mmi_port_instance_h input_port = nullptr; - mmi_node_instance_find_port(instance, MMI_PORT_TYPE_IN, INPUT_PORT_NAME_TEXT, &input_port); - if (nullptr == input_port) { - _E("[REGEX MATCH] Fail to get port from node. %p", instance); - return MMI_ERROR_OPERATION_FAILED; - } - - g_input_port_to_node_map.erase(input_port); - g_node_to_regex_candidates_map.erase(instance); - - return MMI_ERROR_NONE; -} - -static int node_attribute_set_cb(mmi_node_instance_h instance, mmi_attribute_h attribute) -{ - _D("[REGEX MATCH] Node attribute set callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[REGEX MATCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - char *name = nullptr; - mmi_attribute_get_name(attribute, &name); - if (nullptr == name) { - _E("[REGEX MATCH] Fail to get attribute name"); - return MMI_ERROR_INVALID_PARAMETER; - } - - std::string attribute_name(name); - free(name); - name = nullptr; - - if (0 != attribute_name.compare(ATTRIBUTE_NAME_CANDIDATES)) { - _E("[REGEX MATCH] Attribute name is not same as expected one. (%s)", attribute_name.c_str()); - return MMI_ERROR_INVALID_PARAMETER; - } - - mmi_primitive_value_h value = nullptr; - mmi_primitive_value_type_e type = MMI_PRIMITIVE_VALUE_TYPE_INT; - mmi_attribute_get_value(attribute, &value); - mmi_primitive_value_get_type(value, &type); - if (MMI_PRIMITIVE_VALUE_TYPE_STRING != type) { - mmi_primitive_value_destroy(value); - _E("[REGEX MATCH] Invalid type of attribute : %d", type); - return MMI_ERROR_INVALID_PARAMETER; - } - - // TODO: Check the efficient way to set attribute for regex candidates. - size_t count = 0; - mmi_primitive_value_get_array_count(value, &count); - - auto regex_candidates = g_node_to_regex_candidates_map[instance]; - regex_candidates->clear_candidates(); - - for (size_t i = 0; i < count; i += 2) { - mmi_primitive_value_h regex_name = nullptr; - mmi_primitive_value_get_array_element(value, i, ®ex_name); - - mmi_primitive_value_h regex_pattern = nullptr; - mmi_primitive_value_get_array_element(value, i + 1, ®ex_pattern); - - const char *regex_name_value = nullptr; - mmi_primitive_value_get_string(regex_name, ®ex_name_value); - - const char *regex_pattern_value = nullptr; - mmi_primitive_value_get_string(regex_pattern, ®ex_pattern_value); - - if (nullptr != regex_name_value && nullptr != regex_pattern_value) { - _D("[REGEX MATCH] Attribute value : %zu, %s, %s", i, regex_name_value, regex_pattern_value); - regex_candidates->append_candidate(regex_name_value, regex_pattern_value); - } else { - _W("[REGEX MATCH] Fail to get string. Please check error. index(%zu)", i); - } - } - mmi_primitive_value_destroy(value); - - return MMI_ERROR_NONE; -} - -static int node_activated_cb(mmi_node_instance_h instance) -{ - _D("[REGEX MATCH] Node activate callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[REGEX MATCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - return MMI_ERROR_NONE; -} - -static int node_deactivated_cb(mmi_node_instance_h instance) -{ - _D("[REGEX MATCH] Node deactivate callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[REGEX MATCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - return MMI_ERROR_NONE; -} - -static int node_signal_received_cb(mmi_node_instance_h instance, mmi_signal_h signal) -{ - _D("[REGEX MATCH] Node signal received callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[REGEX MATCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - return MMI_ERROR_NONE; -} - -static int port_output_format_requested_cb(mmi_port_instance_h instance, const char *format) -{ - _D("[REGEX MATCH] Port output format request callback is called for %p", instance); - - return MMI_ERROR_NONE; -} - -static int generate_output(mmi_node_instance_h instance, const char *output_name, mmi_data_h data) -{ - mmi_port_instance_h output_port = nullptr; - mmi_node_instance_find_port(instance, MMI_PORT_TYPE_OUT, output_name, &output_port); - if (nullptr == output_port) { - _E("[REGEX MATCH] Fail to get output port. %p", instance); - return MMI_ERROR_OPERATION_FAILED; - } - - int ret = mmi_port_instance_generate_output(output_port, data); - if (MMI_ERROR_NONE != ret) { - _E("[REGEX MATCH] Fail to generate output. error(%d / %s)", ret, get_error_message(ret)); - return ret; - } - - return MMI_ERROR_NONE; -} - -static int port_input_data_received_cb(mmi_port_instance_h instance, mmi_data_h data) -{ - _D("[REGEX MATCH] Text input data callback is called: %p", instance); - auto iterator = g_input_port_to_node_map.find(instance); - if (iterator == g_input_port_to_node_map.end()) { - _E("[REGEX MATCH] Fail to find proper node instance. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - auto node_instance = iterator->second; - if (false == is_node_instance_valid(node_instance)) { - _E("[REGEX MATCH] Node instance is not valid. %p", node_instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - const char *text = nullptr; - mmi_data_get_text(data, &text); - if (nullptr == text) { - _E("[REGEX MATCH] Fail to get text from data"); - return MMI_ERROR_INVALID_PARAMETER; - } - - int ret = MMI_ERROR_NONE; - auto text_candidates = g_node_to_regex_candidates_map[node_instance]; - auto result = text_candidates->find_matched_candidate(text); - if (result) { - mmi_data_h matched_candidate = nullptr; - mmi_data_create_text(result->c_str(), &matched_candidate); - ret = generate_output(node_instance, OUTPUT_PORT_NAME_MATCHED_CANDIDATE, matched_candidate); - mmi_data_destroy(matched_candidate); - } else { - ret = generate_output(node_instance, OUTPUT_PORT_NAME_REJECTED, data); - } - - if (MMI_ERROR_NONE != ret) { - _E("[REGEX MATCH] Fail to generate output"); - return ret; - } - - return MMI_ERROR_NONE; -} - - -extern "C" { - - EXPORT_API void mmi_plugin_module_get_node_list() - { - mmi_node_callbacks node_callbacks { - node_initialized_cb, - node_deinitialized_cb, - node_attribute_set_cb, - node_activated_cb, - node_deactivated_cb, - node_signal_received_cb - }; - - mmi_port_callbacks text_port_callbacks { - port_output_format_requested_cb, - port_input_data_received_cb - }; - - mmi_port_h match_text_port = nullptr; - mmi_port_create(&match_text_port); - mmi_port_set_name(match_text_port, INPUT_PORT_NAME_TEXT); - mmi_port_set_type(match_text_port, MMI_PORT_TYPE_IN); - mmi_port_set_data_type(match_text_port, MMI_DATA_TYPE_TEXT); - mmi_port_set_callbacks(match_text_port, text_port_callbacks); - - mmi_port_h match_candidate_port = nullptr; - mmi_port_create(&match_candidate_port); - mmi_port_set_name(match_candidate_port, OUTPUT_PORT_NAME_MATCHED_CANDIDATE); - mmi_port_set_type(match_candidate_port, MMI_PORT_TYPE_OUT); - mmi_port_set_data_type(match_candidate_port, MMI_DATA_TYPE_TEXT); - - mmi_port_h match_rejected_port = nullptr; - mmi_port_create(&match_rejected_port); - mmi_port_set_name(match_rejected_port, OUTPUT_PORT_NAME_REJECTED); - mmi_port_set_type(match_rejected_port, MMI_PORT_TYPE_OUT); - mmi_port_set_data_type(match_rejected_port, MMI_DATA_TYPE_TEXT); - /* Callbacks for OUT ports are not needed for now */ - - mmi_node_h match_node = nullptr; - mmi_standard_node_create_logic(MMI_STANDARD_NODE_LOGIC_TYPE_REGEX_STRING_MATCH, &match_node); - mmi_node_add_port(match_node, match_text_port); - mmi_node_add_port(match_node, match_candidate_port); - mmi_node_add_port(match_node, match_rejected_port); - mmi_node_set_callbacks(match_node, node_callbacks); - mmi_node_register(match_node); - - mmi_node_destroy(match_node); - } - -} // extern "C" diff --git a/plugins/nodes/voice-touch/meson.build b/plugins/nodes/voice-touch/meson.build deleted file mode 100644 index 1564037..0000000 --- a/plugins/nodes/voice-touch/meson.build +++ /dev/null @@ -1,36 +0,0 @@ -mmi_module_node_voice_touch_library_srcs = [ - 'mmi-module-voice-touch.cpp', - 'mmi-module-voice-touch-common.h', - 'mmi-module-voice-touch-candidates.h', - 'mmi-module-voice-touch-candidates.cpp', - 'mmi-module-voice-touch-string-utility.h', - 'mmi-module-voice-touch-string-utility.cpp', - 'mmi-module-voice-touch-screen-info.h', - 'mmi-module-voice-touch-screen-info.cpp', - 'mmi-module-voice-touch-data-utility.h', - 'mmi-module-voice-touch-data-utility.cpp', - 'mmi-module-voice-touch-primitive-utility.h', - 'mmi-module-voice-touch-primitive-utility.cpp', - ] - -dlog_dep = dependency('dlog', method : 'pkg-config') -ecore_dep = dependency('ecore', method : 'pkg-config') - -mmi_module_node_voice_touch_deps = [ - mmi_declared_dep, - dlog_dep, - ecore_dep, - ] - -mmi_module_node_voice_touch_include_dirs = include_directories( - '.', - '../../../capi/', - ) - -mmi_module_node_voice_touch_library = library('mmi_module_node_voice_touch', - mmi_module_node_voice_touch_library_srcs, - include_directories : [ mmi_module_node_voice_touch_include_dirs ], - dependencies : [mmi_module_node_voice_touch_deps], - install_dir : mmi_prefix_plugindir, - install : true - ) diff --git a/plugins/nodes/voice-touch/mmi-module-voice-touch-candidates.cpp b/plugins/nodes/voice-touch/mmi-module-voice-touch-candidates.cpp deleted file mode 100644 index 07e08bc..0000000 --- a/plugins/nodes/voice-touch/mmi-module-voice-touch-candidates.cpp +++ /dev/null @@ -1,299 +0,0 @@ -/* - * Copyright (c) 2023 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 - -#include -#include - -#include "mmi-module-voice-touch-candidates.h" -#include "mmi-module-voice-touch-string-utility.h" - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MMI-MODULE-VOICE-TOUCH" - - -static constexpr double WORD_MATCHING_RATE = 0.3; -static constexpr double CHAR_MATCHING_RATE = 0.35; -static constexpr size_t MIN_WORD_SIZE = 3; - - -VoiceTouchCandidates::VoiceTouchCandidates() -{ - _I("[VOICE TOUCH] Construct VoiceTouchCandidates"); - m_candidates.clear(); -} - -VoiceTouchCandidates::~VoiceTouchCandidates() -{ - _I("[VOICE TOUCH] Destruct VoiceTouchCandidates"); - m_candidates.clear(); -} - -void VoiceTouchCandidates::set_candidates(const std::vector &candidates) -{ - _I("[VOICE TOUCH] Set candidates(%zu)", candidates.size()); - m_candidates.clear(); - m_candidates = candidates; - _D("[VOICE TOUCH] The current number of candidates (%zu)", m_candidates.size()); -} - -std::optional VoiceTouchCandidates::find_matched_candidate(size_t index) -{ - _I("[VOICE TOUCH] Find matched candidate. index(%zu)", index); - std::optional result = find_matched_candidate_by_index(index); - if (result) { - _I("[VOICE TOUCH] Success To find voice touch candidate(%zu)", index); - return result; - } - - return std::nullopt; -} - -std::optional VoiceTouchCandidates::find_matched_candidate_by_index(size_t index) -{ - _I("[VOICE TOUCH] Find matched candidate by index (%zu)", index); - - if (index > m_candidates.size()) { - _E("[VOICE TOUCH] Invalid index. %zu", index); - return std::nullopt; - } - - for (auto &candidate : m_candidates) { - if (candidate.index == index) { - _I("[VOICE TOUCH] result candidate(%s)", candidate.label.c_str()); - return candidate; - } - } - - return std::nullopt; -} - -std::optional VoiceTouchCandidates::find_matched_candidate(const char *text) -{ - _I("[VOICE TOUCH] Find matched candidate. text(%s)", text); - auto lower_cased_text = StringUtility::make_lower_case(std::string(text)); - auto splited_text = StringUtility::split_text(lower_cased_text, ' '); - - std::optional result; - result = find_matched_candidate_by_text(splited_text); - if (result) { - _I("[VOICE TOUCH] Success To find voice touch candidate(%s)", text); - return result; - } - - result = find_matched_candidate_by_word(splited_text); - if (result) { - _I("[VOICE TOUCH] Success To find voice touch candidate(%s)", text); - return result; - } - - result = find_matched_candidate_by_char(splited_text); - if (result) { - _I("[VOICE TOUCH] Success To find voice touch candidate(%s)", text); - return result; - } - - _I("[VOICE TOUCH] There is no matched candidate by text. Try to find by index. text(%s)", text); - size_t index = 0; - try { - index = std::stoull(lower_cased_text); - } catch (std::exception &e) { - _E("[VOICE TOUCH] Fail string to int conversion. (%s)", e.what()); - return std::nullopt; - } - - result = find_matched_candidate_by_index(index); - if (result) { - _I("[VOICE TOUCH] Success To find voice touch candidate(%zu)", index); - return result; - } - - return std::nullopt; -} - -std::optional VoiceTouchCandidates::find_matched_candidate_by_text(const std::vector &splited_text) -{ - _I("[VOICE TOUCH] Find matched candidate by full text."); - - for (auto &candidate : m_candidates) { - std::string label = StringUtility::make_lower_case(candidate.label); - - bool is_valid = true; - for (auto &word : splited_text) { - if (label.find(word) == std::string::npos) { - is_valid = false; - break; - } - } - - if (is_valid) { - _I("[VOICE TOUCH] Success To find voice touch candidate(%s)", candidate.label.c_str()); - return candidate; - } - } - - return std::nullopt; -} - -std::optional VoiceTouchCandidates::find_matched_candidate_by_word(const std::vector &splited_text) -{ - _I("[VOICE TOUCH] Find matched candidate by word."); - - size_t max_matching_word_num = static_cast(splited_text.size() * WORD_MATCHING_RATE); - if (0 == max_matching_word_num) { - max_matching_word_num = 1; - } - _I("[VOICE TOUCH] Threshold of matching word number (%zu)", max_matching_word_num); - - std::optional result; - for (auto &candidate : m_candidates) { - std::string label = StringUtility::make_lower_case(candidate.label); - - size_t matching_word_num = 0; - for (auto &word : splited_text) { - if (label.find(word) != std::string::npos) { - matching_word_num++; - } - } - - if (matching_word_num >= max_matching_word_num) { - max_matching_word_num = matching_word_num; - result = candidate; - } - } - - if (result) { - _I("[VOICE TOUCH] Success To find voice touch candidate which has highest matching rate(%s)", result->label.c_str()); - return result; - } - - return std::nullopt; -} - -std::optional VoiceTouchCandidates::find_matched_candidate_by_char(const std::vector &splited_text) -{ - _I("[VOICE TOUCH] Find matched candidate by character."); - - auto filter_splited_text = [](std::string x) -> bool { - return x.size() >= MIN_WORD_SIZE; - }; - std::vector filtered_words; - std::copy_if(splited_text.begin(), splited_text.end(), std::back_inserter(filtered_words), filter_splited_text); - - // TODO: Current algorithm doesn't consider the original order of the words. It can affect the total score. - std::optional result; - size_t result_score = std::numeric_limits::max(); - for (auto &candidate : m_candidates) { - auto candidate_label = StringUtility::make_lower_case(candidate.label); - auto candidate_words = StringUtility::split_text(candidate_label, ' '); - - std::vector filtered_candidate_words; - std::copy_if(candidate_words.begin(), candidate_words.end(), std::back_inserter(filtered_candidate_words), filter_splited_text); - _D("[VOICE TOUCH] candidate(%s)", candidate_label.c_str()); - - size_t score = 0; - for (auto &word : filtered_words) { - const size_t MIN_THRESHOLD = static_cast(word.size() * CHAR_MATCHING_RATE) + 1; - size_t min_score = MIN_THRESHOLD; - _D("[VOICE TOUCH] Minimum matching character number (%zu)", MIN_THRESHOLD); - - for (auto &candidate_word : filtered_candidate_words) { - size_t edit_distance = calcualte_edit_distance(candidate_word, word); - - if (min_score > edit_distance) { - min_score = edit_distance; - } - } - - score += (min_score < MIN_THRESHOLD ? min_score : word.size()); - _D("[VOICE TOUCH] word(%s), label word(%s), minscore(%zu), score(%zu)", word.c_str(), candidate_label.c_str(), min_score, score); - } - - _D("[VOICE TOUCH] result score(%zu), score(%zu)", result_score, score); - if (result_score > score) { - result_score = score; - result = candidate; - } - } - - auto accumulate_size = [](size_t sum, std::string word) -> size_t - { - return sum + word.size(); - }; - size_t threshold = std::accumulate(filtered_words.begin(), filtered_words.end(), static_cast(0), accumulate_size); - if (threshold > result_score) { - _I("[VOICE TOUCH] result candidate(%s)", result->label.c_str()); - return result; - } - - return std::nullopt; -} - -size_t VoiceTouchCandidates::calcualte_edit_distance(const std::string &text1, const std::string &text2) -{ - // INFO: This is for calculating Levenshtein distance(a.k.a edit distance) as similarity matric. - std::string long_str; - std::string short_str; - if (text1.size() > text2.size()) { - long_str = text1; - short_str = text2; - } else { - long_str = text2; - short_str = text1; - } - - size_t long_str_size = long_str.size(); - size_t short_str_size = short_str.size(); - - size_t cost_array1[long_str_size + 1]{}; - size_t cost_array2[long_str_size + 1]{}; - - size_t *cost = cost_array1; - size_t *ncost = cost_array2; - - for (size_t l = 0; l <= long_str_size; l++) { - cost[l] = l; - } - - for (size_t s = 1; s <= short_str_size; s++) { - ncost[0] = s; - - for (size_t l = 1; l <= long_str_size; l++) { - size_t match = (short_str[s - 1] == long_str[l - 1] ? 0 : 1); - - size_t rep = cost[l - 1] + match; - size_t ins = cost[l] + 1; - size_t del = ncost[l - 1] + 1; - - ncost[l] = std::min({rep, ins, del}); - } - - std::swap(ncost, cost); - } - - return cost[long_str_size]; -} - -void VoiceTouchCandidates::clear_candidates() -{ - _I("[VOICE TOUCH] Clear current candidates"); - m_candidates.clear(); -} diff --git a/plugins/nodes/voice-touch/mmi-module-voice-touch-candidates.h b/plugins/nodes/voice-touch/mmi-module-voice-touch-candidates.h deleted file mode 100644 index 29b6f6a..0000000 --- a/plugins/nodes/voice-touch/mmi-module-voice-touch-candidates.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright (c) 2023 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. - * - */ - - -#ifndef __MMI_MODULE_VOICE_TOUCH_CANDIDATES_H__ -#define __MMI_MODULE_VOICE_TOUCH_CANDIDATES_H__ - - -#include -#include -#include -#include - -#include "mmi-module-voice-touch-common.h" - - -class VoiceTouchCandidates { -public: - VoiceTouchCandidates(); - ~VoiceTouchCandidates(); - - void set_candidates(const std::vector &candidates); - std::optional find_matched_candidate(size_t index); - std::optional find_matched_candidate(const char *text); - void clear_candidates(); - -private: - std::optional find_matched_candidate_by_index(size_t index); - std::optional find_matched_candidate_by_text(const std::vector &splited_text); - std::optional find_matched_candidate_by_word(const std::vector &splited_text); - std::optional find_matched_candidate_by_char(const std::vector &splited_text); - size_t calcualte_edit_distance(const std::string &text1, const std::string &text2); - -private: - std::vector m_candidates; -}; - -#endif /* __MMI_MODULE_VOICE_TOUCH_CANDIDATES_H__ */ diff --git a/plugins/nodes/voice-touch/mmi-module-voice-touch-common.h b/plugins/nodes/voice-touch/mmi-module-voice-touch-common.h deleted file mode 100644 index 18e0a7e..0000000 --- a/plugins/nodes/voice-touch/mmi-module-voice-touch-common.h +++ /dev/null @@ -1,60 +0,0 @@ - -/* - * Copyright (c) 2023 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. - * - */ - -#ifndef __MMI_MODULE_VOICE_TOUCH_COMMON_H__ -#define __MMI_MODULE_VOICE_TOUCH_COMMON_H__ - - -#include - - -enum voice_touch_mode_e { - VOICE_TOUCH_MODE_TEXT, - VOICE_TOUCH_MODE_INDEX, - VOICE_TOUCH_MODE_GRID -}; - -struct area_coordinates_s { - int x{}; - int y{}; - int w{}; - int h{}; -}; - -struct voice_touch_candidate_s { - voice_touch_mode_e mode{VOICE_TOUCH_MODE_TEXT}; - area_coordinates_s candidate_area{}; - size_t index{}; - std::string object_id{}; - std::string label{}; -}; - -struct screen_element_s { - area_coordinates_s element_area{}; - std::string object_id{}; - std::string label{}; - std::string role{}; -}; - -struct grid_information_s { - size_t col_count{}; - size_t row_count{}; -}; - - -#endif /* __MMI_MODULE_VOICE_TOUCH_COMMON_H__ */ diff --git a/plugins/nodes/voice-touch/mmi-module-voice-touch-data-utility.cpp b/plugins/nodes/voice-touch/mmi-module-voice-touch-data-utility.cpp deleted file mode 100644 index 24c43a7..0000000 --- a/plugins/nodes/voice-touch/mmi-module-voice-touch-data-utility.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (c) 2022 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 -#include - -#include "mmi-module-voice-touch-data-utility.h" - - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MMI-MODULE-VOICE-TOUCH" - -#define NAME_OF_VARIABLE(x) (#x) - - -MmiDataHelper::MmiDataHelper(mmi_data_h data, bool ownership) noexcept -{ - _I("[VOICE TOUCH] Construct helper class for wrapping existing data(%p). ownership(%s)", data, ownership ? "True" : "False"); - m_handle = data; - m_ownership = ownership; -} - -MmiDataHelper::MmiDataHelper(const std::vector &candidates) noexcept -{ - _I("[VOICE TOUCH] Construct helper class for candidates output data"); - m_handle = make_internal_mmi_data(candidates); - m_ownership = true; -} - -MmiDataHelper::MmiDataHelper(const voice_touch_candidate_s &candidate, const screen_element_s &element) noexcept -{ - _I("[VOICE TOUCH] Construct helper class for matched result output data"); - m_handle = make_internal_mmi_data(candidate, element); - m_ownership = true; -} - -MmiDataHelper::MmiDataHelper(const char *text) noexcept -{ - _I("[VOICE TOUCH] Construct helper class for rejected output data"); - m_handle = make_internal_mmi_data(text); - m_ownership = true; -} - -MmiDataHelper::~MmiDataHelper() -{ - if (m_ownership) { - mmi_data_destroy(m_handle); - } -} - -mmi_data_h MmiDataHelper::get_handle() const -{ - return m_handle; -} - -mmi_data_type_e MmiDataHelper::get_type() const -{ - mmi_data_type_e type = MMI_DATA_TYPE_ANY; - int ret = mmi_data_get_type(m_handle, &type); - if (MMI_ERROR_NONE != ret) { - _E("[VOICE TOUCH] Fail to get type. ret(%d)", ret); - throw ret; - } - - return type; -} - -int MmiDataHelper::get_integer_struct_member(const char *name) const -{ - mmi_data_h member_data = nullptr; - mmi_data_get_struct_element(m_handle, name, &member_data); - - int value = 0; - int ret = mmi_data_get_int(member_data, &value); - if (MMI_ERROR_NONE != ret) { - throw ret; - } - - return value; -} - -const char *MmiDataHelper::get_text_struct_member(const char *name) const -{ - mmi_data_h member_data = nullptr; - mmi_data_get_struct_element(m_handle, name, &member_data); - - const char *value = nullptr; - int ret = mmi_data_get_text(member_data, &value); - if (MMI_ERROR_NONE != ret) { - throw ret; - } - - return value; -} - -size_t MmiDataHelper::get_array_count() const -{ - _I("[VOICE TOUCH] Get integer value from handle."); - size_t value = 0; - int ret = mmi_data_get_array_count(m_handle, &value); - if (MMI_ERROR_NONE != ret) { - throw ret; - } - - return value; -} - -MmiDataHelper MmiDataHelper::get_array_element(size_t index) const -{ - _I("[VOICE TOUCH] Get array element on index(%zu) from handle.", index); - mmi_data_h value = nullptr; - int ret = mmi_data_get_array_element(m_handle, index, &value); - if (MMI_ERROR_NONE != ret) { - throw ret; - } - - if (nullptr == value) { - throw MMI_ERROR_OPERATION_FAILED; - } - - return MmiDataHelper(value); -} - -mmi_data_h MmiDataHelper::make_internal_mmi_data(const std::vector &candidates) -{ - mmi_data_h output_data = nullptr; - mmi_data_create_array(&output_data); - if (nullptr == output_data) { - _E("[VOICE TOUCH] Fail to allocate memory for output"); - return nullptr; - } - - for (auto &candidate : candidates) { - mmi_data_h candidate_info = nullptr; - mmi_data_create_struct(&candidate_info); - if (nullptr == output_data) { - _E("[VOICE TOUCH] Fail to allocate memory for output"); - mmi_data_destroy(output_data); - return nullptr; - } - - set_integer_struct_member(candidate_info, "mode", candidate.mode); - set_integer_struct_member(candidate_info, "coord_x", candidate.candidate_area.x); - set_integer_struct_member(candidate_info, "coord_y", candidate.candidate_area.y); - set_integer_struct_member(candidate_info, "width", candidate.candidate_area.w); - set_integer_struct_member(candidate_info, "height", candidate.candidate_area.h); - set_text_struct_member(candidate_info, "label", candidate.label.c_str()); - - mmi_data_add_array_element(output_data, candidate_info); - } - - return output_data; -} - -mmi_data_h MmiDataHelper::make_internal_mmi_data(const voice_touch_candidate_s &candidate, const screen_element_s &element) -{ - mmi_data_h output_data = nullptr; - mmi_data_h candidate_info = nullptr; - mmi_data_h click_info = nullptr; - mmi_data_create_struct(&output_data); - mmi_data_create_struct(&candidate_info); - mmi_data_create_struct(&click_info); - if (nullptr == output_data || nullptr == candidate_info || nullptr == click_info) { - mmi_data_destroy(output_data); - mmi_data_destroy(candidate_info); - mmi_data_destroy(click_info); - _E("[VOICE TOUCH] Fail to allocate memory for data."); - return nullptr; - } - - set_integer_struct_member(candidate_info, "mode", candidate.mode); - set_integer_struct_member(candidate_info, "coord_x", candidate.candidate_area.x); - set_integer_struct_member(candidate_info, "coord_y", candidate.candidate_area.y); - set_integer_struct_member(candidate_info, "width", candidate.candidate_area.w); - set_integer_struct_member(candidate_info, "height", candidate.candidate_area.h); - set_text_struct_member(candidate_info, "label", candidate.label.c_str()); - - auto &element_area = element.element_area; - set_integer_struct_member(click_info, "x", element_area.x + element_area.w / 2); - set_integer_struct_member(click_info, "y", element_area.y + element_area.h / 2); - set_text_struct_member(click_info, "object_id", element.object_id.c_str()); - - mmi_data_set_struct_element(output_data, NAME_OF_VARIABLE(candidate_info), candidate_info); - mmi_data_set_struct_element(output_data, NAME_OF_VARIABLE(click_info), click_info); - - return output_data; -} - -mmi_data_h MmiDataHelper::make_internal_mmi_data(const char *text) -{ - mmi_data_h output_data = nullptr; - mmi_data_create_text(text, &output_data); - if (nullptr == output_data) { - _E("[VOICE TOUCH] Fail to allocate memory for output"); - return nullptr; - } - - return output_data; -} - -void MmiDataHelper::set_integer_struct_member(mmi_data_h struct_data, const char *member_name, int value) -{ - mmi_data_h member_data = nullptr; - mmi_data_create_int(value, &member_data); - if (nullptr == member_data) { - _E("[VOICE TOUCH] Fail to allocate memory for data."); - return; - } - - if (MMI_ERROR_NONE != mmi_data_set_struct_element(struct_data, member_name, member_data)) { - _E("[VOICE TOUCH] Fail to set struct integer type member. name(%s). value(%d)", member_name, value); - mmi_data_destroy(member_data); - } -} - -void MmiDataHelper::set_text_struct_member(mmi_data_h struct_data, const char *member_name, const char *value) -{ - mmi_data_h member_data = nullptr; - mmi_data_create_text(value, &member_data); - if (nullptr == member_data) { - _E("[VOICE TOUCH] Fail to allocate memory for data."); - return; - } - - if (MMI_ERROR_NONE != mmi_data_set_struct_element(struct_data, member_name, member_data)) { - _E("[VOICE TOUCH] Fail to set struct text type member. name(%s). value(%s)", member_name, value); - mmi_data_destroy(member_data); - } -} diff --git a/plugins/nodes/voice-touch/mmi-module-voice-touch-data-utility.h b/plugins/nodes/voice-touch/mmi-module-voice-touch-data-utility.h deleted file mode 100644 index db0cc42..0000000 --- a/plugins/nodes/voice-touch/mmi-module-voice-touch-data-utility.h +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (c) 2023 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. - * - */ - -#ifndef __MMI_MODULE_VOICE_TOUCH_DATA_UTILITY_H__ -#define __MMI_MODULE_VOICE_TOUCH_DATA_UTILITY_H__ - - -#include - -#include -#include "mmi-module-voice-touch-common.h" - -class MmiDataHelper { -public: - MmiDataHelper(mmi_data_h data, bool ownership = false) noexcept; - MmiDataHelper(const std::vector &candidates) noexcept; - MmiDataHelper(const voice_touch_candidate_s &candidate, const screen_element_s &element) noexcept; - MmiDataHelper(const char *text) noexcept; - ~MmiDataHelper(); - - // For common - mmi_data_h get_handle() const; - mmi_data_type_e get_type() const; - - // For struct type - int get_integer_struct_member(const char *name) const; - const char *get_text_struct_member(const char *name) const; - - // For array type - size_t get_array_count() const; - MmiDataHelper get_array_element(size_t index) const; - -private: - mmi_data_h make_internal_mmi_data(const std::vector &candidates); - mmi_data_h make_internal_mmi_data(const voice_touch_candidate_s &candidate, const screen_element_s &element); - mmi_data_h make_internal_mmi_data(const char *text); - - void set_integer_struct_member(mmi_data_h struct_data, const char *member_name, int value); - void set_text_struct_member(mmi_data_h struct_data, const char *member_name, const char *value); - -private: - mmi_data_h m_handle; - bool m_ownership; -}; - -#endif /* __MMI_MODULE_VOICE_TOUCH_DATA_UTILITY_H__ */ diff --git a/plugins/nodes/voice-touch/mmi-module-voice-touch-primitive-utility.cpp b/plugins/nodes/voice-touch/mmi-module-voice-touch-primitive-utility.cpp deleted file mode 100644 index 6c39a1f..0000000 --- a/plugins/nodes/voice-touch/mmi-module-voice-touch-primitive-utility.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2022 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 -#include - -#include "mmi-module-voice-touch-primitive-utility.h" - - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MMI-MODULE-VOICE-TOUCH" - - -MmiPrimitiveHelper::MmiPrimitiveHelper(mmi_primitive_value_h handle, bool ownership) noexcept -{ - _I("[VOICE TOUCH] Construct helper class for primitive value handle"); - m_handle = handle; - m_ownership = ownership; -} - -MmiPrimitiveHelper::~MmiPrimitiveHelper() -{ - _I("[VOICE TOUCH] Destruct helper class for primitive value handle"); - if (m_ownership) { - mmi_primitive_value_destroy(m_handle); - } -} - -mmi_primitive_value_h MmiPrimitiveHelper::get_handle() const -{ - _I("[VOICE TOUCH] Get raw primitive value handle. (%p)", m_handle); - return m_handle; -} - -mmi_primitive_value_type_e MmiPrimitiveHelper::get_type() const -{ - _I("[VOICE TOUCH] Get type from handle."); - mmi_primitive_value_type_e type = MMI_PRIMITIVE_VALUE_TYPE_BOOL; - int ret = mmi_primitive_value_get_type(m_handle, &type); - if (MMI_ERROR_NONE != ret) { - throw ret; - } - - return type; -} - -int MmiPrimitiveHelper::get_integer_value() const -{ - _I("[VOICE TOUCH] Get integer value from handle."); - int value = -1; - int ret = mmi_primitive_value_get_int(m_handle, &value); - if (MMI_ERROR_NONE != ret) { - throw ret; - } - - return value; -} - -size_t MmiPrimitiveHelper::get_array_count() const -{ - _I("[VOICE TOUCH] Get integer value from handle."); - size_t value = 0; - int ret = mmi_primitive_value_get_array_count(m_handle, &value); - if (MMI_ERROR_NONE != ret) { - throw ret; - } - - return value; -} - -MmiPrimitiveHelper MmiPrimitiveHelper::get_array_element(size_t index) const -{ - _I("[VOICE TOUCH] Get array element on index(%zu) from handle.", index); - mmi_primitive_value_h value = nullptr; - int ret = mmi_primitive_value_get_array_element(m_handle, index, &value); - if (MMI_ERROR_NONE != ret) { - throw ret; - } - - if (nullptr == value) { - throw MMI_ERROR_OPERATION_FAILED; - } - - return MmiPrimitiveHelper(value); -} diff --git a/plugins/nodes/voice-touch/mmi-module-voice-touch-primitive-utility.h b/plugins/nodes/voice-touch/mmi-module-voice-touch-primitive-utility.h deleted file mode 100644 index 32c70a4..0000000 --- a/plugins/nodes/voice-touch/mmi-module-voice-touch-primitive-utility.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2023 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. - * - */ - -#ifndef __MMI_MODULE_VOICE_TOUCH_PRIMITIVE_UTILITY_H__ -#define __MMI_MODULE_VOICE_TOUCH_PRIMITIVE_UTILITY_H__ - - -#include - -class MmiPrimitiveHelper { -public: - MmiPrimitiveHelper(mmi_primitive_value_h handle, bool ownership = false) noexcept; - ~MmiPrimitiveHelper(); - - // For common - mmi_primitive_value_h get_handle() const; - mmi_primitive_value_type_e get_type() const; - - // For integer value - int get_integer_value() const; - - // For array value - size_t get_array_count() const; - MmiPrimitiveHelper get_array_element(size_t index) const; - -private: - -private: - mmi_primitive_value_h m_handle; - bool m_ownership; -}; - -#endif /* __MMI_MODULE_VOICE_TOUCH_PRIMITIVE_UTILITY_H__ */ diff --git a/plugins/nodes/voice-touch/mmi-module-voice-touch-screen-info.cpp b/plugins/nodes/voice-touch/mmi-module-voice-touch-screen-info.cpp deleted file mode 100644 index 7aa456e..0000000 --- a/plugins/nodes/voice-touch/mmi-module-voice-touch-screen-info.cpp +++ /dev/null @@ -1,343 +0,0 @@ -/* - * Copyright (c) 2023 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 -#include - -#include -#include - -#include "mmi-module-voice-touch-screen-info.h" -#include "mmi-module-voice-touch-data-utility.h" - - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MMI-MODULE-VOICE-TOUCH" - - -static const double WORD_MATCHING_RATE = 0.3; -static const double CHAR_MATCHING_RATE = 0.35; -static const size_t MIN_WORD_SIZE = 3; - - -ScreenElements::ScreenElements() -{ - _I("[VOICE TOUCH] Construct ScreenElements"); - m_screen_width = 1920; - m_screen_height = 1080; - m_grid_depth = 0; - m_parent_grid_area = { - .x = 0, - .y = 0, - .w = m_screen_width, - .h = m_screen_height - }; - - m_grid_informations.clear(); - m_grid_informations.push_back(grid_information_s{ - .col_count = 7, - .row_count = 5 - }); - m_grid_informations.push_back(grid_information_s{ - .col_count = 4, - .row_count = 3 - }); - - m_screen_elements.clear(); -} - -ScreenElements::~ScreenElements() -{ - _I("[VOICE TOUCH] Destruct ScreenElements"); - m_screen_width = 1920; - m_screen_height = 1080; - m_grid_depth = 0; - m_parent_grid_area = { - .x = 0, - .y = 0, - .w = m_screen_width, - .h = m_screen_height - }; - m_grid_informations.clear(); - m_screen_elements.clear(); -} - -void ScreenElements::set_screen_size(int width, int height) -{ - _I("[VOICE TOUCH] Set screen size information. w(%d), h(%d)", width, height); - m_screen_width = width; - m_screen_height = height; -} - -void ScreenElements::set_grid_informations(const std::vector &grid_informations) -{ - _I("[VOICE TOUCH] Set grid information according to each depth. maximum depth(%zu)", grid_informations.size()); - m_grid_informations = grid_informations; -} - -void ScreenElements::set_screen_elements(const MmiDataHelper &screen_elements) -{ - _I("[VOICE TOUCH] Set screen elements from mmi data"); - try { - size_t counts = screen_elements.get_array_count(); - - m_screen_elements.clear(); - for (size_t i = 0; i < counts; i++) { - auto element = screen_elements.get_array_element(i); - m_screen_elements.push_back(make_screen_element(element)); - } - } catch (mmi_error_e &error) { - _E("[VOICE TOUCH] Fail to make screen element. (%d)", error); - return; - } - - _D("[VOICE TOUCH] The current number of elements (%zu)", m_screen_elements.size()); -} - -screen_element_s ScreenElements::make_screen_element(MmiDataHelper &data) -{ - area_coordinates_s element_area{ - .x = data.get_integer_struct_member("coord_x"), - .y = data.get_integer_struct_member("coord_y"), - .w = data.get_integer_struct_member("width"), - .h = data.get_integer_struct_member("height") - }; - - screen_element_s screen_element{ - .element_area = element_area, - .object_id = std::string(data.get_text_struct_member("object_id")), - .label = std::string(data.get_text_struct_member("label")), - .role = std::string(data.get_text_struct_member("role")) - }; - - return screen_element; -} - -void ScreenElements::set_grid_area(const area_coordinates_s &grid_area) -{ - _I("[VOICE TOUCH] Set screen area information x(%d) / y(%d) / w(%d)/ h(%d)", - grid_area.x, grid_area.y, grid_area.w, grid_area.h); - m_parent_grid_area = grid_area; -} - -void ScreenElements::increase_grid_depth() -{ - m_grid_depth++; - _I("[VOICE TOUCH] Increase current grid depth. (%zu)", m_grid_depth); -} - -void ScreenElements::reset_grid_depth() -{ - _I("[VOICE TOUCH] Reset current grid depth."); - m_grid_depth = 0; - m_parent_grid_area = area_coordinates_s{ - .x = 0, - .y = 0, - .w = m_screen_width, - .h = m_screen_height - }; -} - -bool ScreenElements::is_maximum_grid_depth() -{ - bool result = (m_grid_depth == m_grid_informations.size()); - _I("[VOICE TOUCH] Check current grid depth reaches to maximum. current(%zu) / max(%zu). result(%s)", - m_grid_depth, m_grid_informations.size(), result ? "True" : "False"); - - return result; -} - -std::vector ScreenElements::make_voice_touch_candidates(voice_touch_mode_e mode) -{ - _I("[VOICE TOUCH] Make voice touch candidates according to the mode. (%d)", mode); - std::vector candidates; - - switch (mode) - { - case VOICE_TOUCH_MODE_TEXT: - fill_text_label_candidates(candidates); - break; - - case VOICE_TOUCH_MODE_INDEX: - fill_index_label_candidates(candidates); - break; - - case VOICE_TOUCH_MODE_GRID: - fill_grid_label_candidates(candidates); - break; - - default: - _E("[VOICE TOUCH] Invalid voice touch mode (%d)", mode); - break; - } - - return candidates; -} - -void ScreenElements::fill_grid_label_candidates(std::vector &candidates) -{ - if (m_grid_depth >= m_grid_informations.size()) { - _E("[VOICE TOUCH] Current grid depth is out of range (%zu) / (%zu)", m_grid_depth, m_grid_informations.size()); - return; - } - - size_t col_count = m_grid_informations.at(m_grid_depth).col_count; - size_t row_count = m_grid_informations.at(m_grid_depth).row_count; - - size_t grid_width = m_parent_grid_area.w / col_count; - size_t grid_height = m_parent_grid_area.h / row_count; - - size_t remain_width = m_parent_grid_area.w % col_count; - size_t remain_height = m_parent_grid_area.h % row_count; - - // TODO: Enhance the calculation to uniformly seperate the grid - size_t index = 1; - for (size_t y = 0; y < row_count; y++) { - for (size_t x = 0; x < col_count; x++) { - area_coordinates_s candidate_area{ - .x = static_cast(m_parent_grid_area.x + (x * grid_width)), - .y = static_cast(m_parent_grid_area.y + (y * grid_height)), - .w = static_cast((x == col_count - 1 ? grid_width + remain_width : grid_width)), - .h = static_cast((y == row_count - 1 ? grid_height + remain_height : grid_height)) - }; - - voice_touch_candidate_s candidate{ - .mode = VOICE_TOUCH_MODE_GRID, - .candidate_area = candidate_area, - .index = index, - .object_id = std::string(), - .label = std::to_string(index) - }; - - candidates.push_back(candidate); - index++; - } - } -} - -void ScreenElements::fill_index_label_candidates(std::vector &candidates) -{ - size_t index = 1; - for (auto &element : m_screen_elements) { - voice_touch_candidate_s candidate{ - .mode = VOICE_TOUCH_MODE_INDEX, - .candidate_area = element.element_area, - .index = index, - .object_id = element.object_id, - .label = std::to_string(index) - }; - - candidates.push_back(candidate); - index++; - } -} - -void ScreenElements::fill_text_label_candidates(std::vector &candidates) -{ - size_t index = 1; - for (auto &element : m_screen_elements) { - voice_touch_candidate_s candidate{ - .mode = VOICE_TOUCH_MODE_TEXT, - .candidate_area = element.element_area, - .index = index, - .object_id = element.object_id, - .label = (element.label.empty() ? std::to_string(index) : element.label) - }; - - candidates.push_back(candidate); - index++; - } -} - -std::optional ScreenElements::find_related_screen_element(const voice_touch_candidate_s &candidate) -{ - switch (candidate.mode) - { - case VOICE_TOUCH_MODE_TEXT: - case VOICE_TOUCH_MODE_INDEX: - return find_exact_element_by_object_id(candidate.object_id); - - case VOICE_TOUCH_MODE_GRID: - return find_best_element_in_grid(candidate.candidate_area); - - default: - _E("[VOICE TOUCH] Invalid voice touch mode (%d)", candidate.mode); - break; - } - - return std::nullopt; -} - -std::optional ScreenElements::find_exact_element_by_object_id(const std::string &object_id) -{ - auto is_same_element = [object_id](const screen_element_s &element) -> bool { - return element.object_id == object_id; - }; - - auto result = std::find_if(m_screen_elements.begin(), m_screen_elements.end(), is_same_element); - if (result == m_screen_elements.end()) { - _E("[VOICE TOUCH] No candidates which has object id(%s)", object_id.c_str()); - return std::nullopt; - } - - _I("[VOICE TOUCH] Result. object Id(%s)", object_id.c_str()); - return *result; -} - -std::optional ScreenElements::find_best_element_in_grid(const area_coordinates_s &grid_area) -{ - int grid_x1 = grid_area.x; - int grid_x2 = grid_area.x + grid_area.w; - int grid_y1 = grid_area.y; - int grid_y2 = grid_area.y + grid_area.h; - - auto is_in_area = [grid_x1, grid_x2, grid_y1, grid_y2](const screen_element_s &element) -> bool { - auto &area = element.element_area; - if (area.x >= grid_x2 || area.x + area.w <= grid_x1 || area.y > grid_y2 || area.y + area.h <= grid_y1) { - return false; - } - - return true; - }; - - std::vector filtered_elements; - std::copy_if(m_screen_elements.begin(), m_screen_elements.end(), std::back_inserter(filtered_elements), is_in_area); - if (filtered_elements.empty()) { - _E("[VOICE TOUCH] No candidates in grid (%d, %d / %d, %d)", grid_x1, grid_y1, grid_x2, grid_y2); - return std::nullopt; - } - - std::optional result; - int maximum_area_size = -1; - for (auto &element : filtered_elements) { - auto &area = element.element_area; - int dx = std::min(grid_x2, area.x + area.w) - std::max(grid_x1, area.x); - int dy = std::min(grid_y2, area.y + area.h) - std::max(grid_y1, area.y); - - int area_size = dx * dy; - if (maximum_area_size < area_size) { - maximum_area_size = area_size; - result = element; - } - } - - _I("[VOICE TOUCH] Result. object Id(%s)", result->object_id.c_str()); - return result; -} diff --git a/plugins/nodes/voice-touch/mmi-module-voice-touch-screen-info.h b/plugins/nodes/voice-touch/mmi-module-voice-touch-screen-info.h deleted file mode 100644 index 057c901..0000000 --- a/plugins/nodes/voice-touch/mmi-module-voice-touch-screen-info.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2023 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. - * - */ - - -#ifndef __MMI_MODULE_VOICE_TOUCH_SCREEN_INFO_H__ -#define __MMI_MODULE_VOICE_TOUCH_SCREEN_INFO_H__ - - -#include -#include -#include -#include - -#include "mmi-module-voice-touch-common.h" -#include "mmi-module-voice-touch-data-utility.h" - - -class ScreenElements { -public: - ScreenElements(); - ~ScreenElements(); - - void set_screen_size(int width, int height); - void set_grid_informations(const std::vector &grid_informations); - void set_screen_elements(const MmiDataHelper &screen_elements); - void set_grid_area(const area_coordinates_s &grid_area); - - void increase_grid_depth(); - void reset_grid_depth(); - bool is_maximum_grid_depth(); - - std::vector make_voice_touch_candidates(voice_touch_mode_e mode); - std::optional find_related_screen_element(const voice_touch_candidate_s &candidate); - -private: - screen_element_s make_screen_element(MmiDataHelper &data); - - void fill_grid_label_candidates(std::vector &candidates); - void fill_index_label_candidates(std::vector &candidates); - void fill_text_label_candidates(std::vector &candidates); - - std::optional find_exact_element_by_object_id(const std::string &object_id); - std::optional find_best_element_in_grid(const area_coordinates_s &grid_area); - -private: - // Screen information - int m_screen_width; - int m_screen_height; - - // Grid information - std::vector m_grid_informations; - area_coordinates_s m_parent_grid_area; - size_t m_grid_depth; - - // Current screen elements - std::vector m_screen_elements; -}; - -#endif /* __MMI_MODULE_VOICE_TOUCH_SCREEN_INFO_H__ */ diff --git a/plugins/nodes/voice-touch/mmi-module-voice-touch-string-utility.cpp b/plugins/nodes/voice-touch/mmi-module-voice-touch-string-utility.cpp deleted file mode 100644 index 7a1134c..0000000 --- a/plugins/nodes/voice-touch/mmi-module-voice-touch-string-utility.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2022 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 -#include - -#include "mmi-module-voice-touch-string-utility.h" - - -std::string StringUtility::make_lower_case(std::string text) -{ - transform(text.begin(), text.end(), text.begin(), ::tolower); - return text; -} - -std::vector StringUtility::split_text(std::string text, char delimiter) -{ - std::vector result; - std::istringstream ss{text}; - std::string temp; - - while (getline(ss, temp, delimiter)) { - result.push_back(temp); - } - - return result; -} diff --git a/plugins/nodes/voice-touch/mmi-module-voice-touch-string-utility.h b/plugins/nodes/voice-touch/mmi-module-voice-touch-string-utility.h deleted file mode 100644 index 12c71b2..0000000 --- a/plugins/nodes/voice-touch/mmi-module-voice-touch-string-utility.h +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2023 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. - * - */ - -#ifndef __MMI_MODULE_VOICE_TOUCH_STRING_UTILITY_H__ -#define __MMI_MODULE_VOICE_TOUCH_STRING_UTILITY_H__ - - -#include -#include - -class StringUtility { -public: - static std::string make_lower_case(std::string text); - static std::vector split_text(std::string text, char delimeter); -}; - -#endif /* __MMI_MODULE_VOICE_TOUCH_STRING_UTILITY_H__ */ diff --git a/plugins/nodes/voice-touch/mmi-module-voice-touch.cpp b/plugins/nodes/voice-touch/mmi-module-voice-touch.cpp deleted file mode 100644 index 76d72fc..0000000 --- a/plugins/nodes/voice-touch/mmi-module-voice-touch.cpp +++ /dev/null @@ -1,617 +0,0 @@ -#include -#include -#include -#include - -#include -#include - -#include "mmi-module-voice-touch-candidates.h" -#include "mmi-module-voice-touch-screen-info.h" -#include "mmi-module-voice-touch-data-utility.h" -#include "mmi-module-voice-touch-primitive-utility.h" - - -#ifdef LOG_TAG -#undef LOG_TAG -#endif -#define LOG_TAG "MMI-MODULE-VOICE-TOUCH" - - -struct voice_touch_helper_s -{ - VoiceTouchCandidates voice_touch_candidates; - ScreenElements screen_elements; - voice_touch_mode_e mode{VOICE_TOUCH_MODE_TEXT}; -}; - - -static const char *INPUT_PORT_NAME_SCREEN_INFO = "SCREEN_INFO"; -static const char *INPUT_PORT_NAME_MODE_COMMANDS = "MODE_COMMANDS"; -static const char *INPUT_PORT_NAME_UTTERANCE = "UTTERANCE"; - -static const char *OUTPUT_PORT_NAME_MATCHED_RESULT = "MATCHED_RESULT"; -static const char *OUTPUT_PORT_NAME_REJECTED = "REJECTED"; -static const char *OUTPUT_PORT_NAME_CANDIDATES = "CANDIDATES"; - -static const char *ATTRIBUTE_NAME_GRID_CONFIGURATION = "GRID_CONFIGURATION"; - -static const char *MODE_COMMAND_SHOW_INDEX = "숫자 보여줘"; -static const char *MODE_COMMAND_SHOW_TEXT = "텍스트 보여줘"; -static const char *MODE_COMMAND_SHOW_GRID = "그리드 보여줘"; - - -static std::map> g_node_to_helper_map; - - -static int node_initialized_cb(mmi_node_instance_h instance) -{ - _D("[VOICE TOUCH] Node initialize callback is called for %p", instance); - if (nullptr == instance) { - _E("[VOICE TOUCH] Instance is null. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - try { - auto helper_instance = std::make_shared(); - g_node_to_helper_map[instance] = helper_instance; - } catch (std::bad_alloc &e) { - _E("[VOICE TOUCH] Fail to allocate memory for node instance. %p", instance); - return MMI_ERROR_OUT_OF_MEMORY; - } - - return MMI_ERROR_NONE; -} - -static bool is_node_instance_valid(mmi_node_instance_h instance) -{ - if (nullptr == instance) { - _E("[VOICE TOUCH] Node instance is null %p", instance); - return false; - } - - auto iterator = g_node_to_helper_map.find(instance); - if (iterator == g_node_to_helper_map.end()) { - _E("[VOICE TOUCH] No instance %p", instance); - return false; - } - - return true; -} - -static int node_deinitialized_cb(mmi_node_instance_h instance) -{ - _D("[VOICE TOUCH] Node deinitialize callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[VOICE TOUCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - g_node_to_helper_map.erase(instance); - return MMI_ERROR_NONE; -} - -static int node_attribute_set_cb(mmi_node_instance_h instance, mmi_attribute_h attribute) -{ - _D("[VOICE TOUCH] Node attribute set callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[VOICE TOUCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - char *name = nullptr; - mmi_attribute_get_name(attribute, &name); - if (nullptr == name) { - _E("[VOICE TOUCH] Fail to get name from attribute. %p", attribute); - return MMI_ERROR_INVALID_PARAMETER; - } - - std::string attribute_name(name); - free(name); - name = nullptr; - - if (0 != attribute_name.compare(ATTRIBUTE_NAME_GRID_CONFIGURATION)) { - _E("[VOICE TOUCH] Attribute name is not same as expected one. (%s)", attribute_name.c_str()); - return MMI_ERROR_INVALID_PARAMETER; - } - - mmi_primitive_value_h value = nullptr; - mmi_attribute_get_value(attribute, &value); - if (nullptr == value) { - _E("[VOICE TOUCH] Fail to get primitive value from attribute. %p", attribute); - return MMI_ERROR_INVALID_PARAMETER; - } - - MmiPrimitiveHelper attribute_value(value, true); - value = nullptr; - if (MMI_PRIMITIVE_VALUE_TYPE_ARRAY != attribute_value.get_type()) { - _E("[VOICE TOUCH] Fail to get primitive value from attribute. %p", attribute); - return MMI_ERROR_INVALID_PARAMETER; - } - - auto &screen_elements = g_node_to_helper_map[instance]->screen_elements; - - // TODO: Check the efficient way to set attribute for voice touch. - try { - auto screen_w = attribute_value.get_array_element(0).get_integer_value(); - auto screen_h = attribute_value.get_array_element(1).get_integer_value(); - - _D("[VOICE TOUCH] Screen size : %d, %d", screen_w, screen_h); - screen_elements.set_screen_size(screen_w, screen_h); - } catch (mmi_error_e &error) { - _E("[VOICE TOUCH] Fail to get screen size. %p", attribute); - return error; - } - - size_t count = attribute_value.get_array_count(); - std::vector grid_informations; - for (size_t i = 2; i < count; i += 2) { - try { - grid_information_s grid_information{ - .col_count = static_cast(attribute_value.get_array_element(i).get_integer_value()), - .row_count = static_cast(attribute_value.get_array_element(i + 1).get_integer_value()) - }; - - _D("[VOICE TOUCH] Grid information : col(%zu), row(%zu)", grid_information.col_count, grid_information.row_count); - grid_informations.push_back(grid_information); - } catch (mmi_error_e &error) { - _E("[VOICE TOUCH] Fail to get data. Please check error. index(%zu). error(%d)", i, error); - return error; - } - } - - screen_elements.set_grid_informations(grid_informations); - return MMI_ERROR_NONE; -} - -static int node_activated_cb(mmi_node_instance_h instance) -{ - _D("[VOICE TOUCH] Node activate callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[VOICE TOUCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - return MMI_ERROR_NONE; -} - -static int node_deactivated_cb(mmi_node_instance_h instance) -{ - _D("[VOICE TOUCH] Node deactivate callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[VOICE TOUCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - return MMI_ERROR_NONE; -} - -static int utterance_port_output_format_requested_cb(mmi_port_instance_h instance, const char *format) -{ - _D("[VOICE TOUCH] Port output format request callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[VOICE TOUCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - return MMI_ERROR_NONE; -} - -static void generate_output_for_rejected_port(mmi_node_instance_h instance, const char *text) -{ - mmi_port_instance_h rejected_port = nullptr; - mmi_node_instance_find_port(instance, MMI_PORT_TYPE_OUT, OUTPUT_PORT_NAME_REJECTED, &rejected_port); - if (nullptr == rejected_port) { - _E("[VOICE TOUCH] Fail to get output port. name(%s). node instance(%p)", OUTPUT_PORT_NAME_REJECTED, instance); - return; - } - - MmiDataHelper output_data(text); - if (nullptr == output_data.get_handle()) { - _E("[VOICE TOUCH] Fail to allocate memory for output data. name(%s). node instance(%p)", OUTPUT_PORT_NAME_MATCHED_RESULT, instance); - return; - } - - mmi_port_instance_generate_output(rejected_port, output_data.get_handle()); -} - -static void generate_output_for_matched_result_port(mmi_node_instance_h instance, const voice_touch_candidate_s &candidate, const screen_element_s &element) -{ - mmi_port_instance_h matched_result_port = nullptr; - mmi_node_instance_find_port(instance, MMI_PORT_TYPE_OUT, OUTPUT_PORT_NAME_MATCHED_RESULT, &matched_result_port); - if (nullptr == matched_result_port) { - _E("[VOICE TOUCH] Fail to get output port. name(%s). node instance(%p)", OUTPUT_PORT_NAME_MATCHED_RESULT, instance); - return; - } - - MmiDataHelper output_data(candidate, element); - if (nullptr == output_data.get_handle()) { - _E("[VOICE TOUCH] Fail to allocate memory for output data. name(%s). node instance(%p)", OUTPUT_PORT_NAME_MATCHED_RESULT, instance); - return; - } - - mmi_port_instance_generate_output(matched_result_port, output_data.get_handle()); -} - -static void generate_output_for_candidates_port(mmi_node_instance_h instance, const std::vector &candidates) -{ - mmi_port_instance_h candidates_port = nullptr; - mmi_node_instance_find_port(instance, MMI_PORT_TYPE_OUT, OUTPUT_PORT_NAME_CANDIDATES, &candidates_port); - if (nullptr == candidates_port) { - _E("[VOICE TOUCH] Fail to get output port. name(%s). node instance(%p)", OUTPUT_PORT_NAME_CANDIDATES, instance); - return; - } - - MmiDataHelper output_data(candidates); - if (nullptr == output_data.get_handle()) { - _E("[VOICE TOUCH] Fail to allocate memory for output data. name(%s). node instance(%p)", OUTPUT_PORT_NAME_CANDIDATES, instance); - return; - } - - mmi_port_instance_generate_output(candidates_port, output_data.get_handle()); -} - -static mmi_error_e handle_utterance_input_as_text(mmi_node_instance_h instance, const char *utterance) -{ - auto &voice_touch_candidates = g_node_to_helper_map[instance]->voice_touch_candidates; - auto &screen_elements = g_node_to_helper_map[instance]->screen_elements; - - auto matched_candidate = voice_touch_candidates.find_matched_candidate(utterance); - if (matched_candidate.has_value() == false) { - _I("[VOICE TOUCH] There is no proper candidate in the screen. utterance(%s)", utterance); - return MMI_ERROR_OPERATION_FAILED; - } - - auto matched_element = screen_elements.find_related_screen_element(*matched_candidate); - if (matched_element.has_value() == false) { - _I("[VOICE TOUCH] There is no proper screen element in the screen. utterance(%s)", utterance); - return MMI_ERROR_OPERATION_FAILED; - } - - _I("[VOICE TOUCH] Success to find the candidate. utterance(%s)", utterance); - generate_output_for_matched_result_port(instance, *matched_candidate, *matched_element); - - return MMI_ERROR_NONE; -} - -static mmi_error_e handle_utterance_input_as_index(mmi_node_instance_h instance, const char *utterance) -{ - auto &voice_touch_candidates = g_node_to_helper_map[instance]->voice_touch_candidates; - auto &screen_elements = g_node_to_helper_map[instance]->screen_elements; - - int index = -1; - try { - index = std::stoi(utterance); - } catch (std::exception &e) { - _I("[VOICE TOUCH] There is no number in utterance. utterance(%s). exception(%s)", utterance, e.what()); - return MMI_ERROR_OPERATION_FAILED; - } - - auto matched_candidate = voice_touch_candidates.find_matched_candidate(index); - if (matched_candidate.has_value() == false) { - _I("[VOICE TOUCH] There is no proper candidate in the screen. utterance(%s)", utterance); - return MMI_ERROR_OPERATION_FAILED; - } - - auto matched_element = screen_elements.find_related_screen_element(*matched_candidate); - if (matched_element.has_value() == false) { - _I("[VOICE TOUCH] There is no proper screen element in the screen. utterance(%s)", utterance); - return MMI_ERROR_OPERATION_FAILED; - } - - _I("[VOICE TOUCH] Success to find the candidate. utterance(%s)", utterance); - generate_output_for_matched_result_port(instance, *matched_candidate, *matched_element); - - return MMI_ERROR_NONE; -} - -static mmi_error_e handle_utterance_input_as_grid(mmi_node_instance_h instance, const char *utterance) -{ - auto &voice_touch_candidates = g_node_to_helper_map[instance]->voice_touch_candidates; - auto &screen_elements = g_node_to_helper_map[instance]->screen_elements; - - int index = -1; - try { - index = std::stoi(utterance); - } catch (std::exception &e) { - _I("[VOICE TOUCH] There is no number in utterance. utterance(%s). exception(%s)", utterance, e.what()); - return MMI_ERROR_OPERATION_FAILED; - } - - auto matched_candidate = voice_touch_candidates.find_matched_candidate(index); - if (matched_candidate.has_value() == false) { - _I("[VOICE TOUCH] There is no proper candidate in the screen. utterance(%s)", utterance); - return MMI_ERROR_OPERATION_FAILED; - } - - screen_elements.increase_grid_depth(); - if (screen_elements.is_maximum_grid_depth() == false) { - _I("[VOICE TOUCH] Make candidate for next grid depth."); - screen_elements.set_grid_area(matched_candidate->candidate_area); - - auto candidates = screen_elements.make_voice_touch_candidates(VOICE_TOUCH_MODE_GRID); - voice_touch_candidates.set_candidates(candidates); - generate_output_for_candidates_port(instance, candidates); - return MMI_ERROR_NONE; - } - - auto matched_element = screen_elements.find_related_screen_element(*matched_candidate); - if (matched_element.has_value() == false) { - _I("[VOICE TOUCH] There is no proper screen element in the screen. utterance(%s)", utterance); - _I("[VOICE TOUCH] Make output for center of grid"); - matched_element = screen_element_s{ - .element_area = matched_candidate->candidate_area, - .object_id = std::string(), - .label = matched_candidate->label, - .role = std::string() - }; - } else { - _I("[VOICE TOUCH] Success to find the candidate. utterance(%s)", utterance); - } - - screen_elements.reset_grid_depth(); - generate_output_for_matched_result_port(instance, *matched_candidate, *matched_element); - - return MMI_ERROR_NONE; -} - -static std::optional find_node_instance(mmi_port_instance_h port_instance, const char *port_name) -{ - if (nullptr == port_instance || nullptr == port_name) { - return std::nullopt; - } - - for (auto &element : g_node_to_helper_map) { - mmi_port_instance_h candidate_port = nullptr; - mmi_node_instance_find_port(element.first, MMI_PORT_TYPE_IN, port_name, &candidate_port); - - if (candidate_port == port_instance) { - return element.first; - } - } - - return std::nullopt; -} - -static int utterance_port_input_data_received_cb(mmi_port_instance_h instance, mmi_data_h data) -{ - _D("[VOICE TOUCH] Text input data callback is called: %p", instance); - auto node_instance = find_node_instance(instance, INPUT_PORT_NAME_UTTERANCE); - if (node_instance.has_value() == false) { - _E("[VOICE TOUCH] There is no proper node instance: %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - const char *utterance = nullptr; - mmi_data_get_text(data, &utterance); - if (nullptr == utterance) { - _E("[VOICE TOUCH] Fail to get text from the data: %p", data); - return MMI_ERROR_INVALID_PARAMETER; - } - - voice_touch_mode_e mode = g_node_to_helper_map[*node_instance]->mode; - mmi_error_e ret = MMI_ERROR_NONE; - switch (mode) { - case VOICE_TOUCH_MODE_TEXT: - ret = handle_utterance_input_as_text(*node_instance, utterance); - break; - - case VOICE_TOUCH_MODE_INDEX: - ret = handle_utterance_input_as_index(*node_instance, utterance); - break; - - case VOICE_TOUCH_MODE_GRID: - ret = handle_utterance_input_as_grid(*node_instance, utterance); - break; - } - - if (MMI_ERROR_NONE != ret) { - _I("[VOICE TOUCH] Generate reject output. utterance(%s)", utterance); - generate_output_for_rejected_port(*node_instance, utterance); - } - - return MMI_ERROR_NONE; -} - -static int mode_commands_port_output_format_requested_cb(mmi_port_instance_h instance, const char *format) -{ - _D("[VOICE TOUCH] Port output format request callback is called for %p", instance); - - return MMI_ERROR_NONE; -} - -static int mode_commands_port_input_data_received_cb(mmi_port_instance_h instance, mmi_data_h data) -{ - _D("[VOICE TOUCH] Text input data callback is called: %p", instance); - auto node_instance = find_node_instance(instance, INPUT_PORT_NAME_MODE_COMMANDS); - if (node_instance.has_value() == false) { - _E("[VOICE TOUCH] There is no proper node instance: %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - const char *text = nullptr; - mmi_data_get_text(data, &text); - if (nullptr == text) { - _E("[VOICE TOUCH] Fail to get text from the data: %p", data); - return MMI_ERROR_INVALID_PARAMETER; - } - - std::string mode_str = text; - text = nullptr; - - voice_touch_mode_e mode = VOICE_TOUCH_MODE_TEXT; - if (mode_str.compare(MODE_COMMAND_SHOW_TEXT) == 0) { - mode = VOICE_TOUCH_MODE_TEXT; - } else if (mode_str.compare(MODE_COMMAND_SHOW_INDEX) == 0) { - mode = VOICE_TOUCH_MODE_INDEX; - } else if (mode_str.compare(MODE_COMMAND_SHOW_GRID) == 0) { - mode = VOICE_TOUCH_MODE_GRID; - } else { - _E("[VOICE TOUCH] Invalid mode command: %s", mode_str.c_str()); - return MMI_ERROR_INVALID_PARAMETER; - } - - auto &node_helper = g_node_to_helper_map[*node_instance]; - auto &voice_touch_candidates = node_helper->voice_touch_candidates; - auto &screen_elements = node_helper->screen_elements; - - node_helper->mode = mode; - auto candidates = screen_elements.make_voice_touch_candidates(node_helper->mode); - voice_touch_candidates.set_candidates(candidates); - - generate_output_for_candidates_port(*node_instance, candidates); - - return MMI_ERROR_NONE; -} - -static int screen_info_port_output_format_requested_cb(mmi_port_instance_h instance, const char *format) -{ - _D("[VOICE TOUCH] Port output format request callback is called for %p", instance); - if (false == is_node_instance_valid(instance)) { - _E("[VOICE TOUCH] Instance is not valid. %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - return MMI_ERROR_NONE; -} - -static int screen_info_port_input_data_received_cb(mmi_port_instance_h instance, mmi_data_h data) -{ - _D("[VOICE TOUCH] Text input data callback is called: %p", instance); - auto node_instance = find_node_instance(instance, INPUT_PORT_NAME_SCREEN_INFO); - if (node_instance.has_value() == false) { - _E("[VOICE TOUCH] There is no proper node instance: %p", instance); - return MMI_ERROR_INVALID_PARAMETER; - } - - const MmiDataHelper data_helper(data); - try { - mmi_data_type_e type = data_helper.get_type(); - if (MMI_DATA_TYPE_ARRAY != type) { - _E("[VOICE TOUCH] Type is not valid. data(%p). type(%d)", data, type); - return MMI_ERROR_INVALID_PARAMETER; - } - } catch (mmi_error_e &error) { - return error; - } - - auto &node_helper = g_node_to_helper_map[*node_instance]; - auto &voice_touch_candidates = node_helper->voice_touch_candidates; - auto &screen_elements = node_helper->screen_elements; - - screen_elements.set_screen_elements(data_helper); - auto candidates = screen_elements.make_voice_touch_candidates(node_helper->mode); - voice_touch_candidates.set_candidates(candidates); - generate_output_for_candidates_port(*node_instance, candidates); - - return MMI_ERROR_NONE; -} - -static mmi_port_h create_input_port(const char *name, mmi_data_type_e type, mmi_port_callbacks callbacks) -{ - mmi_port_h input_port = nullptr; - mmi_port_create(&input_port); - if (nullptr == input_port) { - return nullptr; - } - - mmi_port_set_name(input_port, name); - mmi_port_set_type(input_port, MMI_PORT_TYPE_IN); - mmi_port_set_data_type(input_port, type); - mmi_port_set_callbacks(input_port, callbacks); - - return input_port; -} - -static mmi_port_h create_output_port(const char *name, mmi_data_type_e type) -{ - mmi_port_h output_port = nullptr; - mmi_port_create(&output_port); - if (nullptr == output_port) { - return nullptr; - } - - mmi_port_set_name(output_port, name); - mmi_port_set_type(output_port, MMI_PORT_TYPE_OUT); - mmi_port_set_data_type(output_port, type); - - return output_port; -} - - -extern "C" { - - EXPORT_API void mmi_plugin_module_get_node_list() - { - mmi_node_callbacks node_callbacks { - node_initialized_cb, - node_deinitialized_cb, - node_attribute_set_cb, - node_activated_cb, - node_deactivated_cb, - nullptr - }; - - mmi_port_callbacks utterance_port_callbacks { - utterance_port_output_format_requested_cb, - utterance_port_input_data_received_cb - }; - - mmi_port_callbacks mode_commands_port_callbacks { - mode_commands_port_output_format_requested_cb, - mode_commands_port_input_data_received_cb - }; - - mmi_port_callbacks screen_info_port_callbacks { - screen_info_port_output_format_requested_cb, - screen_info_port_input_data_received_cb - }; - - mmi_port_h utterance_input_port = create_input_port( - INPUT_PORT_NAME_UTTERANCE, - MMI_DATA_TYPE_TEXT, - utterance_port_callbacks); - - mmi_port_h mode_commands_input_port = create_input_port( - INPUT_PORT_NAME_MODE_COMMANDS, - MMI_DATA_TYPE_TEXT, - mode_commands_port_callbacks); - - // TODO: check the type of input - mmi_port_h screen_info_input_port = create_input_port( - INPUT_PORT_NAME_SCREEN_INFO, - MMI_DATA_TYPE_ARRAY, - screen_info_port_callbacks); - - mmi_port_h candidates_output_port = create_output_port( - OUTPUT_PORT_NAME_CANDIDATES, - MMI_DATA_TYPE_ARRAY); - - mmi_port_h matched_result_output_port = create_output_port( - OUTPUT_PORT_NAME_MATCHED_RESULT, - MMI_DATA_TYPE_STRUCT); - - mmi_port_h rejected_output_port = create_output_port( - OUTPUT_PORT_NAME_REJECTED, - MMI_DATA_TYPE_TEXT); - - mmi_node_h voice_touch_node = nullptr; - mmi_standard_node_create_processor(MMI_STANDARD_NODE_PROCESSOR_TYPE_VOICE_TOUCH, &voice_touch_node); - - // Add input ports - mmi_node_add_port(voice_touch_node, utterance_input_port); - mmi_node_add_port(voice_touch_node, mode_commands_input_port); - mmi_node_add_port(voice_touch_node, screen_info_input_port); - - // Add output ports - mmi_node_add_port(voice_touch_node, candidates_output_port); - mmi_node_add_port(voice_touch_node, matched_result_output_port); - mmi_node_add_port(voice_touch_node, rejected_output_port); - - mmi_node_set_callbacks(voice_touch_node, node_callbacks); - mmi_node_register(voice_touch_node); - - mmi_node_destroy(voice_touch_node); - } - -} // extern "C" diff --git a/plugins/workflows/script-parser/meson.build b/plugins/workflows/script-parser/meson.build index dd3564c..6da0280 100644 --- a/plugins/workflows/script-parser/meson.build +++ b/plugins/workflows/script-parser/meson.build @@ -2,12 +2,10 @@ mmi_module_script_parser_library_srcs = [ 'mmi-module-script-parser.cpp', ] -dlog_dep = dependency('dlog', method : 'pkg-config') ecore_dep = dependency('ecore', method : 'pkg-config') mmi_module_script_parser_deps = [ mmi_declared_dep, - dlog_dep, ecore_dep, ] diff --git a/plugins/workflows/script-parser/mmi-module-script-parser.cpp b/plugins/workflows/script-parser/mmi-module-script-parser.cpp index b708256..ae02cdd 100644 --- a/plugins/workflows/script-parser/mmi-module-script-parser.cpp +++ b/plugins/workflows/script-parser/mmi-module-script-parser.cpp @@ -8,14 +8,13 @@ #include #include -#include #include extern "C" { EXPORT_API void mmi_plugin_module_get_workflow_list() { - const std::string plugin_module_path{"/usr/share/mmi/scripts"}; + const std::string plugin_module_path{MMI_INSTALL_PREFIX "/share/mmi/scripts"}; for (const auto & entry : std::filesystem::directory_iterator(plugin_module_path)) { auto const pos = entry.path().string().find_last_of("."); if (pos != std::string::npos) { diff --git a/plugins/workflows/user-recognition/user-recognition.mws b/plugins/workflows/user-recognition/user-recognition.mws index 49148b8..9e7b5ec 100644 --- a/plugins/workflows/user-recognition/user-recognition.mws +++ b/plugins/workflows/user-recognition/user-recognition.mws @@ -4,12 +4,14 @@ name : USER_RECOGNITION @node-list [Source] MIC_AMBIENT as MIC [Source] CAMERA as CAMERA +[Processor] VIDEO_CONVERTER as VIDEO_CONVERTER [Processor] FACE_RECOGNITION as FACE_RECOGNITION [Processor] SPEAKER_RECOGNITION as SPEAKER_RECOGNITION [Logic] USER_COMPARISON as USER_COMPARISON @link-list -CAMERA.VIDEO -> FACE_RECOGNITION.VIDEO +CAMERA.VIDEO -> VIDEO_CONVERTER.VIDEO_IN +VIDEO_CONVERTER.VIDEO_OUT -> FACE_RECOGNITION.VIDEO FACE_RECOGNITION.MATCHED_FACES -> USER_COMPARISON.PORT1 MIC.AUDIO -> SPEAKER_RECOGNITION.AUDIO SPEAKER_RECOGNITION.MATCHED_SPEAKERS -> USER_COMPARISON.PORT2 diff --git a/plugins/workflows/voice-touch/meson.build b/plugins/workflows/voice-touch/meson.build index 628d533..6bc11da 100644 --- a/plugins/workflows/voice-touch/meson.build +++ b/plugins/workflows/voice-touch/meson.build @@ -2,12 +2,10 @@ mmi_module_voice_touch_library_srcs = [ 'mmi-module-voice-touch.cpp', ] -dlog_dep = dependency('dlog', method : 'pkg-config') ecore_dep = dependency('ecore', method : 'pkg-config') mmi_module_voice_touch_deps = [ mmi_declared_dep, - dlog_dep, ecore_dep, ] diff --git a/plugins/workflows/voice-touch/mmi-module-voice-touch.cpp b/plugins/workflows/voice-touch/mmi-module-voice-touch.cpp index f8baebd..a636f7f 100644 --- a/plugins/workflows/voice-touch/mmi-module-voice-touch.cpp +++ b/plugins/workflows/voice-touch/mmi-module-voice-touch.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -7,7 +8,6 @@ #include #include -#include #include #ifdef LOG_TAG @@ -66,7 +66,12 @@ extern "C" { mmi_workflow_link_nodes_by_names(workflow, NODE_NAME_MIC, "AUDIO", NODE_NAME_ASR, "AUDIO"); +#ifdef ENABLE_TEMP_RESCAN + mmi_workflow_link_nodes_by_names(workflow, NODE_NAME_ASR, "FINAL_ASR", "TEMP_RESCAN", "TEXT"); + mmi_workflow_link_nodes_by_names(workflow, "TEMP_RESCAN", "REJECTED", NODE_NAME_MATCH_MODE_COMMANDS, "TEXT"); +#elif mmi_workflow_link_nodes_by_names(workflow, NODE_NAME_ASR, "FINAL_ASR", NODE_NAME_MATCH_MODE_COMMANDS, "TEXT"); +#endif mmi_workflow_link_nodes_by_names(workflow, NODE_NAME_MATCH_MODE_COMMANDS, "MATCHED_CANDIDATE", NODE_NAME_VOICE_TOUCH_PROCESSOR, "MODE_COMMANDS"); mmi_workflow_link_nodes_by_names(workflow, NODE_NAME_MATCH_MODE_COMMANDS, "REJECTED", NODE_NAME_MATCH_PREDEFINED_COMMANDS, "TEXT"); @@ -77,13 +82,14 @@ extern "C" { #ifdef ENABLE_TEMP_RESCAN /* These are temporary links for rescanning the screen, it will be removed when the signal mechanism is ready */ - mmi_workflow_link_nodes_by_names(workflow, NODE_NAME_ASR, "FINAL_ASR", "TEMP_RESCAN", "TEXT"); mmi_workflow_link_nodes_by_names(workflow, "TEMP_RESCAN", "MATCHED_CANDIDATE", NODE_NAME_SCREEN_ANALYZER, "RESCAN"); #endif + // INFO: Attribute assigning mmi_workflow_attribute_assign(workflow, "PREDEFINED_COMMANDS", NODE_NAME_MATCH_PREDEFINED_COMMANDS, "CANDIDATES"); - + mmi_workflow_attribute_assign(workflow, "__MODE_COMMANDS", NODE_NAME_MATCH_MODE_COMMANDS, "CANDIDATES"); mmi_workflow_attribute_assign(workflow, "GRID_CONFIGURATION", NODE_NAME_VOICE_TOUCH_PROCESSOR, "GRID_CONFIGURATION"); + mmi_workflow_attribute_assign(workflow, "ASR_STOP_METHOD", NODE_NAME_ASR, "STOP_METHOD"); #ifdef ENABLE_TEMP_RESCAN /* These are temporary attributes for rescanning the screen, it will be removed when the signal mechanism is ready */ @@ -94,40 +100,34 @@ extern "C" { mmi_workflow_output_assign(workflow, "PARTIAL_RESULT", NODE_NAME_ASR, "PARTIAL_ASR"); mmi_workflow_output_assign(workflow, "FINAL_RESULT", NODE_NAME_ASR, "FINAL_ASR"); - mmi_workflow_output_assign(workflow, "MATCHED_CANDIDATE", NODE_NAME_MATCH_PREDEFINED_COMMANDS, "MATCHED_COMMAND"); + mmi_workflow_output_assign(workflow, "MATCHED_COMMAND", NODE_NAME_MATCH_PREDEFINED_COMMANDS, "MATCHED_CANDIDATE"); mmi_workflow_output_assign(workflow, "REJECTED", NODE_NAME_VOICE_TOUCH_PROCESSOR, "REJECTED"); mmi_workflow_output_assign(workflow, "CANDIDATES", NODE_NAME_VOICE_TOUCH_PROCESSOR, "CANDIDATES"); mmi_workflow_output_assign(workflow, "MATCHED_RESULT", NODE_NAME_VOICE_TOUCH_PROCESSOR, "MATCHED_RESULT"); - mmi_primitive_value_h primitive_array = nullptr; - mmi_primitive_value_create_array(&primitive_array); - - mmi_primitive_value_h predefined_command_grid = nullptr; - mmi_primitive_value_create_string("Grid", &predefined_command_grid); - mmi_primitive_value_add_array_element(primitive_array, predefined_command_grid); - - mmi_primitive_value_h predefined_command_number = nullptr; - mmi_primitive_value_create_string("Number", &predefined_command_number); - mmi_primitive_value_add_array_element(primitive_array, predefined_command_number); + const char *modes[] = { + "숫자 보여줘", + "텍스트 보여줘", + "그리드 보여줘", + }; mmi_attribute_h attribute = nullptr; - mmi_attribute_create(primitive_array, "PREDEFINED_COMMANDS", &attribute); - + mmi_attribute_create_string_array("__MODE_COMMANDS", modes, sizeof(modes) / sizeof(const char *), &attribute); mmi_workflow_attribute_set_default_value(workflow, attribute); - mmi_attribute_destroy(attribute); - mmi_primitive_value_destroy(primitive_array); #ifdef ENABLE_TEMP_RESCAN /* This is a temporary attribute for rescanning the screen, it will be removed when the signal mechanism is ready */ - mmi_primitive_value_h temp_rescan_command = nullptr; - mmi_primitive_value_create_string("Rescan", &temp_rescan_command); + const char *rescans[] = { + "새로고침", + "새로 고침", + }; + mmi_attribute_h temp_attribute = nullptr; - mmi_attribute_create(temp_rescan_command, "TEMP_RESCAN_COMMAND", &temp_attribute); + mmi_attribute_create_string_array("TEMP_RESCAN_COMMAND", rescans, sizeof(rescans) / sizeof(const char *), &temp_attribute); mmi_workflow_attribute_set_default_value(workflow, temp_attribute); mmi_attribute_destroy(temp_attribute); - mmi_primitive_value_destroy(temp_rescan_command); #endif mmi_standard_workflow_register(workflow); diff --git a/plugins/workflows/voice-touch/voice-touch.mws b/plugins/workflows/voice-touch/voice-touch.mws deleted file mode 100644 index c4daa81..0000000 --- a/plugins/workflows/voice-touch/voice-touch.mws +++ /dev/null @@ -1,19 +0,0 @@ -@workflow -name : VoiceTouch - -@node-list -[Source] MIC_AMBIENT as MIC -[Processor] ASR as ASR -[Logic] FIXED_STRING_MATCH as MATCH -[Logic] FIXED_STRING_MATCH as DUMMY - -@link-list -MIC.AUDIO -> ASR.AUDIO -ASR.FINAL_RESULT -> MATCH.TEXT -ASR.FINAL_RESULT -> DUMMY.TEXT - -@attribute-list -MATCH.CANDIDATES as COMMANDS - -@output-list -MATCH.MATCHED_CANDIDATE as COMMAND diff --git a/plugins/workflows/wakeupless-command/meson.build b/plugins/workflows/wakeupless-command/meson.build index 55c517b..2fc5a2a 100644 --- a/plugins/workflows/wakeupless-command/meson.build +++ b/plugins/workflows/wakeupless-command/meson.build @@ -2,12 +2,10 @@ mmi_module_wakeupless_command_library_srcs = [ 'mmi-module-wakeupless-command.cpp', ] -dlog_dep = dependency('dlog', method : 'pkg-config') ecore_dep = dependency('ecore', method : 'pkg-config') mmi_module_wakeupless_command_deps = [ mmi_declared_dep, - dlog_dep, ecore_dep, ] diff --git a/plugins/workflows/wakeupless-command/mmi-module-wakeupless-command.cpp b/plugins/workflows/wakeupless-command/mmi-module-wakeupless-command.cpp index 62d0070..c0379d3 100644 --- a/plugins/workflows/wakeupless-command/mmi-module-wakeupless-command.cpp +++ b/plugins/workflows/wakeupless-command/mmi-module-wakeupless-command.cpp @@ -1,11 +1,11 @@ #include +#include #include #include #include #include -#include #include #ifdef LOG_TAG @@ -13,16 +13,6 @@ #endif #define LOG_TAG "MMI-MODULE-WAKEUPLESS-COMMAND" -#define MMI_MODULE_LOG_(prio, tag, fmt, arg...) \ - ({ do { \ - dlog_print(prio, tag, "%s: %s(%d) > " fmt, __MODULE__, __func__, __LINE__, ##arg); \ - } while (0); }) - -#define _D(fmt, args...) MMI_MODULE_LOG_(DLOG_DEBUG, LOG_TAG, fmt, ##args) -#define _I(fmt, args...) MMI_MODULE_LOG_(DLOG_INFO, LOG_TAG, fmt, ##args) -#define _W(fmt, args...) MMI_MODULE_LOG_(DLOG_WARN, LOG_TAG, fmt, ##args) -#define _E(fmt, args...) MMI_MODULE_LOG_(DLOG_ERROR, LOG_TAG, fmt, ##args) - extern "C" { EXPORT_API void mmi_plugin_module_get_workflow_list() @@ -57,6 +47,8 @@ extern "C" { mmi_workflow_output_assign(workflow, "UTTERANCE", "ASR", "PARTIAL_ASR"); mmi_workflow_output_assign(workflow, "UTTERANCE", "ASR", "FINAL_ASR"); + mmi_workflow_signal_assign(workflow, "CONTROL", "ASR", "CONTROL"); + mmi_standard_workflow_register(workflow); mmi_node_destroy(node_mic); diff --git a/setup_linux_build.sh b/setup_linux_build.sh new file mode 100755 index 0000000..bf10d42 --- /dev/null +++ b/setup_linux_build.sh @@ -0,0 +1,5 @@ +meson setup --prefix=/usr/local/mmi \ + --bindir /usr/local/mmi/bin \ + --libdir /usr/local/mmi/lib \ + --datadir /usr/local/mmi/share \ + ./linux_build diff --git a/src/common/mmi-communication-channel.h b/src/common/mmi-communication-channel.h index c09948d..f915565 100644 --- a/src/common/mmi-communication-channel.h +++ b/src/common/mmi-communication-channel.h @@ -43,6 +43,7 @@ public: virtual int send(Message *message) = 0; }; +// LCOV_EXCL_START class CommunicationChannelManager : public CommunicationChannel, public SimpleEventObserver { public: @@ -55,20 +56,23 @@ public: CommunicationChannelClient() = default; virtual ~CommunicationChannelClient() = default; }; +// LCOV_EXCL_STOP struct CommunicationChannelManagerFactory { CommunicationChannelManagerFactory() = default; virtual ~CommunicationChannelManagerFactory() = default; - virtual std::shared_ptr create_channel() = 0; + virtual std::shared_ptr create_channel(); }; +// LCOV_EXCL_START struct CommunicationChannelClientFactory { CommunicationChannelClientFactory() = default; virtual ~CommunicationChannelClientFactory() = default; - virtual std::shared_ptr create_channel() = 0; + virtual std::shared_ptr create_channel(); }; +// LCOV_EXCL_STOP }; // namespace communication diff --git a/src/common/mmi-communication-message.h b/src/common/mmi-communication-message.h index 4fc7ca0..9eb6924 100644 --- a/src/common/mmi-communication-message.h +++ b/src/common/mmi-communication-message.h @@ -22,8 +22,6 @@ #include #include -#include - #include "mmi.h" namespace mmi { @@ -42,9 +40,11 @@ enum class CLIENT_MESSAGE_TYPE { WORKFLOW_INSTANCE_CREATE, WORKFLOW_INSTANCE_DESTROY, WORKFLOW_INSTANCE_SET_ATTRIBUTE, + WORKFLOW_INSTANCE_EMIT_SIGNAL, WORKFLOW_INSTANCE_ACTIVATE, WORKFLOW_INSTANCE_DEACTIVATE, /* Manager to Client */ + WORKFLOW_INSTANCE_OUTPUT, }; struct Message { @@ -78,6 +78,12 @@ struct ClientMessageWorkflowInstanceSetAttribute : public ClientMessage { mmi_attribute_h attribute{nullptr}; }; +struct ClientMessageWorkflowInstanceEmitSignal : public ClientMessage { + ClientMessageWorkflowInstanceEmitSignal() : ClientMessage{CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_EMIT_SIGNAL} {} + int local_workflow_instance_id{0}; + mmi_signal_h signal{nullptr}; +}; + struct ClientMessageWorkflowInstanceActivate : public ClientMessage { ClientMessageWorkflowInstanceActivate() : ClientMessage{CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_ACTIVATE} {} int local_workflow_instance_id{0}; @@ -88,6 +94,13 @@ struct ClientMessageWorkflowInstanceDeactivate : public ClientMessage { int local_workflow_instance_id{0}; }; +struct ClientMessageWorkflowInstanceOutput : public ClientMessage { + ClientMessageWorkflowInstanceOutput() : ClientMessage{CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_OUTPUT} {} + int local_workflow_instance_id{0}; + std::string source_name; + mmi_data_h data{nullptr}; +}; + }; // namespace communication }; // namespace mmi diff --git a/src/common/mmi-workflow-output-event.h b/src/common/mmi-workflow-output-event.h index 818b3e5..af09d14 100644 --- a/src/common/mmi-workflow-output-event.h +++ b/src/common/mmi-workflow-output-event.h @@ -17,10 +17,10 @@ #pragma once +#include "mmi-platform-config.h" #include "mmi-event-observer.h" #include -#include namespace mmi { @@ -39,10 +39,12 @@ struct WorkflowOutputEventOutputGenerated : public WorkflowOutputEvent { WorkflowOutputEventOutputGenerated() : WorkflowOutputEvent(WORKFLOW_OUTPUT_EVENT_TYPE::OUTPUT_GENERATED) {} virtual ~WorkflowOutputEventOutputGenerated() {} - bundle *data{nullptr}; std::string source_name; std::string client_id; int local_workflow_instance_id{0}; + + unsigned char *data_bytes{nullptr}; + size_t data_size{0}; }; }; // namespace mmi diff --git a/src/mmi-cli/meson.build b/src/mmi-cli/meson.build index 0512065..e90d46e 100644 --- a/src/mmi-cli/meson.build +++ b/src/mmi-cli/meson.build @@ -1,19 +1,25 @@ -dlog_dep = dependency('dlog', method : 'pkg-config') ecore_dep = dependency('ecore', method : 'pkg-config') -rpc_port_dep = dependency('rpc-port') +dl_dep = meson.get_compiler('c').find_library('dl', required : true) mmi_cli_deps = [ mmi_declared_dep, - dlog_dep, ecore_dep, - rpc_port_dep, + dl_dep, ] +foreach platform_specific_dependency : mmi_platform_specific_dependencies + message('Platform Specific Dependency : ' + platform_specific_dependency) + extra_dep = dependency(platform_specific_dependency, method : 'pkg-config') + mmi_cli_deps += extra_dep +endforeach + +mmi_extra_include_dir = ''.join(['../../', mmi_platform_specific_include_directory]) mmi_cli_include_dirs = include_directories( '.', '../common/', '../../capi/', '../../external/', + mmi_extra_include_dir, ) mmi_cli_declared_dep = declare_dependency( @@ -31,7 +37,7 @@ mmi_cli_program_deps = [ executable('mmi-cli', mmi_cli_program_srcs, - include_directories : [ mmi_cli_include_dirs ], + include_directories : [ mmi_cli_include_dirs], dependencies : [mmi_cli_program_deps], install_dir : mmi_prefix_bindir, install : true, diff --git a/src/mmi-cli/mmi-cli-node-tester.cpp b/src/mmi-cli/mmi-cli-node-tester.cpp index 3a4a9c4..2282f85 100644 --- a/src/mmi-cli/mmi-cli-node-tester.cpp +++ b/src/mmi-cli/mmi-cli-node-tester.cpp @@ -106,7 +106,7 @@ private: mmi_plugin_module_node_list_s m_node_list; std::map m_node_instance_map; - int m_node_instance_index{0}; + size_t m_node_instance_index{0}; }; static Program g_program; @@ -687,7 +687,7 @@ void Program::set_attribute(AttributeTestType type) { } } if (entry_index == static_cast(AttributeTestType::MaxCount)) { - _E("Failed to find attribute type: %d", type); + _E("Failed to find attribute type: %zu", static_cast(type)); return; } g_attribute_test_entries[entry_index].attribute_generator(this, &attribute); diff --git a/src/mmi-cli/mmi-cli.cpp b/src/mmi-cli/mmi-cli.cpp index d3e6963..adcaf4d 100644 --- a/src/mmi-cli/mmi-cli.cpp +++ b/src/mmi-cli/mmi-cli.cpp @@ -102,6 +102,36 @@ public: mmi_attribute_destroy(attribute); mmi_primitive_value_destroy(stop_method_value); } + void emit_signal() { + if (!m_instance) { + std::cout << "No instance to set attribute" << std::endl; + return; + } + + std::cout << "Emitting signal " << std::endl; + + mmi_primitive_value_h signal_parameter_value_1 = nullptr; + mmi_signal_parameter_h signal_parameter_1 = nullptr; + mmi_primitive_value_h signal_parameter_value_2 = nullptr; + mmi_signal_parameter_h signal_parameter_2 = nullptr; + mmi_signal_h signal = nullptr; + mmi_primitive_value_create_int(6, &signal_parameter_value_1); + mmi_signal_parameter_create(signal_parameter_value_1, + "signal_parameter_1", &signal_parameter_1); + mmi_primitive_value_create_int(3, &signal_parameter_value_2); + mmi_signal_parameter_create(signal_parameter_value_2, + "signal_parameter_2", &signal_parameter_2); + mmi_signal_create("CONTROL", &signal); + mmi_signal_add_parameter(signal, signal_parameter_1); + mmi_signal_add_parameter(signal, signal_parameter_2); + mmi_workflow_instance_emit_signal(m_instance, signal); + mmi_signal_destroy(signal); + mmi_signal_parameter_destroy(signal_parameter_1); + mmi_primitive_value_destroy(signal_parameter_value_1); + mmi_signal_parameter_destroy(signal_parameter_2); + mmi_primitive_value_destroy(signal_parameter_value_2); + } + static int state_changed_cb(mmi_state_e state, void *user_data) { Program *program = static_cast(user_data); @@ -146,6 +176,11 @@ int main(void) }, "Set attributes for the current workflow instance"); + rootMenu->Insert("emit_signal", [](std::ostream& out) { + g_program.emit_signal(); + }, + "Set attributes for the current workflow instance"); + rootMenu->Insert("activate", [](std::ostream& out) { g_program.activate_instance(); }, diff --git a/src/mmi-manager/main.cpp b/src/mmi-manager/main.cpp index 97c95c5..d5f79fb 100644 --- a/src/mmi-manager/main.cpp +++ b/src/mmi-manager/main.cpp @@ -24,18 +24,10 @@ #include #include "mmi-manager.h" -#include "mmi-ipc-tidl.h" #include "mmi-self-container.h" #include "adishavit/argh.h" -struct CommunicationChannelFactoryTIDL : - public mmi::communication::CommunicationChannelManagerFactory { - std::shared_ptr create_channel() override { - return std::make_shared(); - } -}; - static Ecore_Event_Handler *exit_signal_event_handler = nullptr; static Eina_Bool @@ -59,7 +51,7 @@ int main(int argc, char *argv[]) { plugin_module_proxy_factory = std::make_shared(); } - communication_channel_factory = std::make_shared(); + communication_channel_factory = std::make_shared(); mmi::Manager manager(communication_channel_factory, plugin_module_proxy_factory); diff --git a/src/mmi-manager/meson.build b/src/mmi-manager/meson.build index ecec178..30310c2 100644 --- a/src/mmi-manager/meson.build +++ b/src/mmi-manager/meson.build @@ -1,6 +1,5 @@ mmi_manager_library_srcs = [ 'mmi-manager.cpp', - 'mmi-ipc-tidl.cpp', 'mmi-client.cpp', 'mmi-common.cpp', 'mmi-data-gateway.cpp', @@ -17,39 +16,45 @@ mmi_manager_library_srcs = [ 'mmi-plugin-module-proxy.cpp', 'mmi-plugin-module-registry.cpp', 'mmi-self-container.cpp', - 'mmi_stub.c', ] -bundle_dep = dependency('bundle', method : 'pkg-config') -dlog_dep = dependency('dlog', method : 'pkg-config') +foreach platform_specific_manager_file : mmi_platform_specific_manager_files + message('Platform Specific File : ' + platform_specific_manager_file) + mmi_manager_library_srcs += platform_specific_manager_file +endforeach + ecore_dep = dependency('ecore', method : 'pkg-config') glib_dep = dependency('glib-2.0', method : 'pkg-config') -rpc_port_dep = dependency('rpc-port') -libtzplatform_config_dep = dependency('libtzplatform-config') +dl_dep = meson.get_compiler('c').find_library('dl', required : true) mmi_manager_deps = [ mmi_declared_dep, - bundle_dep, - dlog_dep, ecore_dep, glib_dep, - rpc_port_dep, - libtzplatform_config_dep, + dl_dep, ] +foreach platform_specific_dependency : mmi_platform_specific_dependencies + message('Platform Specific Dependency : ' + platform_specific_dependency) + extra_dep = dependency(platform_specific_dependency, method : 'pkg-config') + mmi_manager_deps += extra_dep +endforeach + +mmi_extra_include_dir = ''.join(['../../', mmi_platform_specific_include_directory]) mmi_manager_include_dirs = include_directories( '.', '../common/', '../../capi/', '../../external/', + mmi_extra_include_dir, ) mmi_manager_library = library('mmi_manager', mmi_manager_library_srcs, - include_directories : [ mmi_manager_include_dirs ], + include_directories : [mmi_manager_include_dirs], dependencies : [mmi_manager_deps], install_dir : mmi_prefix_libdir, - install : true + install : true, ) mmi_manager_declared_dep = declare_dependency( @@ -66,13 +71,15 @@ mmi_manager_program_deps = [ mmi_manager_declared_dep ] +message('prefix') +message(mmi_prefix) executable('mmi-manager', mmi_manager_program_srcs, - include_directories : [ mmi_manager_include_dirs ], + include_directories : [ mmi_manager_include_dirs], dependencies : [mmi_manager_program_deps], install_dir : mmi_prefix_bindir, install : true, - pie : true + pie : true, ) install_data('mmi-manager.xml', install_dir:'/usr/share/packages/') diff --git a/src/mmi-manager/mmi-client.cpp b/src/mmi-manager/mmi-client.cpp index 3135075..6c7ab41 100644 --- a/src/mmi-manager/mmi-client.cpp +++ b/src/mmi-manager/mmi-client.cpp @@ -24,7 +24,6 @@ #include "mmi-client.h" #include "mmi-common.h" #include "mmi-manager-log.h" -#include "mmi_stub.h" namespace mmi { @@ -34,6 +33,7 @@ ClientManager::ClientManager() { ClientManager::~ClientManager() { } +// LCOV_EXCL_START void ClientManager::on_observer_event( const COMMUNICATION_CHANNEL_EVENT_TYPE &event, std::any data) { try { @@ -48,6 +48,7 @@ void ClientManager::on_observer_event( LOGE("Failed to cast message data: %s", e.what()); } } +// LCOV_EXCL_STOP int ClientManager::initialize() { return MMI_ERROR_NONE; diff --git a/src/mmi-manager/mmi-client.h b/src/mmi-manager/mmi-client.h index 50e1c1e..c3af26a 100644 --- a/src/mmi-manager/mmi-client.h +++ b/src/mmi-manager/mmi-client.h @@ -33,7 +33,6 @@ #include "mmi-common.h" #include "mmi-communication-channel.h" -#include "mmi_stub.h" namespace mmi { diff --git a/src/mmi-manager/mmi-common.h b/src/mmi-manager/mmi-common.h index 3fc6ad1..08cb1d7 100644 --- a/src/mmi-manager/mmi-common.h +++ b/src/mmi-manager/mmi-common.h @@ -25,7 +25,7 @@ #define __MMI_COMMON_H__ #include -#include +#include "mmi-platform-config.h" #ifndef MMI_API #define MMI_API __attribute__ ((visibility("default"))) diff --git a/src/mmi-manager/mmi-ipc-ecore.cpp b/src/mmi-manager/mmi-ipc-ecore.cpp new file mode 100644 index 0000000..b2e6780 --- /dev/null +++ b/src/mmi-manager/mmi-ipc-ecore.cpp @@ -0,0 +1,350 @@ +#include "mmi-ipc-ecore.h" + +#include + +namespace mmi { + +namespace communication { + +std::shared_ptr +mmi::communication::CommunicationChannelManagerFactory::create_channel() { + return std::make_shared(); +} + +CommunicationChannelEcoreIPC::CommunicationChannelEcoreIPC() { + if (!ecore_ipc_init()) { + _E("Ecore IPC init failed"); + } +} + +CommunicationChannelEcoreIPC::~CommunicationChannelEcoreIPC() { + if (!ecore_ipc_shutdown()) { + _E("Ecore IPC shutdown failed"); + } +} + +int CommunicationChannelEcoreIPC::connect() { + if (m_server) { + return MMI_ERROR_OPERATION_FAILED; + } + m_server = ecore_ipc_server_add(ECORE_IPC_REMOTE_SYSTEM, "localhost", 9999, this); + ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_ADD, handler_client_add, this); + ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_DEL, handler_client_del, this); + ecore_event_handler_add(ECORE_IPC_EVENT_CLIENT_DATA, handler_client_data, this); + return 0; +} + +int CommunicationChannelEcoreIPC::disconnect(void) { + if (m_server) { + ecore_ipc_server_del(m_server); + m_server = nullptr; + } + return 0; +} + +int CommunicationChannelEcoreIPC::send(Message *message) { + if (!message) { + _E("Message object is NULL"); + return MMI_ERROR_INVALID_PARAMETER; + } + + auto client = m_clients.find(message->sender); + if (client != m_clients.end()) { + const char *msg = "test message from server"; + ecore_ipc_client_send(client->second, 0, 0, 0, 0, 0, msg, strlen(msg)); + } else { + _E("Client with sender information %s does not exist", message->sender.c_str()) + } + return 0; +} + +void CommunicationChannelEcoreIPC::on_observer_event( + const WORKFLOW_OUTPUT_EVENT_TYPE &event, std::any data) +{ + try { + WorkflowOutputEventOutputGenerated *output_generated = std::any_cast(data); + if (!output_generated) { + LOGE("Failed to get output generated data !"); + return; + } + size_t byte_size = 0; + byte_size += sizeof(int); // local_workflow_instance_id + byte_size += sizeof(size_t); // source_name_length + byte_size += output_generated->source_name.length(); // source_name + byte_size += sizeof(size_t); // data_size + byte_size += output_generated->data_size; // data_bytes + + unsigned char *bytes = (unsigned char*)(malloc(byte_size)); + int index = 0; + memcpy(bytes + index, &(output_generated->local_workflow_instance_id), sizeof(int)); + index += sizeof(int); + + size_t source_name_length = output_generated->source_name.length(); + memcpy(bytes + index, &source_name_length, sizeof(size_t)); + index += sizeof(size_t); + memcpy(bytes + index, output_generated->source_name.c_str(), source_name_length); + index += source_name_length; + + memcpy(bytes + index, &(output_generated->data_size), sizeof(size_t)); + index += sizeof(size_t); + memcpy(bytes + index, output_generated->data_bytes, output_generated->data_size); + index += output_generated->data_size; + + const auto &client = m_clients.find(output_generated->client_id); + if (client != m_clients.end()) { + ecore_ipc_client_send(client->second, 0, 0, 0, 0, 0, bytes, byte_size); + } + + free(bytes); + } catch (const std::bad_any_cast &e) { + LOGE("Failed to cast message data: %s", e.what()); + } +} + +Eina_Bool CommunicationChannelEcoreIPC::handler_client_add(void *data, int ev_type, void *ev) +{ + Ecore_Ipc_Event_Client_Add *e = (Ecore_Ipc_Event_Client_Add *)ev; + _I("Client Added : %p", e->client); + + CommunicationChannelEcoreIPC *channel = static_cast(data); + if (channel) { + channel->on_client_added(e->client); + } + + return EINA_TRUE; +} + +void CommunicationChannelEcoreIPC::on_client_added(Ecore_Ipc_Client *client) +{ + std::stringstream ss; + ss << client; + std::string sender = ss.str(); + auto exists = m_clients.find(sender); + if (exists != m_clients.end()) { + _E("Client with same sender string exists!!!, overwriting : %s", sender.c_str()); + } + m_clients[sender] = client; + m_connected = true; + notify_observers( + COMMUNICATION_CHANNEL_EVENT_TYPE::CONNECTED, + sender); +} + +Eina_Bool CommunicationChannelEcoreIPC::handler_client_del(void *data, int ev_type, void *ev) +{ + Ecore_Ipc_Event_Client_Del *e = (Ecore_Ipc_Event_Client_Del *)ev; + LOGI("Client Deleted : %p", e->client); + + CommunicationChannelEcoreIPC *channel = static_cast(data); + if (channel) { + channel->on_client_deleted(e->client); + } + return EINA_TRUE; +} + +void CommunicationChannelEcoreIPC::on_client_deleted(Ecore_Ipc_Client *client) +{ + std::stringstream ss; + ss << client; + std::string sender = ss.str(); + m_clients.erase(sender); + m_connected = false; + notify_observers( + COMMUNICATION_CHANNEL_EVENT_TYPE::DISCONNECTED, + sender); +} + +Eina_Bool CommunicationChannelEcoreIPC::handler_client_data(void *data, int ev_type, void *ev) +{ + Ecore_Ipc_Event_Client_Data *e = (Ecore_Ipc_Event_Client_Data*)ev; + LOGI("Client Data Received : %p", e->client); + + CommunicationChannelEcoreIPC *channel = static_cast(data); + if (channel) { + channel->on_client_message(e->client, e->data, e->size); + } + return EINA_TRUE; +} + +void CommunicationChannelEcoreIPC::on_client_message(Ecore_Ipc_Client *client, void *data, int size) +{ + if (size < sizeof(CLIENT_MESSAGE_TYPE)) { + _E("Data Size too small : %d", size) + return; + } + + std::stringstream ss; + ss << client; + std::string sender = ss.str(); + + CLIENT_MESSAGE_TYPE type; + memcpy(&type, data, sizeof(CLIENT_MESSAGE_TYPE)); + + switch(type) + { + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_CREATE: + { + struct workflow_instance_create_payload { + int local_workflow_instance_id; + mmi_standard_workflow_type_e workflow_type; + } payload; + if (size < sizeof(CLIENT_MESSAGE_TYPE) + sizeof(payload)) { + _E("Data Size too small : %d", size) + return; + } + memcpy(&payload, data + sizeof(CLIENT_MESSAGE_TYPE), sizeof(payload)); + ClientMessageWorkflowInstanceCreate message; + message.sender = sender; + message.local_workflow_instance_id = payload.local_workflow_instance_id; + message.workflow_type = payload.workflow_type; + notify_observers( + COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, + static_cast(&message)); + } + break; + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_DESTROY: + { + struct workflow_instance_destroy_payload { + int local_workflow_instance_id; + } payload; + if (size < sizeof(CLIENT_MESSAGE_TYPE) + sizeof(payload)) { + _E("Data Size too small : %d", size) + return; + } + memcpy(&payload, data + sizeof(CLIENT_MESSAGE_TYPE), sizeof(payload)); + ClientMessageWorkflowInstanceDestroy message; + message.sender = sender; + message.local_workflow_instance_id = payload.local_workflow_instance_id; + notify_observers( + COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, + static_cast(&message)); + } + break; + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_SET_ATTRIBUTE: + { + struct workflow_instance_set_attribute_payload { + int local_workflow_instance_id; + char attribute_name[MMI_NAME_MAX_LENGTH]; + size_t value_size; + } payload; + if (size < sizeof(CLIENT_MESSAGE_TYPE) + sizeof(payload)) { + _E("Data Size too small : %d", size) + return; + } + + memcpy(&payload, data + sizeof(CLIENT_MESSAGE_TYPE), sizeof(payload)); + mmi_primitive_value_h value = nullptr; + int index = sizeof(CLIENT_MESSAGE_TYPE) + sizeof(payload); + mmi_primitive_value_from_bytes((unsigned char *)data + index, payload.value_size, &value); + + mmi_attribute_h attribute = nullptr; + mmi_attribute_create(value, payload.attribute_name, &attribute); + + ClientMessageWorkflowInstanceSetAttribute message; + message.sender = sender; + message.local_workflow_instance_id = payload.local_workflow_instance_id; + message.attribute = attribute; + notify_observers( + COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, + static_cast(&message)); + + mmi_attribute_destroy(attribute); + mmi_primitive_value_destroy(value); + } + break; + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_EMIT_SIGNAL: + { + struct workflow_instance_emit_signal_payload { + int local_workflow_instance_id; + char signal_name[MMI_NAME_MAX_LENGTH]; + int signal_parameter_count; + } payload; + if (size < sizeof(CLIENT_MESSAGE_TYPE) + sizeof(payload)) { + _E("Data Size too small : %d", size) + return; + } + memcpy(&payload, data + sizeof(CLIENT_MESSAGE_TYPE), sizeof(payload)); + int index = sizeof(CLIENT_MESSAGE_TYPE) + sizeof(payload); + _D("Signal Name %s, Parameter Count : %d", payload.signal_name, payload.signal_parameter_count); + + mmi_signal_h signal; + mmi_signal_create(payload.signal_name, &signal); + + for (int loop = 0;loop < payload.signal_parameter_count;loop++) { + char parameter_name[MMI_NAME_MAX_LENGTH]; + memcpy(parameter_name, data + index, MMI_NAME_MAX_LENGTH); + index += MMI_NAME_MAX_LENGTH; + + _D("Parameter Name : %s", parameter_name); + + int value_size = 0; + memcpy(&value_size, data + index, sizeof(int)); + index += sizeof(int); + + mmi_primitive_value_h value; + mmi_primitive_value_from_bytes((unsigned char*)data + index, value_size, &value); + index += value_size; + + mmi_signal_parameter_h parameter; + mmi_signal_parameter_create(value, parameter_name, ¶meter); + + mmi_signal_add_parameter(signal, parameter); + + mmi_signal_parameter_destroy(parameter); + mmi_primitive_value_destroy(value); + } + + ClientMessageWorkflowInstanceEmitSignal message; + message.sender = sender; + message.local_workflow_instance_id = payload.local_workflow_instance_id; + message.signal = signal; + notify_observers( + COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, + static_cast(&message)); + + mmi_signal_destroy(signal); + } + break; + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_ACTIVATE: + { + struct workflow_instance_activate_payload { + int local_workflow_instance_id; + } payload; + if (size < sizeof(CLIENT_MESSAGE_TYPE) + sizeof(payload)) { + _E("Data Size too small : %d", size) + return; + } + memcpy(&payload, data + sizeof(CLIENT_MESSAGE_TYPE), sizeof(payload)); + ClientMessageWorkflowInstanceActivate message; + message.sender = sender; + message.local_workflow_instance_id = payload.local_workflow_instance_id; + notify_observers( + COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, + static_cast(&message)); + } + break; + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_DEACTIVATE: + { + struct workflow_instance_deactivate_payload { + int local_workflow_instance_id; + } payload; + if (size < sizeof(CLIENT_MESSAGE_TYPE) + sizeof(payload)) { + _E("Data Size too small : %d", size) + return; + } + memcpy(&payload, data + sizeof(CLIENT_MESSAGE_TYPE), sizeof(payload)); + ClientMessageWorkflowInstanceDeactivate message; + message.sender = sender; + message.local_workflow_instance_id = payload.local_workflow_instance_id; + notify_observers( + COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, + static_cast(&message)); + } + break; + } +} + +}; // namespace communication + +}; // namespace mmi + diff --git a/src/mmi-manager/mmi-ipc-ecore.h b/src/mmi-manager/mmi-ipc-ecore.h new file mode 100644 index 0000000..87e6396 --- /dev/null +++ b/src/mmi-manager/mmi-ipc-ecore.h @@ -0,0 +1,43 @@ +#pragma once + +#include + +#include +#include + +#include "mmi-communication-channel.h" + +namespace mmi { + +namespace communication { + +class CommunicationChannelEcoreIPC : public CommunicationChannelManager { +public: + CommunicationChannelEcoreIPC(); + ~CommunicationChannelEcoreIPC(); + + int connect() override; + int disconnect(void) override; + int send(Message *message) override; + + void on_observer_event( + const WORKFLOW_OUTPUT_EVENT_TYPE &event, std::any data) override; +private: + static Eina_Bool handler_client_add(void *data, int ev_type, void *ev); + static Eina_Bool handler_client_del(void *data, int ev_type, void *ev); + static Eina_Bool handler_client_data(void *data, int ev_type, void *ev); + + void on_client_added(Ecore_Ipc_Client *client); + void on_client_deleted(Ecore_Ipc_Client *client); + void on_client_message(Ecore_Ipc_Client *client, void* data, int size); + +private: + Ecore_Ipc_Server *m_server{nullptr}; + bool m_connected{false}; + std::map m_clients; +}; + +}; // namespace communication + +}; // namespace mmi + diff --git a/src/mmi-manager/mmi-ipc-tidl.cpp b/src/mmi-manager/mmi-ipc-tidl.cpp index a3f2325..70f571a 100644 --- a/src/mmi-manager/mmi-ipc-tidl.cpp +++ b/src/mmi-manager/mmi-ipc-tidl.cpp @@ -37,12 +37,17 @@ namespace mmi { namespace communication { +std::shared_ptr CommunicationChannelManagerFactory ::create_channel() { + return std::make_shared(); +} + CommunicationChannelTIDL::CommunicationChannelTIDL() { } CommunicationChannelTIDL::~CommunicationChannelTIDL() { } +// LCOV_EXCL_START int CommunicationChannelTIDL::connect() { int r; LOGD("mmi_api_handler_initialize"); @@ -64,6 +69,7 @@ int CommunicationChannelTIDL::connect() { workflow_instance_create, workflow_instance_destroy, workflow_instance_set_attribute, + workflow_instance_emit_signal, workflow_instance_activate, workflow_instance_deactivate, workflow_instance_register_result_callback, @@ -242,6 +248,67 @@ int CommunicationChannelTIDL::workflow_instance_set_attribute(rpc_port_stub_mmi_ return MMI_ERROR_NONE; } +int CommunicationChannelTIDL::workflow_instance_emit_signal(rpc_port_stub_mmi_context_h context, + int local_workflow_instance_id, bundle *signal, void *user_data) { + CommunicationChannelTIDL *channel = static_cast(user_data); + + std::string sender; + if (!get_sender_string(context, channel, sender)) + return MMI_ERROR_INVALID_PARAMETER; + + char *name = nullptr; + bundle_get_str(signal, "name", &name); + + int *parameter_count = nullptr; + size_t byte_size; + bundle_get_byte(signal, "parameter_count", (void**)¶meter_count, &byte_size); + + mmi_signal_h restored_signal; + mmi_signal_create(name, &restored_signal); + + for (int loop = 0; loop < *parameter_count; loop++) + { + std::string name_string = std::string("parameter_name_") + std::to_string(loop); + + char *parameter_name; + bundle_get_str(signal, name_string.c_str(), ¶meter_name); + + _D("Parameter Name : %s", parameter_name); + + std::string size_string = std::string("parameter_size_") + std::to_string(loop); + + size_t *value_size = nullptr; + bundle_get_byte(signal, size_string.c_str(), (void **)&value_size, &byte_size); + + std::string data_string = std::string("parameter_data_") + std::to_string(loop); + + unsigned char *value_bytes = nullptr; + bundle_get_byte(signal, data_string.c_str(), (void **)&value_bytes, &byte_size); + + mmi_primitive_value_h value; + mmi_primitive_value_from_bytes(value_bytes, *value_size, &value); + + mmi_signal_parameter_h parameter; + mmi_signal_parameter_create(value, parameter_name, ¶meter); + + mmi_signal_add_parameter(restored_signal, parameter); + + mmi_signal_parameter_destroy(parameter); + mmi_primitive_value_destroy(value); + } + + ClientMessageWorkflowInstanceEmitSignal msg; + msg.sender = sender; + msg.local_workflow_instance_id = local_workflow_instance_id; + msg.signal = restored_signal; + + notify_message_received(channel, static_cast(&msg)); + + mmi_signal_destroy(restored_signal); + + return MMI_ERROR_NONE; +} + int CommunicationChannelTIDL::workflow_instance_activate(rpc_port_stub_mmi_context_h context, int local_workflow_instance_id, void *user_data) { CommunicationChannelTIDL *channel = static_cast(user_data); @@ -297,16 +364,24 @@ void CommunicationChannelTIDL::on_observer_event( const WORKFLOW_OUTPUT_EVENT_TYPE &event, std::any data) { try { WorkflowOutputEventOutputGenerated *output_generated = std::any_cast(data); - + if (!output_generated) { + LOGE("Failed to get output generated data !"); + return; + } + rpc_port_stub_mmi_result_cb_h callback = get_invoke_callbacks(output_generated->client_id, output_generated->local_workflow_instance_id); std::string source_name = output_generated->source_name; - bundle *data_b = reinterpret_cast(output_generated->data); - int ret = rpc_port_stub_mmi_result_cb_invoke(callback, source_name.c_str(), data_b); + bundle *encoded = bundle_create(); + bundle_add_byte(encoded, "data", output_generated->data_bytes, output_generated->data_size); + + int ret = rpc_port_stub_mmi_result_cb_invoke(callback, source_name.c_str(), encoded); if (ret != RPC_PORT_ERROR_NONE) { LOGE("Failed to send result to client !"); } + + bundle_free(encoded); } catch (const std::bad_any_cast &e) { LOGE("Failed to cast message data: %s", e.what()); } @@ -334,6 +409,7 @@ void CommunicationChannelTIDL::clear_invoke_callbacks() { } m_invoke_callbacks.clear(); } +// LCOV_EXCL_STOP } // namespace communication // diff --git a/src/mmi-manager/mmi-ipc-tidl.h b/src/mmi-manager/mmi-ipc-tidl.h index 9117ece..22c32cc 100644 --- a/src/mmi-manager/mmi-ipc-tidl.h +++ b/src/mmi-manager/mmi-ipc-tidl.h @@ -50,17 +50,19 @@ private: static void on_terminate(rpc_port_stub_mmi_context_h context, void *user_data); static int workflow_instance_create(rpc_port_stub_mmi_context_h context, - int local_workflow_instance_id, int workflow_type, void *user_data); + int local_workflow_instance_id, int workflow_type, void *user_data); static int workflow_instance_destroy(rpc_port_stub_mmi_context_h context, - int local_workflow_instance_id, void *user_data); + int local_workflow_instance_id, void *user_data); static int workflow_instance_set_attribute(rpc_port_stub_mmi_context_h context, - int workflow_instance, bundle *attribute, void *user_data); + int workflow_instance, bundle *attribute, void *user_data); + static int workflow_instance_emit_signal(rpc_port_stub_mmi_context_h context, + int workflow_instance, bundle *signal, void *user_data); static int workflow_instance_activate(rpc_port_stub_mmi_context_h context, - int local_workflow_instance_id, void *user_data); + int local_workflow_instance_id, void *user_data); static int workflow_instance_deactivate(rpc_port_stub_mmi_context_h context, - int local_workflow_instance_id, void *user_data); + int local_workflow_instance_id, void *user_data); static int workflow_instance_register_result_callback(rpc_port_stub_mmi_context_h context, - int local_workflow_instance_id, rpc_port_stub_mmi_result_cb_h callback, void *user_data); + int local_workflow_instance_id, rpc_port_stub_mmi_result_cb_h callback, void *user_data); void set_invoke_callbacks(std::string appid, int local_workflow_instance_id, rpc_port_stub_mmi_result_cb_h callback); diff --git a/src/mmi-manager/mmi-manager-log.h b/src/mmi-manager/mmi-manager-log.h index 51afe9c..accce89 100644 --- a/src/mmi-manager/mmi-manager-log.h +++ b/src/mmi-manager/mmi-manager-log.h @@ -24,7 +24,9 @@ #ifndef __MMI_MANAGER_LOG_H__ #define __MMI_MANAGER_LOG_H__ -#include +#include "mmi-platform-config.h" + +#include "magic_enum/magic_enum.hpp" #ifdef LOG_TAG #undef LOG_TAG @@ -47,4 +49,9 @@ #define _W LOGW #endif +template +static std::string enum_to_string(T value) { + return std::string(magic_enum::enum_name(value)); +} + #endif // __MMI_MANAGER_LOG_H__ diff --git a/src/mmi-manager/mmi-node-instance-manager.cpp b/src/mmi-manager/mmi-node-instance-manager.cpp index ab07751..00178d0 100644 --- a/src/mmi-manager/mmi-node-instance-manager.cpp +++ b/src/mmi-manager/mmi-node-instance-manager.cpp @@ -57,6 +57,7 @@ std::shared_ptr NodeInstanceManager::create_node_instance( return ret; } +// LCOV_EXCL_START bool NodeInstanceManager::destroy_node_instance( std::shared_ptr node_instance) { if (node_instance) { @@ -114,6 +115,7 @@ bool NodeInstanceManager::link_node_instances( return true; } +// LCOV_EXCL_STOP void NodeInstanceManager::initialize() { } @@ -131,6 +133,7 @@ void NodeInstanceManager::set_plugin_module_proxy_provider( m_plugin_module_proxy_provider = plugin_module_proxy_provider; } +// LCOV_EXCL_START void NodeInstanceManager::set_port_instance_manager( std::shared_ptr port_instance_manager) { m_port_instance_manager = port_instance_manager; @@ -144,7 +147,6 @@ void NodeInstanceManager::on_observer_event( if (output_generated) { PortInstance *port_instance = reinterpret_cast(output_generated->port_instance); if (port_instance) { - _D("Output generated for %p : %p", port_instance, output_generated->data); port_instance->on_output_data_generated(output_generated->data); } } @@ -168,6 +170,7 @@ void NodeInstanceManager::on_observer_event( LOGE("Failed to cast message data: %s", e.what()); } } +// LCOV_EXCL_STOP } // namespace mmi diff --git a/src/mmi-manager/mmi-node-instance.cpp b/src/mmi-manager/mmi-node-instance.cpp index 8c4c6db..f754f2a 100644 --- a/src/mmi-manager/mmi-node-instance.cpp +++ b/src/mmi-manager/mmi-node-instance.cpp @@ -32,11 +32,13 @@ NodeInstance::NodeInstance( mmi_standard_node_sub_type_e node_sub_type) : m_node_type(node_type) , m_node_sub_type(node_sub_type) { - _D("Node instance is created : %d %d", m_node_type, to_int(m_node_sub_type)); + _D("Node instance is created : %s %s", + enum_to_string(m_node_type).c_str(), to_string(m_node_sub_type).c_str()); } NodeInstance::~NodeInstance() { - _D("Node instance is destroyed : %d %d", m_node_type, to_int(m_node_sub_type)); + _D("Node instance is destroyed : %s %s", + enum_to_string(m_node_type).c_str(), to_string(m_node_sub_type).c_str()); } static bool node_type_and_subtype_matches( @@ -67,6 +69,10 @@ static bool node_type_and_subtype_matches( mmi_standard_node_controller_type_e controller_type; mmi_standard_node_get_controller_type(node, &controller_type); return controller_type == std::get(node_sub_type); + } else if (node_type == MMI_STANDARD_NODE_TYPE_ACTION) { + mmi_standard_node_action_type_e action_type; + mmi_standard_node_get_action_type(node, &action_type); + return action_type == std::get(node_sub_type); } } catch (const std::bad_variant_access &e) { _E("Failed to get node sub type : %s", e.what()); @@ -122,14 +128,15 @@ bool NodeInstance::initialize() { } } - _D("Node instance is initialized for %d %d", - m_node_type, to_int(m_node_sub_type)); + _D("Node instance is initialized for %s %s", + enum_to_string(m_node_type).c_str(), to_string(m_node_sub_type).c_str()); if (m_port_instance_manager == nullptr) { _E("Port instance manager is not set"); return false; } +// LCOV_EXCL_START mmi_plugin_module_node_instance_info_s plugin_module_node_instance_info; plugin_module_node_instance_info.node = static_cast(this); plugin_module_node_instance_info.port_info_count = 0; @@ -174,6 +181,7 @@ bool NodeInstance::initialize() { if (m_callbacks.initialized_cb != nullptr) { m_callbacks.initialized_cb(static_cast(this)); } +// LCOV_EXCL_STOP return true; } @@ -183,7 +191,9 @@ bool NodeInstance::deinitialize() { m_callbacks.deinitialized_cb(static_cast(this)); } - m_plugin_module_proxy->remove_node_instance_info(static_cast(this)); + if (m_plugin_module_proxy) { + m_plugin_module_proxy->remove_node_instance_info(static_cast(this)); + } return true; } @@ -280,6 +290,7 @@ std::shared_ptr NodeInstance::get_plugin_module_proxy() { return m_plugin_module_proxy; } +// LCOV_EXCL_START bool NodeInstance::set_attribute(mmi_attribute_h attribute) { char *name = nullptr; @@ -294,7 +305,22 @@ bool NodeInstance::set_attribute(mmi_attribute_h attribute) m_callbacks.attribute_set_cb(static_cast(this), attribute); return true; } +// LCOV_EXCL_STOP + +bool NodeInstance::handle_signal(mmi_signal_h signal) +{ + char *name = nullptr; + mmi_signal_get_name(signal, &name); + _D("Set signal : %s [%p]", name, signal); + free(name); + if (m_callbacks.signal_received_cb == nullptr) { + _E("Set signal callback is not set"); + return false; + } + m_callbacks.signal_received_cb(static_cast(this), signal); + return true; +} } // namespace mmi diff --git a/src/mmi-manager/mmi-node-instance.h b/src/mmi-manager/mmi-node-instance.h index 5e7e9bf..99c66f5 100644 --- a/src/mmi-manager/mmi-node-instance.h +++ b/src/mmi-manager/mmi-node-instance.h @@ -65,7 +65,8 @@ public: std::shared_ptr get_port_instance(std::string name); std::shared_ptr get_plugin_module_proxy(); - bool set_attribute(mmi_attribute_h attribute); + virtual bool set_attribute(mmi_attribute_h attribute); + virtual bool handle_signal(mmi_signal_h signal); protected: std::shared_ptr m_prototype_store; std::shared_ptr m_plugin_module_proxy_provider; diff --git a/src/mmi-manager/mmi-node-prototype.cpp b/src/mmi-manager/mmi-node-prototype.cpp index 2a6aa31..8926170 100644 --- a/src/mmi-manager/mmi-node-prototype.cpp +++ b/src/mmi-manager/mmi-node-prototype.cpp @@ -66,6 +66,13 @@ bool NodePrototype::is_valid() { std::get(m_sub_type.value()); valid = true; } + break; + case mmi_standard_node_type_e::MMI_STANDARD_NODE_TYPE_ACTION: { + auto subclass = + std::get(m_sub_type.value()); + valid = true; + } + break; } } catch (const std::bad_variant_access& e) { _E("[std::bad_variant_access] Failed to create node prototype: %s", e.what()); diff --git a/src/mmi-manager/mmi-node-prototype.h b/src/mmi-manager/mmi-node-prototype.h index 9273134..2870d2f 100644 --- a/src/mmi-manager/mmi-node-prototype.h +++ b/src/mmi-manager/mmi-node-prototype.h @@ -30,7 +30,9 @@ #include "mmi-node-processor.h" #include "mmi-node-logic.h" #include "mmi-node-controller.h" +#include "mmi-node-action.h" #include "mmi-plugin-module-proxy.h" +#include "mmi-manager-log.h" #include #include @@ -44,20 +46,21 @@ typedef std::variant< mmi_standard_node_source_type_e, mmi_standard_node_processor_type_e, mmi_standard_node_logic_type_e, - mmi_standard_node_controller_type_e + mmi_standard_node_controller_type_e, + mmi_standard_node_action_type_e > mmi_standard_node_sub_type_e; -static int to_int(mmi_standard_node_sub_type_e sub_type) { +static std::string to_string(mmi_standard_node_sub_type_e sub_type) { try { - return std::visit([](auto&& arg) -> int { + return std::visit([](auto&& arg) -> std::string { using T = std::decay_t; if constexpr (std::is_same_v) - return -1; + return std::string("Unknown"); else - return static_cast(arg); + return enum_to_string(arg); }, sub_type); } catch (std::bad_variant_access&) { - return -1; + return std::string("Unknown"); } } diff --git a/src/mmi-manager/mmi-plugin-module-proxy.cpp b/src/mmi-manager/mmi-plugin-module-proxy.cpp index b9682dc..6cadc29 100644 --- a/src/mmi-manager/mmi-plugin-module-proxy.cpp +++ b/src/mmi-manager/mmi-plugin-module-proxy.cpp @@ -28,6 +28,7 @@ namespace mmi { +// LCOV_EXCL_START static void port_instance_output_handler(mmi_port_instance_h port, mmi_data_h data, void *user_data) { PluginModuleProxySharedLibrary* proxy = static_cast(user_data); if (proxy == nullptr) { @@ -208,6 +209,7 @@ void PluginModuleProxySharedLibrary::add_node_instance_info(mmi_plugin_module_no void PluginModuleProxySharedLibrary::remove_node_instance_info(mmi_node_instance_h node_instance) { mmi_plugin_storage_remove_node_instance_info(node_instance); } +// LCOV_EXCL_STOP } // namespace mmi diff --git a/src/mmi-manager/mmi-plugin-module-proxy.h b/src/mmi-manager/mmi-plugin-module-proxy.h index f02002e..1a56c43 100644 --- a/src/mmi-manager/mmi-plugin-module-proxy.h +++ b/src/mmi-manager/mmi-plugin-module-proxy.h @@ -100,7 +100,7 @@ struct IPluginModuleProxyFactory : public SimpleEventObservable get_plugin_module_list() override { - const std::string plugin_module_path{"/usr/share/mmi/plugins"}; + const std::string plugin_module_path{MMI_INSTALL_PREFIX "/share/mmi/plugins"}; std::vector plugin_module_list; for (const auto & entry : std::filesystem::directory_iterator(plugin_module_path)) { PluginModuleInfo info{mmi_plugin_module_type_e::SHARED_LIBRARY, entry.path().string()}; diff --git a/src/mmi-manager/mmi-plugin-module-registry.cpp b/src/mmi-manager/mmi-plugin-module-registry.cpp index 0f19279..29e0b8f 100644 --- a/src/mmi-manager/mmi-plugin-module-registry.cpp +++ b/src/mmi-manager/mmi-plugin-module-registry.cpp @@ -98,6 +98,12 @@ static std::shared_ptr create_node_prototype(mmi_node_h node) { prototype->set_sub_type(controller_type); break; } + case MMI_STANDARD_NODE_TYPE_ACTION: { + mmi_standard_node_action_type_e action_type; + mmi_standard_node_get_action_type(node, &action_type); + prototype->set_sub_type(action_type); + break; + } } size_t port_count; @@ -146,7 +152,10 @@ bool PluginModuleRegistry::load_node_prototypes() { if (prototype) { prototype->set_plugin_module_info(plugin_module_info); bool ret = m_node_prototype_store->add_node_prototype(prototype); - _D("Add Node Prototype ret(%d): %d %d %s", ret, prototype->get_type(), to_int(prototype->get_sub_type()), plugin_module_info.plugin_module_identifier.c_str()); + _D("Add Node Prototype ret(%d): %s %s %s", ret, + enum_to_string(prototype->get_type()).c_str(), + to_string(prototype->get_sub_type()).c_str(), + plugin_module_info.plugin_module_identifier.c_str()); } } } else { @@ -202,6 +211,12 @@ static std::shared_ptr create_workflow_prototype(mmi_workflow node_info.node_sub_type = controller_type; } break; + case MMI_STANDARD_NODE_TYPE_ACTION: { + mmi_standard_node_action_type_e action_type; + mmi_standard_node_get_action_type(workflow_info->node_infos[i].node, &action_type); + node_info.node_sub_type = action_type; + } + break; default: { _E("Invalid node type"); return nullptr; @@ -243,6 +258,17 @@ static std::shared_ptr create_workflow_prototype(mmi_workflow attribute_default_value_info.default_value = default_value; prototype->add_attribute_default_value_info(attribute_default_value_info); + + mmi_attribute_destroy(default_value); + } + + for (size_t i = 0; i < workflow_info->signal_assignment_info_count; i++) { + SignalAssignmentInfo signal_assignment_info; + signal_assignment_info.signal_name = workflow_info->signal_assignment_infos[i].signal_name; + signal_assignment_info.target_node_name = workflow_info->signal_assignment_infos[i].target_node_name; + signal_assignment_info.target_signal_name = workflow_info->signal_assignment_infos[i].target_signal_name; + + prototype->add_signal_assignment_info(signal_assignment_info); } for (size_t i = 0; i < workflow_info->output_assignment_info_count; i++) { diff --git a/src/mmi-manager/mmi-port-instance.cpp b/src/mmi-manager/mmi-port-instance.cpp index d74e0b4..44c771c 100644 --- a/src/mmi-manager/mmi-port-instance.cpp +++ b/src/mmi-manager/mmi-port-instance.cpp @@ -50,8 +50,6 @@ void PortInstance::add_linked_port_instance(std::shared_ptr port_i } void PortInstance::on_output_data_generated(mmi_data_h data) { - _D("Data generated : this[%p] data[%p]", this, data); - for (auto it = m_data_gateways.begin(); it != m_data_gateways.end(); ++it) { (*it)->send_data(data); } @@ -62,8 +60,6 @@ void PortInstance::on_output_data_generated(mmi_data_h data) { } void PortInstance::on_output_data_received(mmi_data_h data) { - _D("Data received : this[%p] data[%p] input_data_received_cb[%p]", - this, data, m_callbacks.input_data_received_cb); if (m_callbacks.input_data_received_cb) { m_callbacks.input_data_received_cb(static_cast(this), data); } diff --git a/src/mmi-manager/mmi-self-container.cpp b/src/mmi-manager/mmi-self-container.cpp index daffaf9..558a1f4 100644 --- a/src/mmi-manager/mmi-self-container.cpp +++ b/src/mmi-manager/mmi-self-container.cpp @@ -28,6 +28,7 @@ namespace mmi { +// LCOV_EXCL_START std::map g_node_instance_info_map; TestNodePluginModule::TestNodePluginModule() { @@ -365,6 +366,7 @@ void PluginModuleProxySelfContainerTest::remove_node_instance_info(mmi_node_inst } } } +// LCOV_EXCL_STOP } // namespace mmi diff --git a/src/mmi-manager/mmi-workflow-instance-manager.cpp b/src/mmi-manager/mmi-workflow-instance-manager.cpp index bfbd1fe..c32996e 100644 --- a/src/mmi-manager/mmi-workflow-instance-manager.cpp +++ b/src/mmi-manager/mmi-workflow-instance-manager.cpp @@ -71,6 +71,7 @@ std::shared_ptr WorkflowInstanceManager::get_workflow_instance return nullptr; } +// LCOV_EXCL_START void WorkflowInstanceManager::on_observer_event( const COMMUNICATION_CHANNEL_EVENT_TYPE &event, std::any data) { try { @@ -113,6 +114,11 @@ void WorkflowInstanceManager::handle_client_message(ClientMessage *message) { handle_set_attribute(msg); } break; + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_EMIT_SIGNAL: { + auto *msg = static_cast(message); + handle_emit_signal(msg); + } + break; case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_ACTIVATE: { auto *msg = static_cast(message); handle_activate(msg); @@ -229,6 +235,20 @@ void WorkflowInstanceManager::handle_set_attribute( } } +void WorkflowInstanceManager::handle_emit_signal( + ClientMessageWorkflowInstanceEmitSignal *message) { + if (nullptr == message) { + LOGE("Message is null"); + return; + } + + std::shared_ptr instance = + get_workflow_instance(message->sender, message->local_workflow_instance_id); + if (instance) { + instance->handle_signal(message->signal); + } +} + void WorkflowInstanceManager::handle_activate( ClientMessageWorkflowInstanceActivate *message) { if (nullptr == message) { @@ -256,6 +276,7 @@ void WorkflowInstanceManager::handle_deactivate( instance->deactivate(); } } +// LCOV_EXCL_STOP } // namespace mmi diff --git a/src/mmi-manager/mmi-workflow-instance-manager.h b/src/mmi-manager/mmi-workflow-instance-manager.h index 5e32912..e4b50c8 100644 --- a/src/mmi-manager/mmi-workflow-instance-manager.h +++ b/src/mmi-manager/mmi-workflow-instance-manager.h @@ -72,6 +72,7 @@ private: void handle_create(ClientMessageWorkflowInstanceCreate *message); void handle_destroy(ClientMessageWorkflowInstanceDestroy *message); void handle_set_attribute(ClientMessageWorkflowInstanceSetAttribute *message); + void handle_emit_signal(ClientMessageWorkflowInstanceEmitSignal *message); void handle_activate(ClientMessageWorkflowInstanceActivate *message); void handle_deactivate(ClientMessageWorkflowInstanceDeactivate *message); protected: diff --git a/src/mmi-manager/mmi-workflow-instance.cpp b/src/mmi-manager/mmi-workflow-instance.cpp index e26b78f..24c7143 100644 --- a/src/mmi-manager/mmi-workflow-instance.cpp +++ b/src/mmi-manager/mmi-workflow-instance.cpp @@ -25,7 +25,6 @@ #include "mmi-manager-log.h" #include "mmi-workflow-output-event.h" -#include namespace mmi { WorkflowInstance::WorkflowInstance() { @@ -166,18 +165,18 @@ void WorkflowInstance::initialize() { mmi_data_transfer_callback callback = [this](mmi_data_h data, std::string name) { _D("Data received from Data Gateway"); unsigned char *data_bytes = nullptr; - size_t data_byte_size = 0; - mmi_data_to_bytes(data, &data_bytes, &data_byte_size); - - bundle *encoded = bundle_create(); - bundle_add_byte(encoded, "data", data_bytes, data_byte_size); + size_t data_size = 0; + mmi_data_to_bytes(data, &data_bytes, &data_size); WorkflowOutputEventOutputGenerated event; event.source_name = name; - event.data = encoded; event.client_id = get_client_id(); + event.data_bytes = data_bytes; + event.data_size = data_size; event.local_workflow_instance_id = get_local_workflow_instance_id(); this->notify_observers(WORKFLOW_OUTPUT_EVENT_TYPE::OUTPUT_GENERATED, &event); + + free(data_bytes); }; output_data_gateway->set_callback(callback); @@ -220,8 +219,10 @@ void WorkflowInstance::deinitialize() { m_node_instance_manager->destroy_node_instance(node_instance.second); } m_node_instances.clear(); + m_state = WORKFLOW_INSTANCE_STATE::NONE; } +// LCOV_EXCL_START void WorkflowInstance::activate() { if (WORKFLOW_INSTANCE_STATE::INITIALIZED != m_state) { _E("Workflow instance state is not INITIALIZED"); @@ -253,6 +254,7 @@ void WorkflowInstance::deactivate() { m_state = WORKFLOW_INSTANCE_STATE::INITIALIZED; } +// LCOV_EXCL_STOP bool WorkflowInstance::set_attribute(mmi_attribute_h attribute) { _D("Setting attribute : %p", attribute); @@ -282,8 +284,11 @@ bool WorkflowInstance::set_attribute(mmi_attribute_h attribute) { std::shared_ptr target_node_instance = m_node_instances.at(it->target_node_name); if (target_node_instance) { - mmi_attribute_set_name(attribute, it->target_attribute_name.c_str()); - target_node_instance->set_attribute(attribute); + mmi_attribute_h cloned = nullptr; + mmi_attribute_clone(attribute, &cloned); + mmi_attribute_set_name(cloned, it->target_attribute_name.c_str()); + target_node_instance->set_attribute(cloned); + mmi_attribute_destroy(cloned); } else { _E("Could not find target node instance : %s", it->target_node_name.c_str()); } @@ -300,6 +305,51 @@ bool WorkflowInstance::set_attribute(mmi_attribute_h attribute) { return true; } +bool WorkflowInstance::handle_signal(mmi_signal_h signal) { + _D("Handling Signal : %p", signal); + + std::shared_ptr prototype = m_prototype_store->get_workflow_prototype(m_type); + if (nullptr == prototype) { + _E("Could not find prototype information from store"); + return false; + } + + char *name = nullptr; + if (MMI_ERROR_NONE == mmi_signal_get_name(signal, &name)) { + std::vector signal_assignment_infos = + prototype->get_signal_assignment_infos(); + + if (!name) { + _E("Signal name is null"); + return false; + } + auto it = std::find_if(signal_assignment_infos.begin(), signal_assignment_infos.end(), + [name](const SignalAssignmentInfo& info) { + return (info.signal_name.compare(name) == 0); + }); + if (it != signal_assignment_infos.end()) { + _D("Found signal assignment info : %s", name); + try { + std::shared_ptr target_node_instance = + m_node_instances.at(it->target_node_name); + if (target_node_instance) { + target_node_instance->handle_signal(signal); + } else { + _E("Could not find target node instance : %s", it->target_node_name.c_str()); + } + } catch (std::out_of_range& e) { + _E("Failed to find node instance : %s", it->target_node_name.c_str()); + } + } else { + _E("Could not find signal assignment info : %s", name); + } + } + free(name); + + return true; +} + +// LCOV_EXCL_START void WorkflowInstance::on_observer_event( const PLUGIN_MODULE_EVENT_TYPE &event, std::any data) { try { @@ -334,6 +384,7 @@ void WorkflowInstance::on_observer_event( LOGE("Failed to cast message data: %s", e.what()); } } +// LCOV_EXCL_STOP bool WorkflowInstance::set_attribute_default_values() { _D("Setting attribute default value"); diff --git a/src/mmi-manager/mmi-workflow-instance.h b/src/mmi-manager/mmi-workflow-instance.h index 42ef79c..dd80d8f 100644 --- a/src/mmi-manager/mmi-workflow-instance.h +++ b/src/mmi-manager/mmi-workflow-instance.h @@ -74,6 +74,8 @@ public: bool set_attribute(mmi_attribute_h attribute); bool set_attribute_default_values(); + bool handle_signal(mmi_signal_h signal); + void on_observer_event( const PLUGIN_MODULE_EVENT_TYPE &event, std::any data) override; private: diff --git a/src/mmi-manager/mmi-workflow-prototype-manager.cpp b/src/mmi-manager/mmi-workflow-prototype-manager.cpp index 5aa3977..c5d89f3 100644 --- a/src/mmi-manager/mmi-workflow-prototype-manager.cpp +++ b/src/mmi-manager/mmi-workflow-prototype-manager.cpp @@ -52,6 +52,7 @@ bool WorkflowPrototypeManager::add_workflow_prototype(std::shared_ptr WorkflowPrototypeManager::get_workflow_prototype( mmi_standard_workflow_type_e type) { std::shared_ptr ret; @@ -71,6 +72,7 @@ void WorkflowPrototypeManager::initialize() { void WorkflowPrototypeManager::deinitialize() { } +// LCOV_EXCL_STOP } // namespace mmi diff --git a/src/mmi-manager/mmi-workflow-prototype.cpp b/src/mmi-manager/mmi-workflow-prototype.cpp index ca66168..9866de1 100644 --- a/src/mmi-manager/mmi-workflow-prototype.cpp +++ b/src/mmi-manager/mmi-workflow-prototype.cpp @@ -70,7 +70,15 @@ bool WorkflowPrototype::add_attribute_assignment_info(AttributeAssignmentInfo at } bool WorkflowPrototype::add_attribute_default_value_info(AttributeDefaultValueInfo attribute_default_value_info) { - m_attribute_default_value_infos.push_back(attribute_default_value_info); + AttributeDefaultValueInfo cloned_info; + mmi_attribute_clone(attribute_default_value_info.default_value, &(cloned_info.default_value)); + + m_attribute_default_value_infos.push_back(cloned_info); + return true; +} + +bool WorkflowPrototype::add_signal_assignment_info(SignalAssignmentInfo signal_assignment_info) { + m_signal_assignment_infos.push_back(signal_assignment_info); return true; } @@ -91,6 +99,7 @@ std::vector WorkflowPrototype::get_link_infos() { return m_link_infos; } +// LCOV_EXCL_START std::vector WorkflowPrototype::get_attribute_assignment_infos() { return m_attribute_assignment_infos; } @@ -98,6 +107,11 @@ std::vector WorkflowPrototype::get_attribute_assignment std::vector WorkflowPrototype::get_attribute_default_value_infos() { return m_attribute_default_value_infos; } +// LCOV_EXCL_STOP + +std::vector WorkflowPrototype::get_signal_assignment_infos() { + return m_signal_assignment_infos; +} std::vector WorkflowPrototype::get_output_assignment_infos() { return m_output_assignment_infos; diff --git a/src/mmi-manager/mmi-workflow-prototype.h b/src/mmi-manager/mmi-workflow-prototype.h index 85058b1..14a397c 100644 --- a/src/mmi-manager/mmi-workflow-prototype.h +++ b/src/mmi-manager/mmi-workflow-prototype.h @@ -54,6 +54,12 @@ typedef struct { mmi_attribute_h default_value; } AttributeDefaultValueInfo; +typedef struct { + std::string signal_name; + std::string target_node_name; + std::string target_signal_name; +} SignalAssignmentInfo; + typedef struct { std::string output_name; std::string from_node_name; @@ -80,6 +86,7 @@ public: bool add_link_info(LinkInfo link_info); bool add_attribute_assignment_info(AttributeAssignmentInfo attribute_assignment_info); bool add_attribute_default_value_info(AttributeDefaultValueInfo attribute_default_value_info); + bool add_signal_assignment_info(SignalAssignmentInfo signal_assignment_info); bool add_output_assignment_info(OutputAssignmentInfo output_assignment_info); mmi_standard_workflow_type_e get_type(); @@ -88,6 +95,7 @@ public: std::vector get_link_infos(); std::vector get_attribute_assignment_infos(); std::vector get_attribute_default_value_infos(); + std::vector get_signal_assignment_infos(); std::vector get_output_assignment_infos(); private: PluginModuleInfo m_plugin_module_info; @@ -98,6 +106,7 @@ private: std::vector m_link_infos; std::vector m_attribute_assignment_infos; std::vector m_attribute_default_value_infos; + std::vector m_signal_assignment_infos; std::vector m_output_assignment_infos; }; diff --git a/src/mmi/meson.build b/src/mmi/meson.build index 4260c90..11613ef 100644 --- a/src/mmi/meson.build +++ b/src/mmi/meson.build @@ -3,11 +3,7 @@ mmi_srcs = [ 'mmi-workflow.cpp', 'mmi-workflow-instance.cpp', 'mmi-workflow-script.cpp', - 'mmi-ipc-tidl.h', - 'mmi-ipc-tidl.cpp', 'mmi-log.h', - 'mmi_proxy.h', - 'mmi_proxy.c', 'mmi-primitive-value.cpp', 'mmi-data.cpp', 'mmi-attribute.cpp', @@ -16,32 +12,42 @@ mmi_srcs = [ 'mmi-node-processor.cpp', 'mmi-node-logic.cpp', 'mmi-node-controller.cpp', + 'mmi-node-action.cpp', 'mmi-port.cpp', 'mmi-signal.cpp', 'mmi-plugin-storage.cpp', + 'mmi-config-parser.cpp', ] +foreach platform_specific_client_file : mmi_platform_specific_client_files + message('Platform Specific File : ' + platform_specific_client_file) + mmi_srcs += platform_specific_client_file +endforeach + glib_dep = dependency('glib-2.0', method : 'pkg-config') gio_dep = dependency('gio-2.0', method : 'pkg-config') -bundle_dep = dependency('bundle', method : 'pkg-config') -dlog_dep = dependency('dlog', method : 'pkg-config') -rpc_port_dep = dependency('rpc-port', method : 'pkg-config') -libtzplatform_config_dep = dependency('libtzplatform-config') ecore_dep = dependency('ecore', method : 'pkg-config') +xml_dep = dependency('libxml-2.0', method : 'pkg-config') mmi_deps = [ ecore_dep, glib_dep, gio_dep, - bundle_dep, - dlog_dep, - rpc_port_dep, - libtzplatform_config_dep] + xml_dep + ] + +foreach platform_specific_dependency : mmi_platform_specific_dependencies + message('Platform Specific Dependency : ' + platform_specific_dependency) + extra_dep = dependency(platform_specific_dependency, method : 'pkg-config') + mmi_deps += extra_dep +endforeach +mmi_extra_include_dir = ''.join(['../../', mmi_platform_specific_include_directory]) mmi_include_dirs = include_directories( '.', '../common', - '../../capi' + '../../capi', + mmi_extra_include_dir, ) mmi_lib = shared_library( diff --git a/src/mmi/mmi-client-manager.h b/src/mmi/mmi-client-manager.h index c8b921b..9851726 100644 --- a/src/mmi/mmi-client-manager.h +++ b/src/mmi/mmi-client-manager.h @@ -34,7 +34,7 @@ struct ICommunicationChannelFactory { class ClientManager : public SimpleEventObserver { public: ClientManager( - ICommunicationChannelFactory *factory, + CommunicationChannelClientFactory *factory, SimpleEventObserver *observer) : m_communication_channel_factory(factory), m_communication_channel_observer(observer) { @@ -67,7 +67,7 @@ public: if (m_reference_count == 0) { if (m_communication_channel) { m_communication_channel->disconnect(); - m_communication_channel_factory->destroy_channel(m_communication_channel); + m_communication_channel.reset(); } m_communication_channel = nullptr; @@ -76,7 +76,8 @@ public: return true; } - CommunicationChannel* get_communication_channel() { +// LCOV_EXCL_START + std::shared_ptr get_communication_channel() { return m_communication_channel; } WorkflowInstanceManager* get_workflow_instance_manager() { @@ -85,13 +86,41 @@ public: void on_observer_event( const COMMUNICATION_CHANNEL_EVENT_TYPE &event, std::any data) override { + if (event == COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED) { + try { + Message *message = std::any_cast(data); + if (message->message_group != MESSAGE_GROUP::CLIENT) { + LOGE("Message Group is not CLIENT"); + return; + } + auto client_message = static_cast(message); + switch (client_message->message_type) { + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_OUTPUT: { + handle_output(static_cast(message)); + } + break; + } + } catch (const std::bad_any_cast &e) { + LOGE("Failed to cast message data: %s", e.what()); + } + } + } + + void handle_output(ClientMessageWorkflowInstanceOutput *message) { + if (message) { + LOGI("Output message received"); + WorkflowInstance *instance = m_workflow_instance_manager.get(message->local_workflow_instance_id); + if (instance) { + instance->call_output_callback(message->source_name, message->data); + } + } } +// LCOV_EXCL_STOP private: - ICommunicationChannelFactory* m_communication_channel_factory{nullptr}; - CommunicationChannel *m_communication_channel{nullptr}; - SimpleEventObserver - *m_communication_channel_observer; + CommunicationChannelClientFactory *m_communication_channel_factory{nullptr}; + std::shared_ptr m_communication_channel; + SimpleEventObserver *m_communication_channel_observer; WorkflowInstanceManager m_workflow_instance_manager; int m_reference_count{0}; diff --git a/src/mmi/mmi-config-parser.cpp b/src/mmi/mmi-config-parser.cpp new file mode 100644 index 0000000..38c5ef6 --- /dev/null +++ b/src/mmi/mmi-config-parser.cpp @@ -0,0 +1,248 @@ +/* + * Copyright © 2023 Samsung Electronics co., Ltd. All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include +#include "mmi-config-parser.h" +#include "mmi-log.h" + + +#define MMI_TAG_CONFIG_BASE_TAG "mmi-config" +#define MMI_TAG_CONFIG_CONFIDENCE "confidence" + +static Ecore_Fd_Handler* g_config_fd_handler_noti = NULL; +static int g_config_fd_noti; +static int g_config_wd_noti; + +static xmlDocPtr g_config_doc = NULL; +static mmi_config_s* g_config_info = NULL; + + +static int mmi_parser_load_config(void) +{ + xmlDocPtr doc = NULL; + xmlNodePtr cur = NULL; + + /* For Thread safety */ + xmlInitParser(); + + if (0 == access(MMI_DEFAULT_CONFIG, F_OK)) { + doc = xmlParseFile(MMI_DEFAULT_CONFIG); + if (doc == NULL) { + LOGE("[ERROR] Fail to parse file error : %s", MMI_DEFAULT_CONFIG); + xmlCleanupParser(); + return -1; + } + } + + cur = xmlDocGetRootElement(doc); + if (cur == NULL) { + LOGE("[ERROR] Empty document(%p)", doc); + xmlFreeDoc(doc); + doc = NULL; + xmlCleanupParser(); + return -1; + } + + if (xmlStrcmp(cur->name, (const xmlChar *) MMI_TAG_CONFIG_BASE_TAG)) { + LOGE("[ERROR] The wrong type, root node is NOT %s. doc(%p)", MMI_TAG_CONFIG_BASE_TAG, doc); + xmlFreeDoc(doc); + doc = NULL; + xmlCleanupParser(); + return -1; + } + + cur = cur->xmlChildrenNode; + if (cur == NULL) { + LOGE("[ERROR] Empty document(%p)", doc); + xmlFreeDoc(doc); + doc = NULL; + xmlCleanupParser(); + return -1; + } + + mmi_config_s* temp; + temp = (mmi_config_s*)calloc(1, sizeof(mmi_config_s)); + if (NULL == temp) { + LOGE("[ERROR] Out of memory(%p)", doc); + xmlFreeDoc(doc); + doc = NULL; + xmlCleanupParser(); + return -1; + } + + while (cur != NULL) { + if (0 == xmlStrcmp(cur->name, (const xmlChar *)MMI_TAG_CONFIG_CONFIDENCE)) { + xmlChar *key = xmlNodeGetContent(cur); + if (NULL != key) { + temp->confidence = atof((char*)key); + xmlFree(key); + key = NULL; + } else { + LOGD("[ERROR] confidence is NULL"); + } + } + cur = cur->next; + } + + g_config_info = temp; + g_config_doc = doc; + + return 0; +} + +static int mmi_parser_unload_config(void) +{ + if (NULL != g_config_doc) { + LOGD("[DEBUG] Free g_config_doc(%p)", g_config_doc); + xmlFreeDoc(g_config_doc); + g_config_doc = NULL; + } + + if (NULL != g_config_info) { + LOGE("[DEBUG] Free config_info(%p)", g_config_info); + free(g_config_info); + g_config_info = NULL; + } + + xmlCleanupParser(); + return 0; +} + +static Eina_Bool mmi_config_mgr_inotify_event_cb(void* data, Ecore_Fd_Handler *fd_handler) +{ + LOGD("into mmi_config_mgr_inotify_event_cb"); + + int length; + struct inotify_event event; + memset(&event, '\0', sizeof(struct inotify_event)); + + length = read(g_config_fd_noti, &event, sizeof(struct inotify_event)); + if (0 > length) { + LOGE("[ERROR] Empty Inotify event"); + return ECORE_CALLBACK_DONE; + } + + if (IN_CLOSE_WRITE == event.mask) { + /* check config changed state */ + if (0 != mmi_parser_load_config()) + return ECORE_CALLBACK_PASS_ON; + + } else if (IN_DELETE_SELF == event.mask) { + LOGE("[ERROR] IN_DELETE_SELF event"); + + mmi_parser_unload_config(); + mmi_parser_load_config(); + } else { + LOGE("[ERROR] Undefined event (0x%x)", event.mask); + } + + return ECORE_CALLBACK_PASS_ON; +} + +static int mmi_config_mgr_register_config_event() +{ + /* get file notification handler */ + int fd; + int wd; + + fd = inotify_init(); + if (fd < 0) { + LOGE("[ERROR] Fail get inotify fd"); + return -1; + } + g_config_fd_noti = fd; + + wd = inotify_add_watch(fd, MMI_DEFAULT_CONFIG, IN_CLOSE_WRITE|IN_DELETE_SELF); + g_config_wd_noti = wd; + + g_config_fd_handler_noti = ecore_main_fd_handler_add(fd, ECORE_FD_READ, + (Ecore_Fd_Cb)mmi_config_mgr_inotify_event_cb, NULL, NULL, NULL); + if (NULL == g_config_fd_handler_noti) { + LOGE("[ERROR] Fail to get handler_noti"); + return -1; + } + + /* Set non-blocking mode of file */ + int value; + value = fcntl(fd, F_GETFL, 0); + value |= O_NONBLOCK; + + if (0 > fcntl(fd, F_SETFL, value)) { + LOGE("[WARNING] Fail to set non-block mode"); + } + + return 0; +} + +static int mmi_config_mgr_unregister_config_event() +{ + /* delete inotify variable */ + ecore_main_fd_handler_del(g_config_fd_handler_noti); + inotify_rm_watch(g_config_fd_noti, g_config_wd_noti); + close(g_config_fd_noti); + + return 0; +} + +int mmi_parser_initialize(void) +{ + if (0 != mmi_config_mgr_register_config_event()) { + LOGE("Fail to mmi_config_mgr_register_config_event"); + } + + if (0 != mmi_parser_load_config()) { + LOGE("Fail to mmi_parser_load_config"); + } + return 0; +} + +int mmi_parser_deinitialize(void) +{ + if (0 != mmi_config_mgr_unregister_config_event()) { + LOGE("Fail to mmi_config_mgr_unregister_config_event"); + } + + if (0 != mmi_parser_unload_config()) { + LOGE("Fail to mmi_parser_unload_config"); + } + return 0; +} + +int mmi_parser_get_confidence(float *confidence) +{ + LOGD("[DEBUG] Get confidence"); + + if (g_config_info) { + *confidence = g_config_info->confidence; + } else { + LOGE("[ERROR] g_config_info is NULL"); + return -1; + } + + return 0; +} diff --git a/src/mmi/mmi-data.cpp b/src/mmi/mmi-data.cpp index 7119506..f12867b 100644 --- a/src/mmi/mmi-data.cpp +++ b/src/mmi/mmi-data.cpp @@ -61,7 +61,7 @@ static inline mmi_data_h *get_element_value_pointer_in_struct(mmi_data_h struct_ return get_element_pointer_in_array(struct_handle, index * 2 + 1); } - +// LCOV_EXCL_START int mmi_data_create_bool(bool value, mmi_data_h *data) { if (nullptr == data) { _E("[ERROR] Some parameters are invalid"); @@ -87,9 +87,9 @@ int mmi_data_create_bool(bool value, mmi_data_h *data) { *data = new_data; - _D("[DEBUG] Success to create for bool(%d)", value); return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP int mmi_data_create_int(int value, mmi_data_h *data) { if (nullptr == data) { @@ -116,10 +116,10 @@ int mmi_data_create_int(int value, mmi_data_h *data) { *data = new_data; - _D("[DEBUG] Success to create for int(%d)", value); return MMI_ERROR_NONE; } +// LCOV_EXCL_START int mmi_data_create_float(float value, mmi_data_h *data) { if (nullptr == data) { _E("[ERROR] Some parameters are invalid"); @@ -145,9 +145,9 @@ int mmi_data_create_float(float value, mmi_data_h *data) { *data = new_data; - _D("[DEBUG] Success to create for float(%f)", value); return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP int mmi_data_create_text(const char *value, mmi_data_h *data) { if (nullptr == data || nullptr == value) { @@ -173,7 +173,6 @@ int mmi_data_create_text(const char *value, mmi_data_h *data) { *data = new_data; - _D("[DEBUG] Success to create for string(%s)", value); return MMI_ERROR_NONE; } @@ -202,10 +201,10 @@ int mmi_data_create_audio(const void *ptr, size_t len, mmi_data_h *data) { *data = new_data; - _D("[DEBUG] Success to create for audio data. len(%zu)", len); return MMI_ERROR_NONE; } +// LCOV_EXCL_START int mmi_data_create_video(const void *ptr, size_t len, mmi_data_h *data) { if (nullptr == data || nullptr == ptr || 0 == len) { _E("[ERROR] Some parameters are invalid"); @@ -231,7 +230,6 @@ int mmi_data_create_video(const void *ptr, size_t len, mmi_data_h *data) { *data = new_data; - _D("[DEBUG] Success to create for video data. len(%zu)", len); return MMI_ERROR_NONE; } @@ -260,7 +258,67 @@ int mmi_data_create_user_identification(const void *ptr, size_t len, mmi_data_h *data = new_data; - _D("[DEBUG] Success to create for user identification data. len(%zu)", len); + return MMI_ERROR_NONE; +} +// LCOV_EXCL_STOP + +int mmi_data_create_coordinate(int x, int y, mmi_data_h *data) { + if (nullptr == data) { + _E("[ERROR] Some parameters are invalid"); + return MMI_ERROR_INVALID_PARAMETER; + } + + auto new_data = reinterpret_cast(malloc(sizeof(mmi_data_s))); + if (nullptr == new_data) { + _E("[ERROR] Fail to allocate memory for mmi data"); + return MMI_ERROR_OUT_OF_MEMORY; + } + + new_data->type = MMI_DATA_TYPE_COORDINATE; + new_data->data = malloc(sizeof(int) * 2); + if (nullptr == new_data->data) { + _E("[ERROR] Fail to allocate memory for raw data"); + free(new_data); + return MMI_ERROR_OUT_OF_MEMORY; + } + + (reinterpret_cast(new_data->data))[0] = x; + (reinterpret_cast(new_data->data))[1] = y; + new_data->datalen = sizeof(int) * 2; + + *data = new_data; + + return MMI_ERROR_NONE; +} + +int mmi_data_create_bounding_box(int x, int y, int w, int h, mmi_data_h *data) { + if (nullptr == data) { + _E("[ERROR] Some parameters are invalid"); + return MMI_ERROR_INVALID_PARAMETER; + } + + auto new_data = reinterpret_cast(malloc(sizeof(mmi_data_s))); + if (nullptr == new_data) { + _E("[ERROR] Fail to allocate memory for mmi data"); + return MMI_ERROR_OUT_OF_MEMORY; + } + + new_data->type = MMI_DATA_TYPE_BOUNDING_BOX; + new_data->data = malloc(sizeof(int) * 4); + if (nullptr == new_data->data) { + _E("[ERROR] Fail to allocate memory for raw data"); + free(new_data); + return MMI_ERROR_OUT_OF_MEMORY; + } + + (reinterpret_cast(new_data->data))[0] = x; + (reinterpret_cast(new_data->data))[1] = y; + (reinterpret_cast(new_data->data))[2] = w; + (reinterpret_cast(new_data->data))[3] = h; + new_data->datalen = sizeof(int) * 4; + + *data = new_data; + return MMI_ERROR_NONE; } @@ -282,7 +340,6 @@ int mmi_data_create_array(mmi_data_h *data) { *data = new_data; - _D("[DEBUG] Success to create empty array"); return MMI_ERROR_NONE; } @@ -318,7 +375,6 @@ int mmi_data_add_array_element(mmi_data_h array, mmi_data_h element) { return MMI_ERROR_OUT_OF_MEMORY; } - _D("[DEBUG] Success to add element(%zu)", get_count_of_elements(array)); return MMI_ERROR_NONE; } @@ -340,7 +396,6 @@ int mmi_data_create_struct(mmi_data_h *struct_handle) { *struct_handle = new_data; - _D("[DEBUG] Success to create empty array"); return MMI_ERROR_NONE; } @@ -377,7 +432,6 @@ int mmi_data_set_struct_element(mmi_data_h struct_handle, const char *name, mmi_ return MMI_ERROR_OUT_OF_MEMORY; } - _D("[DEBUG] Success to add element with name(%s)", name); return MMI_ERROR_NONE; } @@ -389,10 +443,10 @@ int mmi_data_get_type(mmi_data_h data, mmi_data_type_e *type) { *type = data->type; - _D("[DEBUG] Success to get type(%d)", *type); return MMI_ERROR_NONE; } +// LCOV_EXCL_START int mmi_data_get_bool(mmi_data_h data, bool *value) { if (nullptr == data || nullptr == value) { _E("[ERROR] Some parameters are invalid"); @@ -406,9 +460,9 @@ int mmi_data_get_bool(mmi_data_h data, bool *value) { *value = *(reinterpret_cast(data->data)); - _D("[DEBUG] Success to get value: bool(%d)", *value); return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP int mmi_data_get_int(mmi_data_h data, int *value) { if (nullptr == data || nullptr == value) { @@ -423,10 +477,10 @@ int mmi_data_get_int(mmi_data_h data, int *value) { *value = *(reinterpret_cast(data->data)); - _D("[DEBUG] Success to get value: int(%d)", *value); return MMI_ERROR_NONE; } +// LCOV_EXCL_START int mmi_data_get_float(mmi_data_h data, float *value) { if (nullptr == data || nullptr == value) { _E("[ERROR] Some parameters are invalid"); @@ -440,9 +494,9 @@ int mmi_data_get_float(mmi_data_h data, float *value) { *value = *(reinterpret_cast(data->data)); - _D("[DEBUG] Success to get value: float(%f)", *value); return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP int mmi_data_get_text(mmi_data_h data, const char **string) { if (nullptr == data || nullptr == string) { @@ -457,10 +511,10 @@ int mmi_data_get_text(mmi_data_h data, const char **string) { *string = reinterpret_cast(data->data); - _D("[DEBUG] Success to get value: string(%s)", *string); return MMI_ERROR_NONE; } +// LCOV_EXCL_START int mmi_data_get_audio(mmi_data_h data, const void **ptr, size_t *len) { if (nullptr == data || nullptr == ptr || nullptr == len) { _E("[ERROR] Some parameters are invalid"); @@ -475,7 +529,6 @@ int mmi_data_get_audio(mmi_data_h data, const void **ptr, size_t *len) { *len = data->datalen; *ptr = data->data; - _D("[DEBUG] Success to get value: audio(%zu)", *len); return MMI_ERROR_NONE; } @@ -493,7 +546,6 @@ int mmi_data_get_video(mmi_data_h data, const void **ptr, size_t *len) { *len = data->datalen; *ptr = data->data; - _D("[DEBUG] Success to get value: video(%zu)", *len); return MMI_ERROR_NONE; } @@ -511,7 +563,55 @@ int mmi_data_get_user_identification(mmi_data_h data, const void **ptr, size_t * *len = data->datalen; *ptr = data->data; - _D("[DEBUG] Success to get value: user_identification(%zu)", *len); + return MMI_ERROR_NONE; +} +// LCOV_EXCL_STOP + +int mmi_data_get_coordinate(mmi_data_h data, int *x, int *y) { + if (nullptr == data || nullptr == x || nullptr == y) { + _E("[ERROR] Some parameters are invalid"); + return MMI_ERROR_INVALID_PARAMETER; + } + + if (data->type != MMI_DATA_TYPE_COORDINATE) { + _E("[ERROR] Data type is not matched"); + return MMI_ERROR_INVALID_PARAMETER; + } + + int *array = (reinterpret_cast(data->data)); + if (nullptr == array || data->datalen != (sizeof(int) * 2)) { + _E("[ERROR] The parameter contains invalid data"); + return MMI_ERROR_INVALID_PARAMETER; + } + + *x = array[0]; + *y = array[1]; + + return MMI_ERROR_NONE; +} + +int mmi_data_get_bounding_box(mmi_data_h data, int *x, int *y, int *w, int *h) { + if (nullptr == data || nullptr == x || nullptr == y || nullptr == w || nullptr == h) { + _E("[ERROR] Some parameters are invalid"); + return MMI_ERROR_INVALID_PARAMETER; + } + + if (data->type != MMI_DATA_TYPE_BOUNDING_BOX) { + _E("[ERROR] Data type is not matched"); + return MMI_ERROR_INVALID_PARAMETER; + } + + int *array = (reinterpret_cast(data->data)); + if (nullptr == array || data->datalen != (sizeof(int) * 4)) { + _E("[ERROR] The parameter contains invalid data"); + return MMI_ERROR_INVALID_PARAMETER; + } + + *x = array[0]; + *y = array[1]; + *w = array[2]; + *h = array[3]; + return MMI_ERROR_NONE; } @@ -528,7 +628,6 @@ int mmi_data_get_array_count(mmi_data_h array, size_t *count) { *count = get_count_of_elements(array); - _D("[DEBUG] Success to get array count(%zu)", *count); return MMI_ERROR_NONE; } @@ -551,7 +650,6 @@ int mmi_data_get_array_element(mmi_data_h array, size_t index, mmi_data_h *eleme *element = *(get_element_pointer_in_array(array, index)); - _D("[DEBUG] Success to get array element on index(%zu)", index); return MMI_ERROR_NONE; } @@ -590,7 +688,6 @@ int mmi_data_get_struct_element(mmi_data_h struct_handle, const char *name, mmi_ *element = target_element; - _D("[DEBUG] Success to get element on name(%s)", name); return MMI_ERROR_NONE; } @@ -607,7 +704,6 @@ int mmi_data_get_struct_count(mmi_data_h struct_handle, size_t *count) { *count = get_count_of_struct_elements(struct_handle); - _D("[DEBUG] Success to get struct count(%zu)", *count); return MMI_ERROR_NONE; } @@ -631,7 +727,6 @@ int mmi_data_get_struct_element_name(mmi_data_h struct_handle, size_t index, con mmi_data_h *element = get_element_name_pointer_in_struct(struct_handle, index); mmi_data_get_text(*element, string); - _D("[DEBUG] Success to get struct element name on index(%zu)", index); return MMI_ERROR_NONE; } @@ -655,7 +750,6 @@ int mmi_data_get_struct_element_value(mmi_data_h struct_handle, size_t index, mm *element = *(get_element_value_pointer_in_struct(struct_handle, index)); - _D("[DEBUG] Success to get struct element value on index(%zu)", index); return MMI_ERROR_NONE; } @@ -679,10 +773,10 @@ int mmi_data_destroy(mmi_data_h data) { data->type = MMI_DATA_TYPE_ANY; free(data); - _D("[DEBUG] Success to destroy"); return MMI_ERROR_NONE; } +// LCOV_EXCL_START int mmi_data_get_node_timestamp(mmi_data_h data, mmi_data_timestamp_h *timestamp) { if (nullptr == data || nullptr == timestamp) { return MMI_ERROR_INVALID_PARAMETER; @@ -772,8 +866,6 @@ int mmi_data_to_bytes(mmi_data_h data, unsigned char **bytes, size_t *length) { *length = total_size; } - _D("[DEBUG] Success to convert data to bytes"); - return MMI_ERROR_NONE; } @@ -857,7 +949,6 @@ int mmi_data_from_bytes(unsigned char *bytes, size_t length, mmi_data_h *data) { *data = value; } - _D("[DEBUG] Success to convert from bytes. type(%d), size(%zu)", type, length); - return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP diff --git a/src/mmi/mmi-ipc-ecore.cpp b/src/mmi/mmi-ipc-ecore.cpp new file mode 100644 index 0000000..cb1fca3 --- /dev/null +++ b/src/mmi/mmi-ipc-ecore.cpp @@ -0,0 +1,305 @@ +#include "mmi-ipc-ecore.h" + +namespace mmi { + +namespace communication { + +std::shared_ptr +CommunicationChannelClientFactory::create_channel() { + return std::make_shared(); +} + +CommunicationChannelEcoreIPC::CommunicationChannelEcoreIPC() { + if (!ecore_ipc_init()) { + _E("Ecore IPC init failed"); + } +} + +CommunicationChannelEcoreIPC::~CommunicationChannelEcoreIPC() { + if (!ecore_ipc_shutdown()) { + _E("Ecore IPC shutdown failed"); + } +} + +int CommunicationChannelEcoreIPC::connect() { + if (m_server) { + return MMI_ERROR_OPERATION_FAILED; + } + m_server = ecore_ipc_server_connect(ECORE_IPC_REMOTE_SYSTEM, "localhost", 9999, this); + ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_ADD, handler_server_add, this); + ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DEL, handler_server_del, this); + ecore_event_handler_add(ECORE_IPC_EVENT_SERVER_DATA, handler_server_data, this); + return 0; +} + +int CommunicationChannelEcoreIPC::disconnect(void) { + if (m_server) { + ecore_ipc_server_del(m_server); + m_server = nullptr; + } + return 0; +} + +int CommunicationChannelEcoreIPC::send(Message *message) { + auto clientMessage = static_cast(message); + CLIENT_MESSAGE_TYPE type = clientMessage->message_type; + + switch (type) + { + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_CREATE: + { + auto subclass = static_cast(message); + struct workflow_instance_create_payload { + int local_workflow_instance_id; + mmi_standard_workflow_type_e workflow_type; + } payload; + payload.local_workflow_instance_id = subclass->local_workflow_instance_id; + payload.workflow_type = subclass->workflow_type; + size_t byte_size = sizeof(CLIENT_MESSAGE_TYPE) + sizeof(workflow_instance_create_payload); + unsigned char *bytes = (unsigned char*)(malloc(byte_size)); + if (bytes) { + memcpy(bytes, &type, sizeof(CLIENT_MESSAGE_TYPE)); + memcpy(bytes + sizeof(CLIENT_MESSAGE_TYPE), &payload, sizeof(payload)); + ecore_ipc_server_send(m_server, 0, 0, 0, 0, 0, bytes, byte_size); + free(bytes); + } + } + break; + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_DESTROY: + { + auto subclass = static_cast(message); + struct workflow_instance_destroy_payload { + int local_workflow_instance_id; + } payload; + payload.local_workflow_instance_id = subclass->local_workflow_instance_id; + size_t byte_size = sizeof(CLIENT_MESSAGE_TYPE) + sizeof(workflow_instance_destroy_payload); + unsigned char *bytes = (unsigned char*)(malloc(byte_size)); + if (bytes) { + memcpy(bytes, &type, sizeof(CLIENT_MESSAGE_TYPE)); + memcpy(bytes + sizeof(CLIENT_MESSAGE_TYPE), &payload, sizeof(workflow_instance_destroy_payload)); + ecore_ipc_server_send(m_server, 0, 0, 0, 0, 0, bytes, byte_size); + free(bytes); + } + } + break; + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_SET_ATTRIBUTE: + { + auto subclass = static_cast(message); + + char *attribute_name = nullptr; + mmi_attribute_get_name(subclass->attribute, &attribute_name); + mmi_primitive_value_h value = nullptr; + mmi_attribute_get_value(subclass->attribute, &value); + unsigned char *value_bytes = nullptr; + size_t value_size = 0; + mmi_primitive_value_to_bytes(value, &value_bytes, &value_size); + + struct workflow_instance_set_attribute_payload { + int local_workflow_instance_id; + char attribute_name[MMI_NAME_MAX_LENGTH]; + size_t value_size; + } payload; + payload.local_workflow_instance_id = subclass->local_workflow_instance_id; + + strncpy(payload.attribute_name, attribute_name, MMI_NAME_MAX_LENGTH - 1); + payload.attribute_name[MMI_NAME_MAX_LENGTH - 1] = '\0'; + payload.value_size = value_size; + + size_t byte_size = sizeof(CLIENT_MESSAGE_TYPE) + sizeof(payload); + byte_size += value_size; + unsigned char *bytes = (unsigned char*)(malloc(byte_size)); + size_t index = 0; + if (bytes) { + memcpy(bytes, &type, sizeof(CLIENT_MESSAGE_TYPE)); + index += sizeof(CLIENT_MESSAGE_TYPE); + memcpy(bytes + index, &payload, sizeof(payload)); + index += sizeof(payload); + memcpy(bytes + index, value_bytes, value_size); + + ecore_ipc_server_send(m_server, 0, 0, 0, 0, 0, bytes, byte_size); + } + free(bytes); + free(value_bytes); + mmi_primitive_value_destroy(value); + free(attribute_name); + } + break; + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_EMIT_SIGNAL: + { + auto subclass = static_cast(message); + char *signal_name = nullptr; + mmi_signal_get_name(subclass->signal, &signal_name); + + struct workflow_instance_emit_signal_payload { + int local_workflow_instance_id; + char signal_name[MMI_NAME_MAX_LENGTH]; + int signal_parameter_count; + } payload; + + payload.local_workflow_instance_id = subclass->local_workflow_instance_id; + strncpy(payload.signal_name, signal_name, MMI_NAME_MAX_LENGTH - 1); + payload.signal_name[MMI_NAME_MAX_LENGTH - 1] = '\0'; + mmi_signal_get_parameter_count(subclass->signal, &(payload.signal_parameter_count)); + + int index = 0; + size_t byte_size = sizeof(CLIENT_MESSAGE_TYPE) + sizeof(payload); + unsigned char *bytes = (unsigned char*)(malloc(byte_size)); + if (!bytes) return MMI_ERROR_OPERATION_FAILED; + + memcpy(bytes, &type, sizeof(CLIENT_MESSAGE_TYPE)); + index = sizeof(CLIENT_MESSAGE_TYPE); + memcpy(bytes + index, &payload, sizeof(payload)); + index += sizeof(payload); + + for (int loop = 0;loop < payload.signal_parameter_count;loop++) { + mmi_signal_parameter_h parameter = nullptr; + mmi_signal_get_parameter(subclass->signal, loop, ¶meter); + + char *parameter_name = nullptr; + mmi_signal_parameter_get_name(parameter, ¶meter_name); + + byte_size += MMI_NAME_MAX_LENGTH; + bytes = (unsigned char*)(realloc(bytes, byte_size)); + memcpy(bytes + index, parameter_name, MMI_NAME_MAX_LENGTH); + index += MMI_NAME_MAX_LENGTH; + + mmi_primitive_value_h value = nullptr; + mmi_signal_parameter_get_value(parameter, &value); + + unsigned char *value_bytes = nullptr; + size_t value_size = 0; + mmi_primitive_value_to_bytes(value, &value_bytes, &value_size); + + byte_size += (sizeof(int) + value_size); + bytes = (unsigned char*)(realloc(bytes, byte_size)); + memcpy(bytes + index, &value_size, sizeof(int)); + index += (sizeof(int)); + memcpy(bytes + index, value_bytes, value_size); + index += (value_size); + + free(value_bytes); + mmi_primitive_value_destroy(value); + mmi_signal_parameter_destroy(parameter); + } + + if (bytes) { + ecore_ipc_server_send(m_server, 0, 0, 0, 0, 0, bytes, byte_size); + free(bytes); + } + free(signal_name); + } + break; + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_ACTIVATE: + { + auto subclass = static_cast(message); + struct workflow_instance_activate_payload { + int local_workflow_instance_id; + } payload; + payload.local_workflow_instance_id = subclass->local_workflow_instance_id; + size_t byte_size = sizeof(CLIENT_MESSAGE_TYPE) + sizeof(workflow_instance_activate_payload); + unsigned char *bytes = (unsigned char*)(malloc(byte_size)); + if (bytes) { + memcpy(bytes, &type, sizeof(CLIENT_MESSAGE_TYPE)); + memcpy(bytes + sizeof(CLIENT_MESSAGE_TYPE), &payload, sizeof(workflow_instance_activate_payload)); + ecore_ipc_server_send(m_server, 0, 0, 0, 0, 0, bytes, byte_size); + free(bytes); + } + } + break; + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_DEACTIVATE: + { + auto subclass = static_cast(message); + struct workflow_instance_deactivate_payload { + int local_workflow_instance_id; + } payload; + payload.local_workflow_instance_id = subclass->local_workflow_instance_id; + size_t byte_size = sizeof(CLIENT_MESSAGE_TYPE) + sizeof(workflow_instance_deactivate_payload); + unsigned char *bytes = (unsigned char*)(malloc(byte_size)); + if (bytes) { + memcpy(bytes, &type, sizeof(CLIENT_MESSAGE_TYPE)); + memcpy(bytes + sizeof(CLIENT_MESSAGE_TYPE), &payload, sizeof(workflow_instance_deactivate_payload)); + ecore_ipc_server_send(m_server, 0, 0, 0, 0, 0, bytes, byte_size); + free(bytes); + } + } + break; + }; + return 0; +} + +Eina_Bool CommunicationChannelEcoreIPC::handler_server_add(void *data, int ev_type, void *ev) +{ + Ecore_Ipc_Event_Server_Add *e = (Ecore_Ipc_Event_Server_Add *)ev; + LOGI("Server Added : %p", e->server); + CommunicationChannelEcoreIPC *channel = static_cast(data); + if (channel) { + channel->m_connected = true; + channel->notify_observers( + COMMUNICATION_CHANNEL_EVENT_TYPE::CONNECTED); + } + return EINA_TRUE; +} + +Eina_Bool CommunicationChannelEcoreIPC::handler_server_del(void *data, int ev_type, void *ev) +{ + Ecore_Ipc_Event_Server_Del *e = (Ecore_Ipc_Event_Server_Del *)ev; + LOGI("Server Deleted : %p", e->server); + CommunicationChannelEcoreIPC *channel = static_cast(data); + if (channel) { + channel->m_connected = false; + channel->notify_observers( + COMMUNICATION_CHANNEL_EVENT_TYPE::DISCONNECTED); + } + return EINA_TRUE; +} + +Eina_Bool CommunicationChannelEcoreIPC::handler_server_data(void *data, int ev_type, void *ev) +{ + Ecore_Ipc_Event_Server_Data *e = (Ecore_Ipc_Event_Server_Data*)ev; + LOGI("Server Data Received : %p", e->server); + ClientMessageWorkflowInstanceOutput message; + + size_t index = 0; + memcpy(&(message.local_workflow_instance_id), e->data + index, sizeof(int)); + index += sizeof(int); + + size_t source_name_length = 0; + memcpy(&(source_name_length), e->data + index, sizeof(size_t)); + index += sizeof(size_t); + + char *bytes = (char*)(malloc(source_name_length + 1)); + memcpy(bytes, e->data + index, source_name_length); + bytes[source_name_length] = '\0'; + + message.source_name = (char*)bytes; + index += source_name_length; + + free(bytes); + + size_t data_size = 0; + memcpy(&(data_size), e->data + index, sizeof(size_t)); + index += sizeof(size_t); + + mmi_data_h output_data = nullptr; + if (MMI_ERROR_NONE != + mmi_data_from_bytes((unsigned char*)(e->data + index), data_size, &(output_data))) { + LOGE("[ERROR] Failed to restore data from bytes"); + return EINA_TRUE; + } + message.data = output_data; + + CommunicationChannelEcoreIPC *channel = static_cast(data); + if (channel) { + channel->m_connected = false; + channel->notify_observers( + COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, + static_cast(&message)); + } + mmi_data_destroy(output_data); + return EINA_TRUE; +} + +}; // namespace communication + +}; // namespace mmi + diff --git a/src/mmi/mmi-ipc-ecore.h b/src/mmi/mmi-ipc-ecore.h new file mode 100644 index 0000000..98c1ebe --- /dev/null +++ b/src/mmi/mmi-ipc-ecore.h @@ -0,0 +1,34 @@ +#pragma once + +#include +#include + +#include "mmi-communication-channel.h" + +namespace mmi { + +namespace communication { + +class CommunicationChannelEcoreIPC : public CommunicationChannelClient { +public: + CommunicationChannelEcoreIPC(); + ~CommunicationChannelEcoreIPC(); + + int connect() override; + int disconnect(void) override; + int send(Message *message) override; + +private: + static Eina_Bool handler_server_add(void *data, int ev_type, void *ev); + static Eina_Bool handler_server_del(void *data, int ev_type, void *ev); + static Eina_Bool handler_server_data(void *data, int ev_type, void *ev); + +private: + Ecore_Ipc_Server *m_server{nullptr}; + bool m_connected{false}; +}; + +}; // namespace communication + +}; // namespace mmi + diff --git a/src/mmi/mmi-ipc-tidl.cpp b/src/mmi/mmi-ipc-tidl.cpp index a58fc8f..bffcb93 100644 --- a/src/mmi/mmi-ipc-tidl.cpp +++ b/src/mmi/mmi-ipc-tidl.cpp @@ -28,6 +28,10 @@ namespace mmi { namespace communication { +std::shared_ptr CommunicationChannelClientFactory::create_channel() { + return std::make_shared(); +} + CommunicationChannelTIDL::CommunicationChannelTIDL() { } @@ -166,6 +170,11 @@ int CommunicationChannelTIDL::send(Message *message) { workflow_instance_set_attribute(subclass->local_workflow_instance_id, subclass->attribute); } break; + case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_EMIT_SIGNAL: { + auto subclass = static_cast(message); + workflow_instance_emit_signal(subclass->local_workflow_instance_id, subclass->signal); + } + break; case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_ACTIVATE: { auto subclass = static_cast(message); workflow_instance_activate(subclass->local_workflow_instance_id); @@ -304,6 +313,82 @@ int CommunicationChannelTIDL::workflow_instance_set_attribute(int local_workflow return ret; } +int CommunicationChannelTIDL::workflow_instance_emit_signal(int local_workflow_instance_id, mmi_signal_h signal) { + LOGI("Emitting signal for workflow instance (%d)", local_workflow_instance_id); + int ret = MMI_ERROR_NONE; + + if (NULL == signal) { + LOGE("Parameter is NULL or empty"); + return MMI_ERROR_INVALID_PARAMETER; + } + + rpc_port_proxy_mmi_h rpc_h = static_cast(m_rpc_h); + if (NULL == rpc_h) { + LOGE("Fail to get tidl rpc info"); + return MMI_ERROR_OPERATION_FAILED; + } + + if (false == is_connected()) { + LOGE("Try to connect again"); + int ret = retry_connection(rpc_h); + if (RPC_PORT_ERROR_NONE != ret) { + LOGE("Fail to retry connection(%d)", ret); + return MMI_ERROR_OPERATION_FAILED; + } + } + + char *signal_name = nullptr; + mmi_signal_get_name(signal, &signal_name); + + int parameter_count = 0; + mmi_signal_get_parameter_count(signal, ¶meter_count); + + bundle *encoded = bundle_create(); + bundle_add_str(encoded, "name", signal_name); + bundle_add_byte(encoded, "parameter_count", ¶meter_count, sizeof(int)); + + for (int loop = 0;loop < parameter_count;loop++) { + mmi_signal_parameter_h parameter = nullptr; + mmi_signal_get_parameter(signal, loop, ¶meter); + + char *parameter_name = nullptr; + mmi_signal_parameter_get_name(parameter, ¶meter_name); + + std::string name_string = std::string("parameter_name_") + std::to_string(loop); + bundle_add_str(encoded, name_string.c_str(), parameter_name); + + mmi_primitive_value_h value = nullptr; + mmi_signal_parameter_get_value(parameter, &value); + + unsigned char *value_bytes = nullptr; + size_t value_size = 0; + + mmi_primitive_value_to_bytes(value, &value_bytes, &value_size); + + std::string size_string = std::string("parameter_size_") + std::to_string(loop); + bundle_add_byte(encoded, size_string.c_str(), &value_size, sizeof(size_t)); + + std::string data_string = std::string("parameter_data_") + std::to_string(loop); + bundle_add_byte(encoded, data_string.c_str(), value_bytes, value_size); + + mmi_primitive_value_destroy(value); + mmi_signal_parameter_destroy(parameter); + } + + if (encoded) { + int ret = rpc_port_proxy_mmi_invoke_workflow_instance_emit_signal(rpc_h, local_workflow_instance_id, encoded); + bundle_free(encoded); + + if (RPC_PORT_ERROR_NONE != ret) { + LOGE("Failed to set workflow signal(%d)\n", ret); + ret = MMI_ERROR_OPERATION_FAILED; + } + } + + free(signal_name); + return ret; +} + int CommunicationChannelTIDL::workflow_instance_activate(int local_workflow_instance_id) { LOGI("Activating workflow instance of id (%d)", local_workflow_instance_id); diff --git a/src/mmi/mmi-ipc-tidl.h b/src/mmi/mmi-ipc-tidl.h index 8f794c7..c603998 100644 --- a/src/mmi/mmi-ipc-tidl.h +++ b/src/mmi/mmi-ipc-tidl.h @@ -41,6 +41,7 @@ private: int workflow_instance_create(int local_workflow_instance_id, mmi_standard_workflow_type_e workflow_type, void *user_data); int workflow_instance_destroy(int local_workflow_instance_id); int workflow_instance_set_attribute(int local_workflow_instance_id, mmi_attribute_h attribute); + int workflow_instance_emit_signal(int local_workflow_instance_id, mmi_signal_h signal); int workflow_instance_activate(int local_workflow_instance_id); int workflow_instance_deactivate(int local_workflow_instance_id); int workflow_instance_register_result_callback(int local_workflow_instance_id, void *user_data); diff --git a/src/mmi/mmi-log.h b/src/mmi/mmi-log.h index 7718fcd..17ef75f 100644 --- a/src/mmi/mmi-log.h +++ b/src/mmi/mmi-log.h @@ -18,27 +18,11 @@ #ifndef __MMI_LOG_H__ #define __MMI_LOG_H__ -#include +#include "mmi-platform-config.h" #ifdef LOG_TAG #undef LOG_TAG #endif #define LOG_TAG "MMI" -#ifndef _E -#define _E LOGE -#endif - -#ifndef _D -#define _D LOGD -#endif - -#ifndef _I -#define _I LOGI -#endif - -#ifndef _W -#define _W LOGW -#endif - #endif // __MMI_LOG_H__ diff --git a/src/mmi/mmi-node-action.cpp b/src/mmi/mmi-node-action.cpp new file mode 100644 index 0000000..91e62e3 --- /dev/null +++ b/src/mmi/mmi-node-action.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2023 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 "mmi.h" +#include "mmi-node-action.h" + +#include "mmi-log.h" + +int mmi_standard_node_create_action(mmi_standard_node_action_type_e type, mmi_node_h *node) { + if (nullptr == node) { + return MMI_ERROR_INVALID_PARAMETER; + } + *node = new mmi_node_s; + (*node)->type = MMI_STANDARD_NODE_TYPE_ACTION; + (*node)->sub_type = (int)type; + (*node)->ports = nullptr; + (*node)->port_count = 0; + memset(&(*node)->callbacks, 0, sizeof(mmi_node_callbacks)); + return MMI_ERROR_NONE; +} + +int mmi_standard_node_get_action_type(mmi_node_h node, mmi_standard_node_action_type_e *type) { + if (nullptr == node || nullptr == type) { + return MMI_ERROR_INVALID_PARAMETER; + } + *type = (mmi_standard_node_action_type_e)node->sub_type; + return MMI_ERROR_NONE; +} + +int mmi_standard_node_register_action(mmi_standard_node_action_type_e type, mmi_node_callbacks *callbacks, mmi_node_h node) { + if (nullptr == callbacks || nullptr == node) { + return MMI_ERROR_INVALID_PARAMETER; + } + return MMI_ERROR_NONE; +} + diff --git a/src/mmi/mmi-node-logic.cpp b/src/mmi/mmi-node-logic.cpp index 36e003d..f859186 100644 --- a/src/mmi/mmi-node-logic.cpp +++ b/src/mmi/mmi-node-logic.cpp @@ -42,10 +42,12 @@ int mmi_standard_node_get_logic_type(mmi_node_h node, mmi_standard_node_logic_ty return MMI_ERROR_NONE; } +// LCOV_EXCL_START int mmi_standard_node_register_logic(mmi_standard_node_logic_type_e type, mmi_node_callbacks *callbacks, mmi_node_h node) { if (nullptr == callbacks || nullptr == node) { return MMI_ERROR_INVALID_PARAMETER; } return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP diff --git a/src/mmi/mmi-node-processor.cpp b/src/mmi/mmi-node-processor.cpp index 8634a81..d94a7fe 100644 --- a/src/mmi/mmi-node-processor.cpp +++ b/src/mmi/mmi-node-processor.cpp @@ -42,10 +42,12 @@ int mmi_standard_node_get_processor_type(mmi_node_h node, mmi_standard_node_proc return MMI_ERROR_NONE; } +// LCOV_EXCL_START int mmi_standard_node_register_processor(mmi_standard_node_processor_type_e type, mmi_node_callbacks *callbacks, mmi_node_h node) { if (nullptr == callbacks || nullptr == node) { return MMI_ERROR_INVALID_PARAMETER; } return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP diff --git a/src/mmi/mmi-node.cpp b/src/mmi/mmi-node.cpp index 1faffa9..47f7aff 100644 --- a/src/mmi/mmi-node.cpp +++ b/src/mmi/mmi-node.cpp @@ -52,6 +52,7 @@ int mmi_node_add_port(mmi_node_h node, mmi_port_h port) { return MMI_ERROR_NONE; } +// LCOV_EXCL_START int mmi_node_find_port(mmi_node_h node, mmi_port_type_e port_type, const char *port_name, mmi_port_h *port) { if (nullptr == node || nullptr == port_name || nullptr == port) { LOGE("[ERROR] parameter is null"); @@ -75,6 +76,7 @@ int mmi_node_link_by_name(mmi_node_h from_node, const char *from_port_name, mmi_ } return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP int mmi_node_get_type(mmi_node_h node, mmi_standard_node_type_e *type) { if (nullptr == node || nullptr == type) { @@ -182,6 +184,7 @@ int mmi_node_register(mmi_node_h node) { } break; } +// LCOV_EXCL_START case MMI_STANDARD_NODE_TYPE_CONTROLLER: { mmi_standard_node_controller_type_e node_controller_type; mmi_standard_node_get_controller_type(node, &node_controller_type); @@ -192,6 +195,17 @@ int mmi_node_register(mmi_node_h node) { } break; } + case MMI_STANDARD_NODE_TYPE_ACTION: { + mmi_standard_node_action_type_e node_action_type; + mmi_standard_node_get_action_type(node, &node_action_type); + mmi_standard_node_action_type_e action_type; + mmi_standard_node_get_action_type(nodes[i], &action_type); + if (node_action_type == action_type) { + duplicated = true; + } + break; + } +// LCOV_EXCL_STOP } } if (duplicated) { @@ -274,6 +288,7 @@ int mmi_node_destroy(mmi_node_h node) { return MMI_ERROR_NONE; } +// LCOV_EXCL_START int mmi_node_instance_set_attribute(mmi_node_instance_h instance, mmi_attribute_h attribute) { return MMI_ERROR_NONE; } @@ -305,3 +320,4 @@ int mmi_node_instance_emit_signal(mmi_node_instance_h instance, mmi_signal_h sig int mmi_node_instance_update_pending_activation_result(mmi_error_e result) { return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP diff --git a/src/mmi/mmi-port.cpp b/src/mmi/mmi-port.cpp index 2358a9e..9e3fc47 100644 --- a/src/mmi/mmi-port.cpp +++ b/src/mmi/mmi-port.cpp @@ -82,6 +82,7 @@ MMI_API int mmi_port_get_data_type(mmi_port_h port, mmi_data_type_e *data_type) return MMI_ERROR_NONE; } +// LCOV_EXCL_START MMI_API int mmi_port_get_callbacks(mmi_port_h port, mmi_port_callbacks *callbacks) { if (nullptr == port || nullptr == callbacks) { LOGE("[ERROR] parameter is null"); @@ -94,6 +95,7 @@ MMI_API int mmi_port_get_callbacks(mmi_port_h port, mmi_port_callbacks *callback return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP MMI_API int mmi_port_set_name(mmi_port_h port, const char *name) { if (nullptr == port || nullptr == name) { @@ -180,6 +182,7 @@ MMI_API int mmi_port_destroy(mmi_port_h port) { return MMI_ERROR_NONE; } +// LCOV_EXCL_START MMI_API int mmi_port_instance_generate_output(mmi_port_instance_h instance, mmi_data_h data) { mmi_plugin_module_event_handler_info_s event_handler_info = mmi_plugin_storage_get_plugin_module_event_handler(); void *user_data = mmi_plugin_storage_get_plugin_module_event_handler_user_data(); @@ -203,3 +206,4 @@ MMI_API int mmi_port_instance_request_input_data_format(mmi_port_instance_h inst MMI_API int mmi_port_instance_announce_output_data_format(mmi_port_instance_h instance, const char *format) { return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP diff --git a/src/mmi/mmi-signal.cpp b/src/mmi/mmi-signal.cpp index 1d2c97c..bee325b 100644 --- a/src/mmi/mmi-signal.cpp +++ b/src/mmi/mmi-signal.cpp @@ -19,123 +19,147 @@ #include "mmi.h" #include "mmi-signal.h" +#include "mmi-log.h" + MMI_API int mmi_signal_parameter_create(mmi_primitive_value_h value, const char *name, mmi_signal_parameter_h *signal_parameter) { if (signal_parameter == NULL) { - return -1; + return MMI_ERROR_INVALID_PARAMETER; + } + + const size_t length = strlen(name); + if (0 == length || MMI_NAME_MAX_LENGTH <= length) { + _E("[ERROR] Length of name is invalid. length(%zu)", length); + return MMI_ERROR_INVALID_PARAMETER; } *signal_parameter = (mmi_signal_parameter_s*)calloc(1, sizeof(mmi_signal_parameter_s)); - if (*signal_parameter == NULL) return -1; + if (*signal_parameter == NULL) return MMI_ERROR_OUT_OF_MEMORY; strncpy((*signal_parameter)->name, name, MMI_NAME_MAX_LENGTH - 1); (*signal_parameter)->name[MMI_NAME_MAX_LENGTH - 1] = '\0'; mmi_primitive_value_clone(value, &((*signal_parameter)->value)); - return 0; + return MMI_ERROR_NONE; } MMI_API int mmi_signal_parameter_get_name(mmi_signal_parameter_h signal_parameter, char **name) { if (signal_parameter == NULL || name == NULL) { - return -1; + return MMI_ERROR_INVALID_PARAMETER; } *name = strdup(signal_parameter->name); - return 0; + return MMI_ERROR_NONE; } MMI_API int mmi_signal_parameter_get_value(mmi_signal_parameter_h signal_parameter, mmi_primitive_value_h *value) { if (signal_parameter == NULL || value == NULL) { - return -1; + return MMI_ERROR_INVALID_PARAMETER; } mmi_primitive_value_clone(signal_parameter->value, value); - return 0; + return MMI_ERROR_NONE; } MMI_API int mmi_signal_parameter_clone(mmi_signal_parameter_h signal_parameter, mmi_signal_parameter_h *cloned) { if (cloned == NULL) { - return -1; + return MMI_ERROR_INVALID_PARAMETER; } *cloned = (mmi_signal_parameter_s*)calloc(1, sizeof(mmi_signal_parameter_s)); - if (*cloned == NULL) return -1; + if (*cloned == NULL) return MMI_ERROR_OUT_OF_MEMORY; strncpy((*cloned)->name, signal_parameter->name, MMI_NAME_MAX_LENGTH - 1); (*cloned)->name[MMI_NAME_MAX_LENGTH - 1] = '\0'; mmi_primitive_value_clone(signal_parameter->value, &((*cloned)->value)); - return 0; + return MMI_ERROR_NONE; } MMI_API int mmi_signal_parameter_destroy(mmi_signal_parameter_h signal_parameter) { if (signal_parameter == NULL) { - return -1; + return MMI_ERROR_INVALID_PARAMETER; } mmi_primitive_value_destroy(signal_parameter->value); free(signal_parameter); - return 0; + return MMI_ERROR_NONE; } MMI_API int mmi_signal_create(const char *name, mmi_signal_h *handle) { - if (handle == NULL) { - return -1; + if (handle == NULL || name == NULL) { + return MMI_ERROR_INVALID_PARAMETER; + } + + const size_t length = strlen(name); + if (0 == length || MMI_NAME_MAX_LENGTH <= length) { + _E("[ERROR] Length of name is invalid. length(%zu)", length); + return MMI_ERROR_INVALID_PARAMETER; } *handle = (mmi_signal_s*)calloc(1, sizeof(mmi_signal_s)); - if (*handle == NULL) return -1; + if (*handle == NULL) return MMI_ERROR_OUT_OF_MEMORY; strncpy((*handle)->name, name, MMI_NAME_MAX_LENGTH - 1); (*handle)->name[MMI_NAME_MAX_LENGTH - 1] = '\0'; - return 0; + return MMI_ERROR_NONE; } MMI_API int mmi_signal_add_parameter(mmi_signal_h handle, mmi_signal_parameter_h parameter) { if (handle == NULL || parameter == NULL) { - return -1; + return MMI_ERROR_INVALID_PARAMETER; } if (handle->parameter_count >= MMI_PARAMETER_MAX_COUNT) { - return -1; + return MMI_ERROR_INVALID_PARAMETER; + } + + bool duplicated_name = false; + for (int loop = 0;loop < handle->parameter_count; loop++) { + if (strncmp(handle->parameters[loop]->name, parameter->name, MMI_NAME_MAX_LENGTH) == 0) { + duplicated_name = true; + } + } + if (duplicated_name) { + return MMI_ERROR_INVALID_PARAMETER; } mmi_signal_parameter_clone(parameter, &handle->parameters[handle->parameter_count]); handle->parameter_count++; - return 0; + return MMI_ERROR_NONE; } MMI_API int mmi_signal_get_name(mmi_signal_h handle, char **name) { if (handle == NULL || name == NULL) { - return -1; + return MMI_ERROR_INVALID_PARAMETER; } - *name = handle->name; - return 0; + *name = strdup(handle->name); + return MMI_ERROR_NONE; } MMI_API int mmi_signal_get_parameter_count(mmi_signal_h handle, int *count) { if (handle == NULL || count == NULL) { - return -1; + return MMI_ERROR_INVALID_PARAMETER; } *count = handle->parameter_count; - return 0; + return MMI_ERROR_NONE; } MMI_API int mmi_signal_get_parameter(mmi_signal_h handle, int index, mmi_signal_parameter_h *parameter) { if (handle == NULL || parameter == NULL) { - return -1; + return MMI_ERROR_INVALID_PARAMETER; } if (index < 0 || index >= handle->parameter_count) { - return -1; + return MMI_ERROR_INVALID_PARAMETER; } mmi_signal_parameter_clone(handle->parameters[index], parameter); - return 0; + return MMI_ERROR_NONE; } MMI_API int mmi_signal_destroy(mmi_signal_h handle) { if (handle == NULL) { - return -1; + return MMI_ERROR_INVALID_PARAMETER; } for (int i = 0; i < handle->parameter_count; i++) { @@ -143,5 +167,5 @@ MMI_API int mmi_signal_destroy(mmi_signal_h handle) { } free(handle); - return 0; + return MMI_ERROR_NONE; } diff --git a/src/mmi/mmi-workflow-instance-manager.h b/src/mmi/mmi-workflow-instance-manager.h index ae6ff6e..f286cbb 100644 --- a/src/mmi/mmi-workflow-instance-manager.h +++ b/src/mmi/mmi-workflow-instance-manager.h @@ -48,6 +48,7 @@ public: return m_workflow_type; } +// LCOV_EXCL_START bool add_output_callback(std::string key, mmi_workflow_output_cb callback, void *user_data) { bool ret = false; if (callback) { @@ -66,6 +67,7 @@ public: } return ret; } +// LCOV_EXCL_STOP private: int m_local_workflow_instance_id; @@ -97,6 +99,15 @@ public: return newInstance; } + WorkflowInstance* get(int local_workflow_instance_id) { + for (auto &instance : m_instances) { + if (instance->get_local_workflow_instance_id() == local_workflow_instance_id) + return instance; + } + return nullptr; + } + +// LCOV_EXCL_START bool destroy(WorkflowInstance *instance) { bool ret = false; auto it = std::find(m_instances.begin(), m_instances.end(), instance); @@ -108,6 +119,7 @@ public: } return ret; } +// LCOV_EXCL_STOP private: int m_last_local_workflow_instance_id{0}; diff --git a/src/mmi/mmi-workflow-instance.cpp b/src/mmi/mmi-workflow-instance.cpp index 74d5844..fb2cea4 100644 --- a/src/mmi/mmi-workflow-instance.cpp +++ b/src/mmi/mmi-workflow-instance.cpp @@ -29,7 +29,6 @@ #include "mmi-client-manager.h" #include "mmi-log.h" #include "mmi-workflow-instance-manager.h" -#include "mmi_proxy.h" using namespace mmi; using namespace mmi::communication; @@ -52,7 +51,7 @@ MMI_API int mmi_standard_workflow_instance_create(mmi_standard_workflow_type_e t if (workflow_instance) { *instance = static_cast(workflow_instance); - CommunicationChannel *channel = g_mmi_client_manager.get_communication_channel(); + std::shared_ptr channel = g_mmi_client_manager.get_communication_channel(); if (channel) { ClientMessageWorkflowInstanceCreate msg; msg.local_workflow_instance_id = @@ -69,6 +68,7 @@ MMI_API int mmi_standard_workflow_instance_create(mmi_standard_workflow_type_e t return MMI_ERROR_NONE; } +// LCOV_EXCL_START MMI_API int mmi_workflow_instance_destroy(mmi_workflow_instance_h instance) { if (nullptr == instance) { LOGE("[ERROR] parameter is null"); @@ -81,7 +81,7 @@ MMI_API int mmi_workflow_instance_destroy(mmi_workflow_instance_h instance) { return MMI_ERROR_OPERATION_FAILED; } - CommunicationChannel *channel = g_mmi_client_manager.get_communication_channel(); + std::shared_ptr channel = g_mmi_client_manager.get_communication_channel(); if (channel) { ClientMessageWorkflowInstanceDestroy msg; WorkflowInstance *workflow_instance = static_cast(instance); @@ -94,6 +94,7 @@ MMI_API int mmi_workflow_instance_destroy(mmi_workflow_instance_h instance) { return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP MMI_API int mmi_workflow_instance_activate(mmi_workflow_instance_h instance) { if (nullptr == instance) { @@ -101,7 +102,7 @@ MMI_API int mmi_workflow_instance_activate(mmi_workflow_instance_h instance) { return MMI_ERROR_INVALID_PARAMETER; } - CommunicationChannel *channel = g_mmi_client_manager.get_communication_channel(); + std::shared_ptr channel = g_mmi_client_manager.get_communication_channel(); if (nullptr == channel) { LOGE("[ERROR] Failed to get channel"); return MMI_ERROR_OPERATION_FAILED; @@ -117,13 +118,14 @@ MMI_API int mmi_workflow_instance_activate(mmi_workflow_instance_h instance) { return MMI_ERROR_NONE; } +// LCOV_EXCL_START MMI_API int mmi_workflow_instance_deactivate(mmi_workflow_instance_h instance) { if (nullptr == instance) { LOGE("[ERROR] parameter is null"); return MMI_ERROR_INVALID_PARAMETER; } - CommunicationChannel *channel = g_mmi_client_manager.get_communication_channel(); + std::shared_ptr channel = g_mmi_client_manager.get_communication_channel(); if (nullptr == channel) { LOGE("[ERROR] Failed to get channel"); return MMI_ERROR_OPERATION_FAILED; @@ -138,6 +140,7 @@ MMI_API int mmi_workflow_instance_deactivate(mmi_workflow_instance_h instance) { return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP MMI_API int mmi_workflow_instance_set_attribute(mmi_workflow_instance_h instance, mmi_attribute_h attribute) { if (nullptr == instance) { @@ -145,7 +148,7 @@ MMI_API int mmi_workflow_instance_set_attribute(mmi_workflow_instance_h instance return MMI_ERROR_INVALID_PARAMETER; } - CommunicationChannel *channel = g_mmi_client_manager.get_communication_channel(); + std::shared_ptr channel = g_mmi_client_manager.get_communication_channel(); if (nullptr == channel) { LOGE("[ERROR] Failed to get channel"); return MMI_ERROR_OPERATION_FAILED; @@ -162,7 +165,30 @@ MMI_API int mmi_workflow_instance_set_attribute(mmi_workflow_instance_h instance return MMI_ERROR_NONE; } +MMI_API int mmi_workflow_instance_emit_signal(mmi_workflow_instance_h instance, mmi_signal_h signal) { + if (nullptr == instance) { + LOGE("[ERROR] parameter is null"); + return MMI_ERROR_INVALID_PARAMETER; + } + + std::shared_ptr channel = g_mmi_client_manager.get_communication_channel(); + if (nullptr == channel) { + LOGE("[ERROR] Failed to get channel"); + return MMI_ERROR_OPERATION_FAILED; + } + + WorkflowInstance *workflow_instance = static_cast(instance); + + ClientMessageWorkflowInstanceEmitSignal msg; + msg.local_workflow_instance_id = workflow_instance->get_local_workflow_instance_id(); + msg.signal = signal; + + channel->send(&msg); + + return MMI_ERROR_NONE; +} +// LCOV_EXCL_START MMI_API int mmi_workflow_instance_set_output_callback(mmi_workflow_instance_h instance, const char *name, mmi_workflow_output_cb callback, void *user_data) { if (nullptr == instance) { LOGE("[ERROR] parameter is null"); @@ -184,3 +210,4 @@ MMI_API int mmi_workflow_instance_set_output_callback(mmi_workflow_instance_h in return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP diff --git a/src/mmi/mmi-workflow-script-parser.h b/src/mmi/mmi-workflow-script-parser.h index d2e035d..0f20bfe 100644 --- a/src/mmi/mmi-workflow-script-parser.h +++ b/src/mmi/mmi-workflow-script-parser.h @@ -28,6 +28,7 @@ #include "mmi-node-processor.h" #include "mmi-node-logic.h" #include "mmi-node-controller.h" +#include "mmi-node-action.h" enum class WorkflowScriptSection { NONE, @@ -116,6 +117,7 @@ public: m_standard_node_source_names.push_back({MMI_STANDARD_NODE_SOURCE_TYPE_CAMERA, "CAMERA"}); m_standard_node_processor_names.push_back({MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR, "ASR"}); + m_standard_node_processor_names.push_back({MMI_STANDARD_NODE_PROCESSOR_TYPE_VIDEO_CONVERTER, "VIDEO_CONVERTER"}); m_standard_node_processor_names.push_back({MMI_STANDARD_NODE_PROCESSOR_TYPE_FACE_RECOGNITION, "FACE_RECOGNITION"}); m_standard_node_processor_names.push_back({MMI_STANDARD_NODE_PROCESSOR_TYPE_SPEAKER_RECOGNITION, "SPEAKER_RECOGNITION"}); @@ -448,6 +450,8 @@ private: workflow_s->attribute_assignment_info_count = 0; workflow_s->attribute_default_value_infos = nullptr; workflow_s->attribute_default_value_info_count = 0; + workflow_s->signal_assignment_infos = nullptr; + workflow_s->signal_assignment_info_count = 0; workflow_s->output_assignment_infos = nullptr; workflow_s->output_assignment_info_count = 0; diff --git a/src/mmi/mmi-workflow.cpp b/src/mmi/mmi-workflow.cpp index dcc7260..db6843a 100644 --- a/src/mmi/mmi-workflow.cpp +++ b/src/mmi/mmi-workflow.cpp @@ -49,6 +49,8 @@ MMI_API int mmi_workflow_create(mmi_workflow_h *workflow) { workflow_s->attribute_assignment_info_count = 0; workflow_s->attribute_default_value_infos = nullptr; workflow_s->attribute_default_value_info_count = 0; + workflow_s->signal_assignment_infos = nullptr; + workflow_s->signal_assignment_info_count = 0; workflow_s->output_assignment_infos = nullptr; workflow_s->output_assignment_info_count = 0; @@ -139,6 +141,10 @@ MMI_API int mmi_workflow_attribute_assign(mmi_workflow_h workflow, const char *a mmi_workflow_attribute_assignment_info_s *attribute_assignment_infos = workflow_s->attribute_assignment_infos; size_t attribute_assignment_info_count = workflow_s->attribute_assignment_info_count; workflow_s->attribute_assignment_infos = new(std::nothrow) mmi_workflow_attribute_assignment_info_s[attribute_assignment_info_count + 1]; + if (nullptr == workflow_s->attribute_assignment_infos) { + LOGE("[ERROR] Failed to allocate memory"); + return MMI_ERROR_OUT_OF_MEMORY; + } if (attribute_assignment_info_count > 0) { memcpy(workflow_s->attribute_assignment_infos, attribute_assignment_infos, sizeof(mmi_workflow_attribute_assignment_info_s) * attribute_assignment_info_count); delete [] attribute_assignment_infos; @@ -153,6 +159,7 @@ MMI_API int mmi_workflow_attribute_assign(mmi_workflow_h workflow, const char *a return MMI_ERROR_NONE; } +// LCOV_EXCL_START MMI_API int mmi_workflow_attribute_set_default_value(mmi_workflow_h workflow, mmi_attribute_h default_value) { if (nullptr == workflow || nullptr == default_value) { LOGE("[ERROR] parameter is null"); @@ -163,6 +170,11 @@ MMI_API int mmi_workflow_attribute_set_default_value(mmi_workflow_h workflow, mm mmi_workflow_attribute_default_value_info_s *attribute_default_value_infos = workflow_s->attribute_default_value_infos; size_t attribute_default_value_info_count = workflow_s->attribute_default_value_info_count; workflow_s->attribute_default_value_infos = new(std::nothrow) mmi_workflow_attribute_default_value_info_s[attribute_default_value_info_count + 1]; + if (nullptr == workflow_s->attribute_default_value_infos) { + LOGE("[ERROR] Failed to allocate memory"); + return MMI_ERROR_OUT_OF_MEMORY; + } + if (attribute_default_value_info_count > 0) { memcpy(workflow_s->attribute_default_value_infos, attribute_default_value_infos, sizeof(mmi_workflow_attribute_default_value_info_s) * attribute_default_value_info_count); delete [] attribute_default_value_infos; @@ -177,13 +189,35 @@ MMI_API int mmi_workflow_attribute_set_default_value(mmi_workflow_h workflow, mm return MMI_ERROR_NONE; } -MMI_API int mmi_workflow_signal_assign(mmi_workflow_h workflow, const char *workflow_signal, mmi_node_h node, const char *node_signal) { - if (nullptr == workflow || nullptr == workflow_signal || nullptr == node || nullptr == node_signal) { +MMI_API int mmi_workflow_signal_assign(mmi_workflow_h workflow, const char *signal_name, const char *target_node_name, const char *target_signal_name) { + if (nullptr == workflow || nullptr == signal_name || nullptr == target_node_name || nullptr == target_signal_name) { LOGE("[ERROR] parameter is null"); return MMI_ERROR_INVALID_PARAMETER; } + + mmi_workflow_s *workflow_s = static_cast(workflow); + mmi_workflow_signal_assignment_info_s *signal_assignment_infos = workflow_s->signal_assignment_infos; + size_t signal_assignment_info_count = workflow_s->signal_assignment_info_count; + workflow_s->signal_assignment_infos = new(std::nothrow) mmi_workflow_signal_assignment_info_s[signal_assignment_info_count + 1]; + if (nullptr == workflow_s->signal_assignment_infos) { + LOGE("[ERROR] Failed to allocate memory"); + return MMI_ERROR_OUT_OF_MEMORY; + } + + if (signal_assignment_info_count > 0) { + memcpy(workflow_s->signal_assignment_infos, signal_assignment_infos, sizeof(mmi_workflow_signal_assignment_info_s) * signal_assignment_info_count); + delete [] signal_assignment_infos; + } + + snprintf(workflow_s->signal_assignment_infos[signal_assignment_info_count].signal_name, MMI_NAME_MAX_LENGTH, "%s", signal_name); + snprintf(workflow_s->signal_assignment_infos[signal_assignment_info_count].target_node_name, MMI_NAME_MAX_LENGTH, "%s", target_node_name); + snprintf(workflow_s->signal_assignment_infos[signal_assignment_info_count].target_signal_name, MMI_NAME_MAX_LENGTH, "%s", target_signal_name); + + workflow_s->signal_assignment_info_count = signal_assignment_info_count + 1; + return MMI_ERROR_NONE; } +// LCOV_EXCL_STOP MMI_API int mmi_workflow_output_assign(mmi_workflow_h workflow, const char *workflow_output, const char *out_node_name, const char *node_out_port_name) { if (nullptr == workflow || nullptr == workflow_output || nullptr == out_node_name || nullptr == node_out_port_name) { diff --git a/src/mmi/mmi.cpp b/src/mmi/mmi.cpp index e49ec6e..88d10ec 100644 --- a/src/mmi/mmi.cpp +++ b/src/mmi/mmi.cpp @@ -24,7 +24,6 @@ #include #include "mmi-log.h" -#include "mmi-ipc-tidl.h" #include "mmi-client-manager.h" @@ -36,19 +35,12 @@ using namespace mmi::communication; static mmi_state_e g_mmi_state{MMI_STATE_NONE}; static std::vector> g_state_changed_cb_list; -struct CommunicationChannelFactoryTIDL : public ICommunicationChannelFactory { - CommunicationChannel* create_channel() override { - return new(std::nothrow) CommunicationChannelTIDL(); - } - void destroy_channel(CommunicationChannel* channel) override { - delete channel; - } -}; -static CommunicationChannelFactoryTIDL g_communication_channel_factory_tidl; +CommunicationChannelClientFactory g_communication_channel_factory; class CommunicationChannelObserver : public SimpleEventObserver { public: +// LCOV_EXCL_START void on_observer_event( const COMMUNICATION_CHANNEL_EVENT_TYPE &event, std::any data) override { mmi_state_e previous_state = g_mmi_state; @@ -65,11 +57,12 @@ public: } } } +// LCOV_EXCL_STOP }; static CommunicationChannelObserver g_communication_channel_observer; ClientManager g_mmi_client_manager{ - &g_communication_channel_factory_tidl, + &g_communication_channel_factory, &g_communication_channel_observer }; diff --git a/tests/mmi-manager/plugin-module-registry/mmi-plugin-module-registry-tests.cpp b/tests/mmi-manager/plugin-module-registry/mmi-plugin-module-registry-tests.cpp index d60dcde..66bc567 100644 --- a/tests/mmi-manager/plugin-module-registry/mmi-plugin-module-registry-tests.cpp +++ b/tests/mmi-manager/plugin-module-registry/mmi-plugin-module-registry-tests.cpp @@ -30,8 +30,9 @@ public: _D("Adding prototype : %d", prototype->is_valid()); m_prototypes.push_back(prototype); - _D("Node prototype added: type=%d, sub_type=%d, plugin_module_type=%d, plugin_module_identifier=%s", - prototype->get_type(), to_int(prototype->get_sub_type()), + _D("Node prototype added: type=%s, sub_type=%s, plugin_module_type=%d, plugin_module_identifier=%s", + enum_to_string(prototype->get_type()).c_str(), + to_string(prototype->get_sub_type()).c_str(), static_cast(prototype->get_plugin_module_info().plugin_module_type), prototype->get_plugin_module_info().plugin_module_identifier.c_str()); @@ -74,8 +75,10 @@ public: prototype->get_plugin_module_info().plugin_module_identifier.c_str()); _D(" node_infos:"); for (auto& elem : prototype->get_node_infos()) { - _D(" name=%s, node_type=%d, node_sub_type=%d", - elem.name.c_str(), elem.node_type, to_int(elem.node_sub_type)); + _D(" name=%s, node_type=%s, node_sub_type=%s", + elem.name.c_str(), + enum_to_string(elem.node_type).c_str(), + to_string(elem.node_sub_type).c_str()); } _D(" link_infos:"); for (auto& elem : prototype->get_link_infos()) { diff --git a/tests/mmi-manager/workflow-instance/mmi-workflow-instance-tests.cpp b/tests/mmi-manager/workflow-instance/mmi-workflow-instance-tests.cpp index 96d13b8..50cc718 100644 --- a/tests/mmi-manager/workflow-instance/mmi-workflow-instance-tests.cpp +++ b/tests/mmi-manager/workflow-instance/mmi-workflow-instance-tests.cpp @@ -26,10 +26,14 @@ int __wrap_vconf_get_int(const char *in_key, int *intval) class WorkflowPrototypeStoreDummy : public IWorkflowPrototypeStore { public: - bool add_workflow_prototype(std::shared_ptr prototype) override { - return true; - } - std::shared_ptr get_workflow_prototype(mmi_standard_workflow_type_e type) override { + WorkflowPrototypeStoreDummy() { + mmi_primitive_value_h value = nullptr; + mmi_primitive_value_create_string("Default", &value); + mmi_attribute_h default_value = nullptr; + mmi_attribute_create(value, "COMMAND", &default_value); + attribute_default_value_info.default_value = default_value; + mmi_primitive_value_destroy(value); + auto prototype = std::make_shared(); prototype->set_type(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND); @@ -39,12 +43,28 @@ public: prototype->add_node_info(mmi::NodeInfo{ "ASR", MMI_STANDARD_NODE_TYPE_PROCESSOR, MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR}); AttributeAssignmentInfo attribute_assignment_info; - attribute_assignment_info.attribute_name = "CANDIDATE"; + attribute_assignment_info.attribute_name = "COMMAND"; attribute_assignment_info.target_node_name = "ASR"; attribute_assignment_info.target_attribute_name = "CANDIDATE"; prototype->add_attribute_assignment_info(attribute_assignment_info); - return prototype; + prototype->add_attribute_default_value_info(attribute_default_value_info); + + workflow_prototype = prototype; + } + virtual ~WorkflowPrototypeStoreDummy() { + if (attribute_default_value_info.default_value) { + mmi_attribute_destroy(attribute_default_value_info.default_value); + } + } + + bool add_workflow_prototype(std::shared_ptr prototype) override { + return true; } + std::shared_ptr get_workflow_prototype(mmi_standard_workflow_type_e type) override { + return workflow_prototype; + } + std::shared_ptr workflow_prototype; + AttributeDefaultValueInfo attribute_default_value_info{nullptr}; }; class NodePrototypeStoreDummy : public INodePrototypeStore { @@ -66,6 +86,55 @@ public: std::vector> node_prototypes; }; +class NodeAttributeSetHistoryItem { +public: + NodeAttributeSetHistoryItem() {} + ~NodeAttributeSetHistoryItem() { + if (attribute) { + mmi_attribute_destroy(attribute); + } + } + void reset() { + type = MMI_STANDARD_NODE_TYPE_NONE; + sub_type = std::monostate(); + if (attribute) { + mmi_attribute_destroy(attribute); + attribute = nullptr; + } + } + void set_item( + mmi_standard_node_type_e type, + mmi_standard_node_sub_type_e sub_type, + mmi_attribute_h attribute) { + this->type = type; + this->sub_type = sub_type; + if (this->attribute) { + mmi_attribute_destroy(this->attribute); + } + mmi_attribute_clone(attribute, &(this->attribute)); + } + mmi_standard_node_type_e type{MMI_STANDARD_NODE_TYPE_NONE}; + mmi_standard_node_sub_type_e sub_type{std::monostate()}; + mmi_attribute_h attribute{nullptr}; +}; + +static NodeAttributeSetHistoryItem g_last_node_attribute_set_history; + +class NodeInstanceTest : public NodeInstance +{ +public: + NodeInstanceTest(mmi_standard_node_type_e node_type, mmi_standard_node_sub_type_e node_sub_type) : + NodeInstance(node_type, node_sub_type) { + } + virtual ~NodeInstanceTest() { + } + bool set_attribute(mmi_attribute_h attribute) override { + g_last_node_attribute_set_history.set_item( + get_node_type(), get_node_sub_type(), attribute); + return true; + } +}; + class NodeInstanceManagerDummy : public INodeInstanceManager { public: NodeInstanceManagerDummy() { @@ -89,7 +158,7 @@ public: virtual std::shared_ptr create_node_instance( mmi_standard_node_type_e node_type, mmi_standard_node_sub_type_e node_sub_type) override { - auto node_instance = std::make_shared(node_type, node_sub_type); + auto node_instance = std::make_shared(node_type, node_sub_type); if (node_instance) { node_instance->set_node_prototype_store(node_prototype_store); node_instance->set_plugin_module_proxy_provider(plugin_module_proxy_provider); @@ -162,18 +231,143 @@ public: }; TEST_F(WorkflowInstanceTest, WorkflowAttributePassedToNodeAttribute_p) { - ASSERT_NE(workflow_instance, nullptr); + EXPECT_NE(workflow_instance, nullptr); workflow_instance->initialize(); mmi_primitive_value_h value = nullptr; - mmi_primitive_value_create_int(5, &value); + mmi_primitive_value_create_string("Hello", &value); mmi_attribute_h attribute = nullptr; - mmi_attribute_create(value, "CANDIDATE", &attribute); - ASSERT_TRUE(workflow_instance->set_attribute(attribute)); + mmi_attribute_create(value, "COMMAND", &attribute); + EXPECT_TRUE(workflow_instance->set_attribute(attribute)); + EXPECT_EQ(g_last_node_attribute_set_history.type, MMI_STANDARD_NODE_TYPE_PROCESSOR); + EXPECT_TRUE(std::holds_alternative(g_last_node_attribute_set_history.sub_type)); + EXPECT_EQ(std::get(g_last_node_attribute_set_history.sub_type), + MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR); + EXPECT_TRUE(g_last_node_attribute_set_history.attribute != nullptr); + + mmi_primitive_value_h history_item_value; + mmi_attribute_get_value(g_last_node_attribute_set_history.attribute, &history_item_value); + + mmi_primitive_value_type_e type; + mmi_primitive_value_get_type(history_item_value, &type); + EXPECT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_STRING); + + const char* str; + mmi_primitive_value_get_string(history_item_value, &str); + EXPECT_STREQ(str, "Hello"); + + mmi_primitive_value_destroy(history_item_value); + workflow_instance->deinitialize(); mmi_attribute_destroy(attribute); mmi_primitive_value_destroy(value); } +TEST_F(WorkflowInstanceTest, WorkflowAttributePassedProperlyAfter2ndInitialization_p) { + EXPECT_NE(workflow_instance, nullptr); + workflow_instance.reset(); + workflow_instance = std::make_shared(); + if (workflow_instance) { + workflow_instance->set_type(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND); + + workflow_instance->set_workflow_prototype_store(workflow_prototype_store); + workflow_instance->set_plugin_module_proxy_provider(plugin_module_proxy_provider); + workflow_instance->set_node_instance_manager(node_instance_manager); + } + EXPECT_NE(workflow_instance, nullptr); + workflow_instance->initialize(); + mmi_primitive_value_h value = nullptr; + mmi_primitive_value_create_string("Hello", &value); + mmi_attribute_h attribute = nullptr; + mmi_attribute_create(value, "COMMAND", &attribute); + EXPECT_TRUE(workflow_instance->set_attribute(attribute)); + EXPECT_EQ(g_last_node_attribute_set_history.type, MMI_STANDARD_NODE_TYPE_PROCESSOR); + EXPECT_TRUE(std::holds_alternative(g_last_node_attribute_set_history.sub_type)); + EXPECT_EQ(std::get(g_last_node_attribute_set_history.sub_type), + MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR); + EXPECT_TRUE(g_last_node_attribute_set_history.attribute != nullptr); + + mmi_primitive_value_h history_item_value; + mmi_attribute_get_value(g_last_node_attribute_set_history.attribute, &history_item_value); + + mmi_primitive_value_type_e type; + mmi_primitive_value_get_type(history_item_value, &type); + EXPECT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_STRING); + + const char* str; + mmi_primitive_value_get_string(history_item_value, &str); + EXPECT_STREQ(str, "Hello"); + + mmi_primitive_value_destroy(history_item_value); + + workflow_instance->deinitialize(); + mmi_attribute_destroy(attribute); + mmi_primitive_value_destroy(value); +} + +TEST_F(WorkflowInstanceTest, WorkflowDefaultAttributePassedToNodeAttribute_p) { + g_last_node_attribute_set_history.reset(); + + EXPECT_NE(workflow_instance, nullptr); + workflow_instance->initialize(); + EXPECT_EQ(g_last_node_attribute_set_history.type, MMI_STANDARD_NODE_TYPE_PROCESSOR); + EXPECT_TRUE(std::holds_alternative(g_last_node_attribute_set_history.sub_type)); + EXPECT_EQ(std::get(g_last_node_attribute_set_history.sub_type), + MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR); + EXPECT_TRUE(g_last_node_attribute_set_history.attribute != nullptr); + + mmi_primitive_value_h history_item_value; + mmi_attribute_get_value(g_last_node_attribute_set_history.attribute, &history_item_value); + + mmi_primitive_value_type_e type; + mmi_primitive_value_get_type(history_item_value, &type); + EXPECT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_STRING); + + const char* str; + mmi_primitive_value_get_string(history_item_value, &str); + EXPECT_STREQ(str, "Default"); + + mmi_primitive_value_destroy(history_item_value); + + workflow_instance->deinitialize(); +} + +TEST_F(WorkflowInstanceTest, WorkflowDefaultAttributePassedProperlyAfter2ndInitialization_p) { + EXPECT_NE(workflow_instance, nullptr); + workflow_instance->initialize(); + workflow_instance->deinitialize(); + + g_last_node_attribute_set_history.reset(); + + EXPECT_NE(workflow_instance, nullptr); + workflow_instance->initialize(); + + EXPECT_EQ(g_last_node_attribute_set_history.type, MMI_STANDARD_NODE_TYPE_PROCESSOR); + EXPECT_TRUE(std::holds_alternative(g_last_node_attribute_set_history.sub_type)); + EXPECT_EQ(std::get(g_last_node_attribute_set_history.sub_type), + MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR); + EXPECT_TRUE(g_last_node_attribute_set_history.attribute != nullptr); + + char *name = nullptr; + mmi_attribute_get_name(g_last_node_attribute_set_history.attribute, &name); + EXPECT_STREQ(name, "CANDIDATE"); + free(name); + + mmi_primitive_value_h history_item_value; + mmi_attribute_get_value(g_last_node_attribute_set_history.attribute, &history_item_value); + + mmi_primitive_value_type_e type; + mmi_primitive_value_get_type(history_item_value, &type); + EXPECT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_STRING); + + const char* str; + mmi_primitive_value_get_string(history_item_value, &str); + EXPECT_STREQ(str, "Default"); + + mmi_primitive_value_destroy(history_item_value); + + workflow_instance->deinitialize(); +} + #ifdef TEST_MAIN_REQUIRED int main(int argc, char** argv) { std::cout << "Starting tests" << std::endl; diff --git a/tests/mmi/meson.build b/tests/mmi/meson.build index 4834a64..ad61818 100644 --- a/tests/mmi/meson.build +++ b/tests/mmi/meson.build @@ -4,6 +4,7 @@ mmi_tests_srcs = [ 'mmi-ipc-test.cpp', 'mmi-data-test.cpp', 'attribute/mmi-attribute-test.cpp', + 'signal/mmi-signal-test.cpp', 'primitive-value/mmi-primitive-value-test.cpp', 'workflow/mmi-workflow-test.cpp', ] diff --git a/tests/mmi/mmi-data-test.cpp b/tests/mmi/mmi-data-test.cpp index 393acb0..626449c 100644 --- a/tests/mmi/mmi-data-test.cpp +++ b/tests/mmi/mmi-data-test.cpp @@ -88,6 +88,24 @@ TEST_F(MMIDataTest, MMIDataCreateDataByAudio_n) { EXPECT_EQ(mmi_data_create_audio(sourceValue, DATA_LENGTH, nullptr), MMI_ERROR_INVALID_PARAMETER); } +TEST_F(MMIDataTest, MMIDataCreateDataByCoordinate_p) { + constexpr int x = 123; + constexpr int y = 456; + + ASSERT_EQ(mmi_data_create_coordinate(x, y, &mmiData), MMI_ERROR_NONE); + ASSERT_NE(mmiData, nullptr); +} + +TEST_F(MMIDataTest, MMIDataCreateDataByBoundingBox_p) { + constexpr int x = 12; + constexpr int y = 34; + constexpr int w = 56; + constexpr int h = 78; + + ASSERT_EQ(mmi_data_create_bounding_box(x, y, w, h, &mmiData), MMI_ERROR_NONE); + ASSERT_NE(mmiData, nullptr); +} + TEST_F(MMIDataTest, MMIDataCreateDataByArray_p) { EXPECT_EQ(mmi_data_create_array(&mmiData), MMI_ERROR_NONE); ASSERT_NE(mmiData, nullptr); @@ -231,6 +249,18 @@ TEST_F(MMIDataTest, MMIDataGetType_p) { EXPECT_EQ(mmi_data_destroy(tempValue), MMI_ERROR_NONE); tempValue = nullptr; + EXPECT_EQ(mmi_data_create_coordinate(123, 456, &tempValue), MMI_ERROR_NONE); + EXPECT_EQ(mmi_data_get_type(tempValue, &type), MMI_ERROR_NONE); + EXPECT_EQ(type, MMI_DATA_TYPE_COORDINATE); + EXPECT_EQ(mmi_data_destroy(tempValue), MMI_ERROR_NONE); + tempValue = nullptr; + + EXPECT_EQ(mmi_data_create_bounding_box(12, 34, 56, 78, &tempValue), MMI_ERROR_NONE); + EXPECT_EQ(mmi_data_get_type(tempValue, &type), MMI_ERROR_NONE); + EXPECT_EQ(type, MMI_DATA_TYPE_BOUNDING_BOX); + EXPECT_EQ(mmi_data_destroy(tempValue), MMI_ERROR_NONE); + tempValue = nullptr; + constexpr size_t length = 10; constexpr char sourceValue[length] = {1, }; EXPECT_EQ(mmi_data_create_audio(sourceValue, length, &tempValue), MMI_ERROR_NONE); @@ -319,6 +349,92 @@ TEST_F(MMIDataTest, MMIDataGetTextValue_n2) { EXPECT_EQ(mmi_data_get_text(mmiData, &textInData), MMI_ERROR_INVALID_PARAMETER); } +TEST_F(MMIDataTest, MMIDataGetCoordinateValue_p) { + constexpr int sourceX = 123; + constexpr int sourceY = 456; + ASSERT_EQ(mmi_data_create_coordinate(sourceX, sourceY, &mmiData), MMI_ERROR_NONE); + ASSERT_NE(mmiData, nullptr); + + int targetX = -1; + int targetY = -1; + EXPECT_EQ(mmi_data_get_coordinate(mmiData, &targetX, &targetY), MMI_ERROR_NONE); + EXPECT_EQ(targetX, sourceX); + EXPECT_EQ(targetY, sourceY); +} + +TEST_F(MMIDataTest, MMIDataGetCoordinateValue_n1) { + constexpr int sourceX = 123; + constexpr int sourceY = 456; + ASSERT_EQ(mmi_data_create_coordinate(sourceX, sourceY, &mmiData), MMI_ERROR_NONE); + ASSERT_NE(mmiData, nullptr); + + int targetX = -1; + int targetY = -1; + EXPECT_EQ(mmi_data_get_coordinate(nullptr, &targetX, &targetY), MMI_ERROR_INVALID_PARAMETER); + EXPECT_EQ(mmi_data_get_coordinate(mmiData, nullptr, &targetY), MMI_ERROR_INVALID_PARAMETER); + EXPECT_EQ(mmi_data_get_coordinate(mmiData, &targetX, nullptr), MMI_ERROR_INVALID_PARAMETER); +} + +TEST_F(MMIDataTest, MMIDataGetCoordinateValue_n2) { + constexpr const char *sourceText = "Hello"; + ASSERT_EQ(mmi_data_create_text(sourceText, &mmiData), MMI_ERROR_NONE); + ASSERT_NE(mmiData, nullptr); + + int targetX = -1; + int targetY = -1; + EXPECT_EQ(mmi_data_get_coordinate(mmiData, &targetX, &targetY), MMI_ERROR_INVALID_PARAMETER); +} + +TEST_F(MMIDataTest, MMIDataGetBoundingBoxValue_p) { + constexpr int sourceX = 12; + constexpr int sourceY = 34; + constexpr int sourceW = 56; + constexpr int sourceH = 78; + ASSERT_EQ(mmi_data_create_bounding_box(sourceX, sourceY, sourceW, sourceH, &mmiData), MMI_ERROR_NONE); + ASSERT_NE(mmiData, nullptr); + + int targetX = -1; + int targetY = -1; + int targetW = -1; + int targetH = -1; + EXPECT_EQ(mmi_data_get_bounding_box(mmiData, &targetX, &targetY, &targetW, &targetH), MMI_ERROR_NONE); + EXPECT_EQ(targetX, sourceX); + EXPECT_EQ(targetY, sourceY); + EXPECT_EQ(targetW, sourceW); + EXPECT_EQ(targetH, sourceH); +} + +TEST_F(MMIDataTest, MMIDataGetBoundingBoxValue_n1) { + constexpr int sourceX = 12; + constexpr int sourceY = 34; + constexpr int sourceW = 56; + constexpr int sourceH = 78; + ASSERT_EQ(mmi_data_create_bounding_box(sourceX, sourceY, sourceW, sourceH, &mmiData), MMI_ERROR_NONE); + ASSERT_NE(mmiData, nullptr); + + int targetX = -1; + int targetY = -1; + int targetW = -1; + int targetH = -1; + EXPECT_EQ(mmi_data_get_bounding_box(nullptr, &targetX, &targetY, &targetW, &targetH), MMI_ERROR_INVALID_PARAMETER); + EXPECT_EQ(mmi_data_get_bounding_box(mmiData, nullptr, &targetY, &targetW, &targetH), MMI_ERROR_INVALID_PARAMETER); + EXPECT_EQ(mmi_data_get_bounding_box(mmiData, &targetX, nullptr, &targetW, &targetH), MMI_ERROR_INVALID_PARAMETER); + EXPECT_EQ(mmi_data_get_bounding_box(mmiData, &targetX, &targetY, nullptr, &targetH), MMI_ERROR_INVALID_PARAMETER); + EXPECT_EQ(mmi_data_get_bounding_box(mmiData, &targetX, &targetY, &targetW, nullptr), MMI_ERROR_INVALID_PARAMETER); +} + +TEST_F(MMIDataTest, MMIDataGetBoundingBoxValue_n2) { + constexpr const char *sourceText = "Hello"; + ASSERT_EQ(mmi_data_create_text(sourceText, &mmiData), MMI_ERROR_NONE); + ASSERT_NE(mmiData, nullptr); + + int targetX = -1; + int targetY = -1; + int targetW = -1; + int targetH = -1; + EXPECT_EQ(mmi_data_get_bounding_box(mmiData, &targetX, &targetY, &targetW, &targetH), MMI_ERROR_INVALID_PARAMETER); +} + TEST_F(MMIDataTest, MMIDataGetArrayCount_p) { ASSERT_EQ(mmi_data_create_array(&mmiData), MMI_ERROR_NONE); ASSERT_NE(mmiData, nullptr); diff --git a/tests/mmi/mmi-ipc-test.cpp b/tests/mmi/mmi-ipc-test.cpp index 2574314..7604dcb 100644 --- a/tests/mmi/mmi-ipc-test.cpp +++ b/tests/mmi/mmi-ipc-test.cpp @@ -17,10 +17,8 @@ #include "mmi.h" #include "mmi-tests.h" -#include "mmi-ipc-tidl.h" #include -#include static mmi_state_e g_state = MMI_STATE_NONE; static int state_changed_cb(mmi_state_e state, void *user_data) { diff --git a/tests/mmi/mmi-main-test.cpp b/tests/mmi/mmi-main-test.cpp index 1abb86a..aec1353 100644 --- a/tests/mmi/mmi-main-test.cpp +++ b/tests/mmi/mmi-main-test.cpp @@ -17,10 +17,8 @@ #include "mmi.h" #include "mmi-tests.h" -#include "mmi-ipc-tidl.h" #include -#include static int state_changed_cb(mmi_state_e state, void *user_data) { return MMI_ERROR_NONE; diff --git a/tests/mmi/signal/mmi-signal-test.cpp b/tests/mmi/signal/mmi-signal-test.cpp new file mode 100644 index 0000000..1bbfc31 --- /dev/null +++ b/tests/mmi/signal/mmi-signal-test.cpp @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2023 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 + +#include +#include + + +class MMISignalTest : public ::testing::Test { +public: + void SetUp(void) override { + } + + void TearDown(void) override { + } +}; + +TEST_F(MMISignalTest, MMISignalCreate_p) { + mmi_signal_h signal = nullptr; + constexpr const char *name = "signal"; + EXPECT_EQ(mmi_signal_create(name, &signal), MMI_ERROR_NONE); + EXPECT_NE(signal, nullptr); + + mmi_signal_destroy(signal); +} + +TEST_F(MMISignalTest, MMISignalCreate_n1) { + mmi_signal_h signal = nullptr; + + constexpr const char *name = "signal"; + EXPECT_EQ(mmi_signal_create(nullptr, &signal), MMI_ERROR_INVALID_PARAMETER); + EXPECT_EQ(mmi_signal_create(name, nullptr), MMI_ERROR_INVALID_PARAMETER); + + if (signal) mmi_signal_destroy(signal); +} + +TEST_F(MMISignalTest, MMISignalCreate_n2) { + mmi_signal_h signal = nullptr; + + EXPECT_EQ(mmi_signal_create("", &signal), MMI_ERROR_INVALID_PARAMETER); + + constexpr size_t NAME_LENGTH = 300; + char name[NAME_LENGTH]; + for (auto &c : name) { + c = 'a'; + } + name[NAME_LENGTH - 1] = 0; + EXPECT_EQ(mmi_signal_create(name, &signal), MMI_ERROR_INVALID_PARAMETER); + + if (signal) mmi_signal_destroy(signal); +} + +TEST_F(MMISignalTest, MMISignalGetName_p) { + mmi_signal_h signal = nullptr; + constexpr const char *name = "signal"; + EXPECT_EQ(mmi_signal_create(name, &signal), MMI_ERROR_NONE); + EXPECT_NE(signal, nullptr); + + char *temp_name = nullptr; + EXPECT_EQ(mmi_signal_get_name(signal, &temp_name), MMI_ERROR_NONE); + EXPECT_NE(temp_name, nullptr); + EXPECT_STREQ(temp_name, name); + free(temp_name); + + mmi_signal_destroy(signal); +} + +TEST_F(MMISignalTest, MMISignalGetName_n) { + mmi_signal_h signal = nullptr; + constexpr const char *name = "signal"; + EXPECT_EQ(mmi_signal_create(name, &signal), MMI_ERROR_NONE); + EXPECT_NE(signal, nullptr); + + char *temp_name = nullptr; + EXPECT_EQ(mmi_signal_get_name(nullptr, &temp_name), MMI_ERROR_INVALID_PARAMETER); + EXPECT_EQ(mmi_signal_get_name(signal, nullptr), MMI_ERROR_INVALID_PARAMETER); + + mmi_signal_destroy(signal); +} + +TEST_F(MMISignalTest, MMISignalAddParameter_p) { + mmi_signal_h signal = nullptr; + constexpr const char *name = "signal"; + EXPECT_EQ(mmi_signal_create(name, &signal), MMI_ERROR_NONE); + EXPECT_NE(signal, nullptr); + + mmi_primitive_value_h value = nullptr; + EXPECT_EQ(mmi_primitive_value_create_int(100, &value), MMI_ERROR_NONE); + EXPECT_NE(value, nullptr); + + mmi_signal_parameter_h parameter = nullptr; + mmi_signal_parameter_create(value, "parameter", ¶meter); + EXPECT_EQ(mmi_signal_add_parameter(signal, parameter), MMI_ERROR_NONE); + + mmi_signal_parameter_destroy(parameter); + mmi_primitive_value_destroy(value); + + mmi_signal_destroy(signal); +} + +TEST_F(MMISignalTest, MMISignalAddParameter_n) { + mmi_primitive_value_h value = nullptr; + EXPECT_EQ(mmi_primitive_value_create_int(100, &value), MMI_ERROR_NONE); + EXPECT_NE(value, nullptr); + + mmi_signal_parameter_h parameter = nullptr; + mmi_signal_parameter_create(value, "parameter", ¶meter); + EXPECT_EQ(mmi_signal_add_parameter(nullptr, parameter), MMI_ERROR_INVALID_PARAMETER); + + mmi_signal_parameter_destroy(parameter); + mmi_primitive_value_destroy(value); +} + +TEST_F(MMISignalTest, MMISignalAddParameter_n2) { + mmi_signal_h signal = nullptr; + constexpr const char *name = "signal"; + EXPECT_EQ(mmi_signal_create(name, &signal), MMI_ERROR_NONE); + EXPECT_NE(signal, nullptr); + + mmi_signal_parameter_h parameter = nullptr; + EXPECT_EQ(mmi_signal_add_parameter(signal, parameter), MMI_ERROR_INVALID_PARAMETER); + + mmi_signal_destroy(signal); +} + +TEST_F(MMISignalTest, MMISignalAddParameters_p) { + mmi_signal_h signal = nullptr; + constexpr const char *name = "signal"; + EXPECT_EQ(mmi_signal_create(name, &signal), MMI_ERROR_NONE); + EXPECT_NE(signal, nullptr); + + mmi_primitive_value_h value_1 = nullptr; + EXPECT_EQ(mmi_primitive_value_create_int(100, &value_1), MMI_ERROR_NONE); + EXPECT_NE(value_1, nullptr); + + mmi_primitive_value_h value_2 = nullptr; + EXPECT_EQ(mmi_primitive_value_create_string("Hello", &value_2), MMI_ERROR_NONE); + EXPECT_NE(value_2, nullptr); + + mmi_signal_parameter_h parameter_1 = nullptr; + mmi_signal_parameter_create(value_1, "parameter_1", ¶meter_1); + EXPECT_EQ(mmi_signal_add_parameter(signal, parameter_1), MMI_ERROR_NONE); + + mmi_signal_parameter_h parameter_2 = nullptr; + mmi_signal_parameter_create(value_2, "parameter_2", ¶meter_2); + EXPECT_EQ(mmi_signal_add_parameter(signal, parameter_2), MMI_ERROR_NONE); + + mmi_signal_parameter_destroy(parameter_2); + mmi_signal_parameter_destroy(parameter_1); + + mmi_primitive_value_destroy(value_2); + mmi_primitive_value_destroy(value_1); + + mmi_signal_destroy(signal); +} + +TEST_F(MMISignalTest, MMISignalAddParameters_n) { + mmi_signal_h signal = nullptr; + constexpr const char *name = "signal"; + EXPECT_EQ(mmi_signal_create(name, &signal), MMI_ERROR_NONE); + EXPECT_NE(signal, nullptr); + + mmi_primitive_value_h value_1 = nullptr; + EXPECT_EQ(mmi_primitive_value_create_int(100, &value_1), MMI_ERROR_NONE); + EXPECT_NE(value_1, nullptr); + + mmi_primitive_value_h value_2 = nullptr; + EXPECT_EQ(mmi_primitive_value_create_string("Hello", &value_2), MMI_ERROR_NONE); + EXPECT_NE(value_2, nullptr); + + mmi_signal_parameter_h parameter_1 = nullptr; + mmi_signal_parameter_create(value_1, "parameter_1", ¶meter_1); + EXPECT_EQ(mmi_signal_add_parameter(signal, parameter_1), MMI_ERROR_NONE); + + /* Parameter with already-existing name */ + mmi_signal_parameter_h parameter_2 = nullptr; + mmi_signal_parameter_create(value_2, "parameter_1", ¶meter_2); + EXPECT_EQ(mmi_signal_add_parameter(signal, parameter_2), MMI_ERROR_INVALID_PARAMETER); + + mmi_signal_parameter_destroy(parameter_2); + mmi_signal_parameter_destroy(parameter_1); + + mmi_primitive_value_destroy(value_2); + mmi_primitive_value_destroy(value_1); + + mmi_signal_destroy(signal); +} + +TEST_F(MMISignalTest, MMISignalGetParameterValue_p) { + mmi_signal_h signal = nullptr; + constexpr const char *name = "signal"; + EXPECT_EQ(mmi_signal_create(name, &signal), MMI_ERROR_NONE); + EXPECT_NE(signal, nullptr); + + mmi_primitive_value_h value = nullptr; + EXPECT_EQ(mmi_primitive_value_create_int(100, &value), MMI_ERROR_NONE); + EXPECT_NE(value, nullptr); + + mmi_signal_parameter_h parameter = nullptr; + mmi_signal_parameter_create(value, "parameter", ¶meter); + EXPECT_EQ(mmi_signal_add_parameter(signal, parameter), MMI_ERROR_NONE); + + mmi_signal_parameter_h temp_parameter = nullptr; + EXPECT_EQ(mmi_signal_get_parameter(signal, 0, &temp_parameter), MMI_ERROR_NONE); + EXPECT_NE(temp_parameter, nullptr); + + char *temp_parameter_name = nullptr; + EXPECT_EQ(mmi_signal_parameter_get_name(temp_parameter, &temp_parameter_name), MMI_ERROR_NONE); + EXPECT_STREQ(temp_parameter_name, "parameter"); + free(temp_parameter_name); + + mmi_primitive_value_h temp_value = nullptr; + EXPECT_EQ(mmi_signal_parameter_get_value(temp_parameter, &temp_value), MMI_ERROR_NONE); + EXPECT_NE(temp_value, nullptr); + + mmi_primitive_value_type_e type; + mmi_primitive_value_type_e temp_type; + + mmi_primitive_value_get_type(value, &type); + mmi_primitive_value_get_type(temp_value, &temp_type); + + EXPECT_EQ(type, temp_type); + + int temp_int = 0; + EXPECT_EQ(mmi_primitive_value_get_int(temp_value, &temp_int), MMI_ERROR_NONE); + EXPECT_EQ(temp_int, 100); + + mmi_signal_parameter_destroy(temp_parameter); + mmi_signal_parameter_destroy(parameter); + + mmi_primitive_value_destroy(temp_value); + mmi_primitive_value_destroy(value); + + mmi_signal_destroy(signal); +} + +TEST_F(MMISignalTest, MMISignalDestroy_p1) { + mmi_signal_h signal = nullptr; + constexpr const char *name = "signal"; + EXPECT_EQ(mmi_signal_create(name, &signal), MMI_ERROR_NONE); + EXPECT_NE(signal, nullptr); + + EXPECT_EQ(mmi_signal_destroy(signal), MMI_ERROR_NONE); + signal = nullptr; +} + +TEST_F(MMISignalTest, MMISignalDestroy_n) { + EXPECT_EQ(mmi_signal_destroy(nullptr), MMI_ERROR_INVALID_PARAMETER); +} diff --git a/tidl/mmi.tidl b/tidl/mmi.tidl index 3d5f6f0..aec62ab 100644 --- a/tidl/mmi.tidl +++ b/tidl/mmi.tidl @@ -4,6 +4,7 @@ interface mmi { int workflow_instance_create(in int local_workflow_instance_id, in int workflow_type); int workflow_instance_destroy(in int local_workflow_instance_id); int workflow_instance_set_attribute(in int local_workflow_instance_id, in bundle attribute); + int workflow_instance_emit_signal(in int local_workflow_instance_id, in bundle signal); int workflow_instance_activate(in int local_workflow_instance_id); int workflow_instance_deactivate(in int local_workflow_instance_id); int workflow_instance_register_result_callback(in int local_workflow_instance_id, result_cb callback);