# the repo. Unless a later match takes precedence,
# @global-owner1 and @global-owner2 will be requested for
# review when someone opens a pull request.
-* @TizenWS/mmi-iu-and-voice
+* @Tizen-Interaction/MMI_FW
-# MMI(Multi-modal Interaction) Framework Library
-
-[Source Tree]
+# MMI(Multi-modal Interaction) Framework Library
+
+```
+[Source Tree]
.
+├── capi
+│ ├── meson.build
+│ ├── mmi-attribute.h
+│ ├── mmi-data.h
+│ ├── mmi-error.h
+│ ├── mmi.h
+│ ├── mmi-node-gate.h
+│ ├── mmi-node.h
+│ ├── mmi-node-processor.h
+│ ├── mmi-node-source.h
+│ ├── mmi-port.h
+│ ├── mmi-primitive-value.h
+│ ├── mmi-signal.h
+│ └── mmi-workflow.h
├── CODEOWNERS
├── COPYING
├── meson.build
├── meson_options.txt
├── packaging
-│ ├── mmi.manifest
-│ └── mmi.spec
-├── README.md
-├── src
-│ ├── interface
-│ │ ├── mmi_proxy.c
-│ │ └── mmi_proxy.h
-│ ├── meson.build
-│ ├── mmi.c
-│ └── mmi.h
-├── tests
-│ ├── meson.build
-│ ├── mmi-tests.cpp
-│ └── mmi-tests.h
-└── tidl
- └── mmi.tidl
-
+│ ├── mmi.manifest
+│ └── mmi.spec
+├── README.md
+├── src
+│ ├── common
+│ │ ├── mmi-communication-channel.h
+│ │ ├── mmi-communication-message.h
+│ │ └── mmi-event-observer.h
+│ ├── meson.build
+│ ├── mmi-attribute.cpp
+│ ├── mmi-client-manager.h
+│ ├── mmi.cpp
+│ ├── mmi-data.cpp
+│ ├── mmi-ipc-tidl.cpp
+│ ├── mmi-ipc-tidl.h
+│ ├── mmi-log.h
+│ ├── mmi-node.cpp
+│ ├── mmi-node-gate.cpp
+│ ├── mmi-node-processor.cpp
+│ ├── mmi-node-source.cpp
+│ ├── mmi-port.cpp
+│ ├── mmi-primitive-value.cpp
+│ ├── mmi-signal.cpp
+│ ├── mmi-workflow.cpp
+│ └── mmi-workflow-instance-manager.h
+├── tests
+│ ├── meson.build
+│ ├── mmi-attribute-test.cpp
+│ ├── mmi-data-test.cpp
+│ ├── mmi-ipc-test.cpp
+│ ├── mmi-main-test.cpp
+│ ├── mmi-primitive-value-test.cpp
+│ ├── mmi-tests.cpp
+│ └── mmi-tests.h
+└── tidl
+ └── mmi.tidl
+```
--- /dev/null
+install_headers(
+ 'mmi-primitive-value.h',
+ 'mmi-data.h',
+ 'mmi-attribute.h',
+ 'mmi-error.h',
+ 'mmi-workflow.h',
+ 'mmi-node.h',
+ 'mmi-node-source.h',
+ 'mmi-node-processor.h',
+ 'mmi-node-logic.h',
+ 'mmi-port.h',
+ 'mmi-signal.h',
+ 'mmi-defines.h',
+ 'mmi-plugin-module.h',
+ 'mmi-plugin-storage.h',
+ 'mmi.h',
+ )
--- /dev/null
+/*
+ * 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_ATTRIBUTE_H__
+#define __TIZEN_UIX_MMI_ATTRIBUTE_H__
+
+
+#include <tizen.h>
+#include <stdlib.h>
+#include <mmi-primitive-value.h>
+
+
+/**
+* @file mmi-attribute.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct mmi_attribute_s* mmi_attribute_h;
+
+
+int mmi_attribute_create(mmi_primitive_value_h value, const char *name, mmi_attribute_h *attribute);
+
+int mmi_attribute_set_name(mmi_attribute_h attribute, const char *name);
+
+int mmi_attribute_get_name(mmi_attribute_h attribute, char **name);
+
+int mmi_attribute_get_value(mmi_attribute_h attribute, mmi_primitive_value_h *value);
+
+int mmi_attribute_clone(mmi_attribute_h attribute, mmi_attribute_h *cloned);
+
+int mmi_attribute_destroy(mmi_attribute_h attribute);
+
+int mmi_attribute_to_bytes(mmi_attribute_h attribute, unsigned char **bytes, size_t *length);
+
+int mmi_attribute_from_bytes(const unsigned char *bytes, size_t length, mmi_attribute_h *attribute);
+
+/* Utility functions */
+int mmi_attribute_create_string_array(const char *name, const char *strings[], size_t count, mmi_attribute_h *attribute);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_ATTRIBUTE_H__ */
--- /dev/null
+/*
+ * 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_DATA_H__
+#define __TIZEN_UIX_MMI_DATA_H__
+
+
+#include <tizen.h>
+#include <stdlib.h>
+
+
+/**
+* @file mmi-data.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef enum {
+ MMI_DATA_TYPE_BOOLEAN,
+ MMI_DATA_TYPE_INTEGER,
+ MMI_DATA_TYPE_FLOAT,
+ MMI_DATA_TYPE_TEXT,
+ MMI_DATA_TYPE_JSON,
+ MMI_DATA_TYPE_USER_IDENTIFICATION,
+ MMI_DATA_TYPE_AUDIO,
+ MMI_DATA_TYPE_VIDEO,
+ MMI_DATA_TYPE_BOUNDING_BOX,
+ MMI_DATA_TYPE_ARRAY,
+ MMI_DATA_TYPE_STRUCT,
+ MMI_DATA_TYPE_ANY,
+} mmi_data_type_e;
+
+/* Data Format */
+/*
+- MMI_DATA_BOOLEAN
+ data : pointer to a byte
+ datalen : 1 byte
+ description : false if all bits are 0, true otherwise
+
+- MMI_DATA_INTEGER
+ data : pointer to a signed integer type
+ datalen : 4 byte
+ 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
+ description : cast 'data' to a 32-bit floating-point type (e.g. float)
+
+- MMI_DATA_TEXT
+ data : pointer to a null-terminated string
+ datalen : length of the text
+ description : cast 'data' to a char*
+
+- MMI_DATA_JSON
+ data : pointer to a null-terminated string
+ datalen : length of the json string
+ description : cast 'data' to a char*
+
+- MMI_DATA_USER_IDENTIFICATION
+ data : pointer to a platform-dependent id for a user
+ datalen : platform-dependent
+ description : this value can be used to acquire platform-dependent user information
+
+- MMI_DATA_AUDIO
+ data : pointer to bytes
+ datalen : size of 'data' in bytes
+ format:
+ {
+ "bitrate" : 48000,
+ "format" : {
+ "signed" : true,
+ "bits" : 16
+ },
+ "channels" : 1
+ }
+ description : audio frame data
+
+- MMI_DATA_VIDEO
+ data : pointer to bytes
+ datalen : size of 'data' in bytes
+ format:
+ {
+ "width":1920,
+ "height":1080,
+ "encoding":"mp4"
+ }
+ description : video frame data
+
+- 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
+ }
+
+- MMI_DATA_ARRAY
+ data : pointer to an array of mmi_data_h struct
+ datalen : size of a pointer * number of items
+ description : A container that can hold multiple mmi_data_h with the same type.
+
+- MMI_DATA_STRUCT
+ data : pointer to an array of mmi_data_h struct
+ datalen : size of a pointer * number of items * 2 (one for key, one for value)
+ description : A container that can hold multiple mmi_data_h with different types.
+ A key is a MMI_DATA_TEXT that identifies the value.
+- MMI_DATA_ANY
+ data : pointer to an mmi_data_h struct
+ datalen : size of a pointer
+ description : Represents a data type that can be any of the above types.
+*/
+
+
+
+
+typedef struct mmi_data_timestamp_s *mmi_data_timestamp_h;
+
+typedef struct mmi_data_s *mmi_data_h;
+
+int mmi_data_create_bool(bool value, mmi_data_h *data);
+
+int mmi_data_create_int(int value, mmi_data_h *data);
+
+int mmi_data_create_float(float value, mmi_data_h *data);
+
+int mmi_data_create_text(const char *value, mmi_data_h *data);
+
+int mmi_data_create_audio(const void *ptr, size_t len, mmi_data_h *data);
+
+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_array(mmi_data_h *array_handle);
+
+int mmi_data_add_array_element(mmi_data_h array_handle, mmi_data_h element);
+
+int mmi_data_create_struct(mmi_data_h *struct_handle);
+
+int mmi_data_set_struct_element(mmi_data_h struct_handle, const char *name, mmi_data_h element);
+
+int mmi_data_get_type(mmi_data_h data, mmi_data_type_e *type);
+
+int mmi_data_get_bool(mmi_data_h data, bool *value);
+
+int mmi_data_get_int(mmi_data_h data, int *value);
+
+int mmi_data_get_float(mmi_data_h data, float *value);
+
+int mmi_data_get_text(mmi_data_h data, const char **string);
+
+int mmi_data_get_audio(mmi_data_h data, const void **ptr, size_t *len);
+
+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_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);
+
+int mmi_data_get_struct_element(mmi_data_h struct_handle, const char *name, mmi_data_h *element);
+
+int mmi_data_get_struct_count(mmi_data_h struct_handle, size_t *count);
+
+int mmi_data_get_struct_element_name(mmi_data_h struct_handle, size_t index, const char **string);
+
+int mmi_data_get_struct_element_value(mmi_data_h struct_handle, size_t index, mmi_data_h *element);
+
+int mmi_data_get_node_timestamp(mmi_data_h data, mmi_data_timestamp_h *timestamp);
+
+int mmi_data_get_source_timestamp(mmi_data_h data, mmi_data_timestamp_h *timestamp);
+
+int mmi_data_set_source_timestamp(mmi_data_h data, mmi_data_timestamp_h timestamp);
+
+int mmi_data_to_bytes(mmi_data_h data, unsigned char **bytes, size_t *length);
+
+int mmi_data_from_bytes(unsigned char *bytes, size_t length, mmi_data_h *data);
+
+int mmi_data_destroy(mmi_data_h data);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_DATA_H__ */
/*
- * Copyright (c) 2022 Samsung Electronics Co., Ltd All Rights Reserved
+ * 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.
*
*/
-#ifndef __MMI_IPC_H__
-#define __MMI_IPC_H__
-#include "mmi_proxy.h"
-#include "mmi.h"
+#ifndef __TIZEN_UIX_MMI_DEFINES_H__
+#define __TIZEN_UIX_MMI_DEFINES_H__
+
+
+/**
+* @file mmi-defines.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
#ifdef __cplusplus
extern "C" {
#endif
-int mmi_ipc_initialize(void);
-void mmi_ipc_deinitialize(void);
-int mmi_ipc_register_input_event_result_cb(int input_event_type, rpc_port_proxy_mmi_result_cb_cb callback);
-int mmi_ipc_activate_input_event(int input_event_type);
-int mmi_ipc_deactivate_input_event(int input_event_type);
-rpc_port_proxy_mmi_h mmi_ipc_get_rpc_h(void);
-int mmi_ipc_get_uid(void);
-bool mmi_ipc_is_connected(void);
-const char *mmi_ipc_get_stub_appid(void);
+#define MMI_NAME_MAX_LENGTH 32
+#define MMI_PARAMETER_MAX_COUNT 32
+#define MMI_PORT_MAX_COUNT 32
+#define MMI_NODE_MAX_COUNT 128
+#define MMI_LINK_MAX_COUNT 128
+#define MMI_OUTPUT_MAX_COUNT 32
+#define MMI_WORKFLOW_MAX_COUNT 64
+
#ifdef __cplusplus
}
#endif
-#endif //__MMI_IPC_H__
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_DEFINES_H__ */
--- /dev/null
+/*
+ * 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_ERROR_H__
+#define __TIZEN_UIX_MMI_ERROR_H__
+
+
+#include <tizen.h>
+
+
+/**
+* @file mmi-error.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
+
+#ifdef __cplusplus
+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_e;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_ERROR_H__ */
--- /dev/null
+/*
+ * 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_CONTROLLER_H__
+#define __TIZEN_UIX_MMI_NODE_CONTROLLER_H__
+
+
+
+#include <mmi-node.h>
+
+/**
+* @file mmi-node-controller.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+enum mmi_standard_node_controller_type_e {
+ MMI_STANDARD_NODE_CONTROLLER_TYPE_NONE,
+
+ /* - Description : Turns the node with a name specified in the attribute "TARGET" on or off
+ - Attributes :
+ "TARGET" : string
+ - Input Port 1
+ Name : "VALUE"
+ Data Type : MMI_DATA_TYPE_BOOLEAN
+ */
+ MMI_STANDARD_NODE_CONTROLLER_TYPE_SWITCH,
+};
+
+int mmi_standard_node_create_controller(mmi_standard_node_controller_type_e type, mmi_node_h *node);
+
+int mmi_standard_node_get_controller_type(mmi_node_h node, mmi_standard_node_controller_type_e *type);
+
+int mmi_standard_node_register_controller(mmi_standard_node_controller_type_e type, mmi_node_callbacks *callbacks, mmi_node_h node);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_NODE_LOGIC_H__ */
--- /dev/null
+/*
+ * 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_LOGIC_H__
+#define __TIZEN_UIX_MMI_NODE_LOGIC_H__
+
+
+
+#include <mmi-node.h>
+
+/**
+* @file mmi-node-logic.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+enum mmi_standard_node_logic_type_e {
+ MMI_STANDARD_NODE_LOGIC_TYPE_NONE,
+
+ /*
+ - Description : Compares the text received from the input port 1 ("TEXT") with
+ 1) the fixed strings specified in the attribute "CANDIDATES"
+ 2) the array of texts received from input port 2 ("TEXT_ARRAY")
+ 3) the array of structs received from input port 3 ("STRUCT_ARRAY"),
+ for the element specified in the attribute "COMPARAND_STRUCT_ELEMENT"
+ ex) if the struct has two elements named "label" and "text", and
+ "COMPARAND_STRUCT_ELEMENT" is "label", then the value of
+ "label" will be compared with the text received from input port 1
+ And outputs the mmi_data_t to the corresponding OUT port when matched.
+ ex1) if the text received from input port 1 is "Hello", and the fixed strings
+ specified in the attribute "CANDIDATES" is ["Hello", "World"], then the
+ text "Hello" will be sent to output port 1.
+ ex2) if the text received from input port 1 is "Hello", and the array of texts
+ received from input port 2 is ["Hello", "World", "Goodbye"], then the
+ text "Hello" will be sent to output port 2.
+ ex3) if the text received from input port 1 is "Hello", with the attribute
+ "COMPARAND_STRUCT_ELEMENT" set to "label", and the array of structs
+ received from input port 3 is like below,
+ [
+ {"label":"Hello"},
+ {"label":"World"},
+ {"label":"Goodbye"}
+ ]
+ then the struct {"label":"Hello"} will be sent to output port 3.
+ - Attributes :
+ "CANDIDATES" : array [ string ]
+ "COMPARAND_STRUCT_ELEMENT" : string
+ - Input Port 1
+ Name : "TEXT"
+ Data Type : MMI_DATA_TYPE_TEXT
+ - Input Port 2
+ Name : "TEXT_ARRAY"
+ Data Type : MMI_DATA_TYPE_ARRAY [ MMI_DATA_TYPE_TEXT ]
+ - Input Port 3
+ Name : "STRUCT_ARRAY"
+ Data Type : MMI_DATA_TYPE_ARRAY [ MMI_DATA_TYPE_STRUCT ]
+ - Output Port 1
+ Name : "MATCHED_CANDIDATE"
+ Data Type : MMI_DATA_TYPE_TEXT
+ - Output Port 2
+ Name : "MATCHED_TEXT_ARRAY"
+ Data Type : MMI_DATA_TYPE_TEXT
+ - Output Port 3
+ Name : "MATCHED_STRUCT_ARRAY"
+ Data Type : MMI_DATA_TYPE_STRUCT
+ */
+ MMI_STANDARD_NODE_LOGIC_TYPE_FIXED_STRING_MATCH,
+
+ /*
+ - Description : Tests if the regex strings specified in the attribute "REGEX" with
+ 1) the text received from the input port 1 ("TEXT") matches
+ 2) the array of texts received from input port 2 ("TEXT_ARRAY")
+ 3) the array of structs received from input port 3 ("STRUCT_ARRAY"),
+ for the element specified in the attribute "COMPARAND_STRUCT_ELEMENT"
+ - Attributes :
+ "REGEX" : array [ string ]
+ "COMPARAND_STRUCT_ELEMENT" : string
+ - Input Port 1
+ Name : "TEXT"
+ Data Type : MMI_DATA_TYPE_TEXT
+ - Input Port 2
+ Name : "TEXT_ARRAY"
+ Data Type : MMI_DATA_TYPE_ARRAY [ MMI_DATA_TYPE_TEXT ]
+ - Input Port 3
+ Name : "STRUCT_ARRAY"
+ Data Type : MMI_DATA_TYPE_ARRAY [ MMI_DATA_TYPE_STRUCT ]
+ - Output Port 1
+ Name : "MATCHED_TEXT"
+ Data Type : MMI_DATA_TYPE_TEXT
+ - Output Port 2
+ Name : "MATCHED_TEXT_ARRAY"
+ Data Type : MMI_DATA_TYPE_TEXT
+ - Output Port 3
+ Name : "MATCHED_STRUCT_ARRAY"
+ Data Type : MMI_DATA_TYPE_STRUCT
+ */
+ MMI_STANDARD_NODE_LOGIC_TYPE_REGEX_STRING_MATCH,
+
+
+ /*
+ - Description : Compares the User Recognition Struct from each input ports
+ and selects the one with the highest score.
+ - Input Port 1
+ Name : "Port1"
+ Data Type : MMI_DATA_TYPE_ARRAY of MMI_DATA_TYPE_STRUCT
+ Format of MMI_DATA_TYPE_STRUCT :
+ - "USER" : MMI_DATA_TYPE_USER_IDENTIFICATION
+ - "SCORE" : MMI_DATA_TYPE_FLOAT
+ - Input Port 2
+ Name : "Port2"
+ Data Type : MMI_DATA_TYPE_ARRAY of MMI_DATA_TYPE_STRUCT
+ Format of MMI_DATA_TYPE_STRUCT :
+ - "USER" : MMI_DATA_TYPE_USER_IDENTIFICATION
+ - "SCORE" : MMI_DATA_TYPE_FLOAT
+ - Output Port 1
+ Name : "BYPASS_RESULT"
+ Data Type : MMI_DATA_TYPE_USER_IDENTIFICATION
+ - Output Port 2
+ Name : "COMPARISON_RESULT"
+ Data Type : MMI_DATA_TYPE_USER_IDENTIFICATION
+ */
+ MMI_STANDARD_NODE_LOGIC_TYPE_USER_COMPARISON,
+};
+
+int mmi_standard_node_create_logic(mmi_standard_node_logic_type_e type, mmi_node_h *node);
+
+int mmi_standard_node_get_logic_type(mmi_node_h node, mmi_standard_node_logic_type_e *type);
+
+int mmi_standard_node_register_logic(mmi_standard_node_logic_type_e type, mmi_node_callbacks *callbacks, mmi_node_h node);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_NODE_LOGIC_H__ */
--- /dev/null
+/*
+ * 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_PROCESSOR_H__
+#define __TIZEN_UIX_MMI_NODE_PROCESSOR_H__
+
+
+
+#include <mmi-node.h>
+
+/**
+* @file mmi-node-processor.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+enum mmi_standard_node_processor_type_e {
+ MMI_STANDARD_NODE_PROCESSOR_TYPE_NONE,
+
+ /*
+ - Attributes : None
+ - Input Port 1
+ Name : "AUDIO"
+ Data Type : MMI_DATA_TYPE_AUDIO
+ - Output Port 1
+ Name : "PARTIAL"
+ Data Type : MMI_DATA_TYPE_TEXT
+ - Output Port 2
+ Name : "FINAL"
+ Data Type : MMI_DATA_TYPE_TEXT
+ */
+ MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR,
+
+ /*
+ - Attributes : None
+ - Input Port 1
+ Name : "VIDEO"
+ Data Type : MMI_DATA_TYPE_VIDEO
+ - Output Port 1
+ Name : "MATCHED_FACES"
+ Data Type : MMI_DATA_TYPE_ARRAY of MMI_DATA_TYPE_STRUCT
+ Format of MMI_DATA_TYPE_STRUCT :
+ - "USER" : MMI_DATA_TYPE_USER_IDENTIFICATION
+ - "SCORE" : MMI_DATA_TYPE_FLOAT
+ */
+ MMI_STANDARD_NODE_PROCESSOR_TYPE_FACE_RECOGNITION,
+
+ /*
+ - Attributes : None
+ - Input Port 1
+ Name : "AUDIO"
+ Data Type : MMI_DATA_TYPE_AUDIO
+ - Output Port 1
+ Name : "MATCHED_SPEAKERS"
+ Data Type : MMI_DATA_TYPE_ARRAY of MMI_DATA_TYPE_STRUCT
+ Format of MMI_DATA_TYPE_STRUCT :
+ - "USER" : MMI_DATA_TYPE_USER_IDENTIFICATION
+ - "SCORE" : MMI_DATA_TYPE_FLOAT
+ */
+ MMI_STANDARD_NODE_PROCESSOR_TYPE_SPEAKER_RECOGNITION,
+
+ /*
+ - Attributes :
+ "GRID_CONFIGURATION" : array [ integer ]
+ - Input Port 1
+ Name : "SCREEN_INFO"
+ Data Type : MMI_DATA_TYPE_ARRAY of MMI_DATA_TYPE_STRUCT
+ MMI_DATA_TYPE STRUCT format: {
+ "coord_x": MMI_DATA_TYPE_INT,
+ "coord_y": MMI_DATA_TYPE_INT,
+ "width": MMI_DATA_TYPE_INT,
+ "height": MMI_DATA_TYPE_INT,
+ "object_id": MMI_DATA_TYPE_TEXT,
+ "label": MMI_DATA_TYPE_TEXT,
+ "role": MMI_DATA_TYPE_TEXT,
+ }
+ - Input Port 2
+ Name : "MODE_COMMANDS"
+ Data Type : MMI_DATA_TYPE_TEXT
+ - Input Port 3
+ Name : "UTTERANCE"
+ Data Type : MMI_DATA_TYPE_TEXT
+ - Output Port 1
+ Name : "CANDIDATES"
+ Data Type : MMI_DATA_TYPE_ARRAY of MMI_DATA_TYPE_STRUCT
+ MMI_DATA_TYPE STRUCT format: {
+ "mode": MMI_DATA_TYPE_INT,
+ "coord_x": MMI_DATA_TYPE_INT,
+ "coord_y": MMI_DATA_TYPE_INT,
+ "width": MMI_DATA_TYPE_INT,
+ "height": MMI_DATA_TYPE_INT,
+ "label": MMI_DATA_TYPE_TEXT,
+ }
+ - Output Port 2
+ Name : "MATCHED_RESULT"
+ Data Type : MMI_DATA_TYPE_STRUCT
+ MMI_DATA_TYPE STRUCT format: {
+ "candidate_info": MMI_DATA_TYPE_STRUCT {
+ "mode": MMI_DATA_TYPE_INT,
+ "coord_x": MMI_DATA_TYPE_INT,
+ "coord_y": MMI_DATA_TYPE_INT,
+ "width": MMI_DATA_TYPE_INT,
+ "height": MMI_DATA_TYPE_INT,
+ "label": MMI_DATA_TYPE_TEXT,
+ },
+ "click_info": MMI_DATA_TYPE_STRUCT {
+ "x": MMI_DATA_TYPE_INT,
+ "y": MMI_DATA_TYPE_INT,
+ "object_id": MMI_DATA_TYPE_TEXT,
+ }
+ }
+ - Output Port 3
+ Name : "REJECTED"
+ Data Type : MMI_DATA_TYPE_TEXT
+ */
+ MMI_STANDARD_NODE_PROCESSOR_TYPE_VOICE_TOUCH,
+};
+
+int mmi_standard_node_create_processor(mmi_standard_node_processor_type_e type, mmi_node_h *node);
+
+int mmi_standard_node_get_processor_type(mmi_node_h node, mmi_standard_node_processor_type_e *type);
+
+int mmi_standard_node_register_processor(mmi_standard_node_processor_type_e type, mmi_node_callbacks *callbacks, mmi_node_h node);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_NODE_PROCESSOR_H__ */
--- /dev/null
+/*
+ * 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_SOURCE_H__
+#define __TIZEN_UIX_MMI_NODE_SOURCE_H__
+
+
+
+#include <mmi-node.h>
+
+/**
+* @file mmi-node-source.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum mmi_standard_node_source_type_e {
+ MMI_STANDARD_NODE_SOURCE_TYPE_NONE,
+
+ /*
+ - Description : A microphone that captures sound all the time.
+ - Attributes :
+ - "UNFOCUSED_ONLY" : bool
+ Default : false
+ Description : If true, the node will be activated only when there is
+ no other application currently acquired sound focus.
+ - Output Port 1
+ Name : "AUDIO"
+ Type : OUT
+ Data Type : MMI_DATA_TYPE_AUDIO
+ */
+ MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT,
+
+ /*
+ - Description : A camera that captures video.
+ - Output Port 1
+ Name : "VIDEO"
+ Type : OUT
+ Data Type : MMI_DATA_TYPE_VIDEO
+ */
+ MMI_STANDARD_NODE_SOURCE_TYPE_CAMERA,
+
+ /*
+ - Description : A screen analyzer that gets screen info when rescanning occur.
+ // FIXME: temporary attribute for replacing signal
+ - Attributes :
+ - "RESCANNING" : bool
+ Default : false
+ Description : If true, the node will rescan the screen and make screen info
+ - Output Port 1
+ Name : "SCREEN_INFO"
+ Type : OUT
+ Data Type : MMI_DATA_TYPE_ARRAY of MMI_DATA_TYPE_STRUCT
+ MMI_DATA_TYPE STRUCT format: {
+ "coord_x": MMI_DATA_TYPE_INT,
+ "coord_y": MMI_DATA_TYPE_INT,
+ "width": MMI_DATA_TYPE_INT,
+ "height": MMI_DATA_TYPE_INT,
+ "object_id": MMI_DATA_TYPE_TEXT,
+ "label": MMI_DATA_TYPE_TEXT,
+ "role": MMI_DATA_TYPE_TEXT,
+ }
+ */
+ MMI_STANDARD_NODE_SOURCE_TYPE_SCREEN_ANALYZER,
+};
+
+int mmi_standard_node_create_source(mmi_standard_node_source_type_e type, mmi_node_h *node);
+
+int mmi_standard_node_get_source_type(mmi_node_h node, mmi_standard_node_source_type_e *type);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_NODE_SOURCE_H__ */
--- /dev/null
+/*
+ * 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_H__
+#define __TIZEN_UIX_MMI_NODE_H__
+
+
+#include <tizen.h>
+
+#include <mmi-attribute.h>
+#include <mmi-data.h>
+#include <mmi-error.h>
+#include <mmi-port.h>
+#include <mmi-signal.h>
+
+/**
+* @file mmi-node.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum mmi_standard_node_type_e {
+ MMI_STANDARD_NODE_TYPE_NONE,
+ MMI_STANDARD_NODE_TYPE_SOURCE,
+ MMI_STANDARD_NODE_TYPE_PROCESSOR,
+ MMI_STANDARD_NODE_TYPE_LOGIC,
+ MMI_STANDARD_NODE_TYPE_CONTROLLER,
+};
+
+typedef void* mmi_node_instance_h;
+
+typedef int (*mmi_node_initialized_cb)(mmi_node_instance_h instance);
+typedef int (*mmi_node_deinitialized_cb)(mmi_node_instance_h instance);
+typedef int (*mmi_node_attribute_set_cb)(mmi_node_instance_h instance, mmi_attribute_h attribute);
+typedef int (*mmi_node_activated_cb)(mmi_node_instance_h instance);
+typedef int (*mmi_node_deactivated_cb)(mmi_node_instance_h instance);
+typedef int (*mmi_node_signal_received_cb)(mmi_node_instance_h instance, mmi_signal_h signal);
+
+typedef struct {
+ mmi_node_initialized_cb initialized_cb;
+ mmi_node_deinitialized_cb deinitialized_cb;
+ mmi_node_attribute_set_cb attribute_set_cb;
+ mmi_node_activated_cb activated_cb;
+ mmi_node_deactivated_cb deactivated_cb;
+ mmi_node_signal_received_cb signal_received_cb;
+} mmi_node_callbacks;
+
+typedef struct {
+ mmi_standard_node_type_e type;
+ int sub_type;
+ mmi_port_h *ports;
+ size_t port_count;
+ mmi_node_callbacks callbacks;
+} mmi_node_s;
+
+typedef mmi_node_s* mmi_node_h;
+
+/* Adds a static port to a static node. The port has to be already created before calling this function. */
+int mmi_node_add_port(mmi_node_h node, mmi_port_h port);
+
+/* Finds a port in a node matching the given name and type. */
+int mmi_node_find_port(mmi_node_h node, mmi_port_type_e port_type, const char *port_name, mmi_port_h *port);
+
+/* Retrieves the type of a node. */
+int mmi_node_get_type(mmi_node_h node, mmi_standard_node_type_e *type);
+
+/* Retrieves the number of ports in a node. */
+int mmi_node_get_port_count(mmi_node_h node, size_t *port_count);
+
+/* Retrieves the port at the given index. */
+int mmi_node_get_port(mmi_node_h node, size_t index, mmi_port_h *port);
+
+/* Get the callbacks of a node */
+int mmi_node_get_callbacks(mmi_node_h node, mmi_node_callbacks *callbacks);
+
+/* Set the callbacks of a node */
+int mmi_node_set_callbacks(mmi_node_h node, mmi_node_callbacks callbacks);
+
+/* Registers a node. */
+int mmi_node_register(mmi_node_h node);
+
+/* Clones a node. */
+int mmi_node_clone(mmi_node_h node, mmi_node_h *cloned);
+
+/* Destroys a node. */
+int mmi_node_destroy(mmi_node_h node);
+
+/* Provide a attribute to a node instance. */
+int mmi_node_instance_set_attribute(mmi_node_instance_h instance, mmi_attribute_h attribute);
+
+/* Provide a attribute bundle to a node instance. */
+//int mmi_node_instance_attribute_bundle_set(mmi_node_instance_h instance, mmi_attribute_bundle_h bundle);
+
+/* Retrieve a port instance of a node instance. */
+int mmi_node_instance_find_port(mmi_node_instance_h instance, mmi_port_type_e port_type, const char *port_name, mmi_port_instance_h *port);
+
+/* Retrieve a sibiling port instance of a port instance in a node, that matches the given name. */
+int mmi_node_instance_find_sibling_port(mmi_port_instance_h instance, const char *sibling_name, mmi_port_instance_h *sibling);
+
+/* Emits a signal from a node instance. */
+int mmi_node_instance_emit_signal(mmi_node_instance_h instance, mmi_signal_h signal);
+
+/* If the correct result could not be returned on last activate_cb() call, it needs to be updated afterwards using this function. */
+int mmi_node_instance_update_pending_activation_result(mmi_error_e result);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_NODE_H__ */
--- /dev/null
+/*
+ * 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_PLUGIN_MODULE_H__
+#define __TIZEN_UIX_MMI_PLUGIN_MODULE_H__
+
+
+#include <mmi.h>
+
+/**
+* @file mmi-plugin-module.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* If a plugin module wants to provide Nodes to mmi framework,
+ * it should implement a function named "mmi_plugin_module_get_node_list",
+ * with the following prototype. */
+#define MMI_PLUGIN_MODULE_GET_NODE_LIST_FUNC_NAME "mmi_plugin_module_get_node_list"
+typedef void (*mmi_plugin_module_get_node_list_func)();
+
+/* If a plugin module wants to provide Workflows to mmi framework,
+ * it should implement a function named "mmi_plugin_module_get_workflow_list",
+ * with the following prototype. */
+#define MMI_PLUGIN_MODULE_GET_WORKFLOW_LIST_FUNC_NAME "mmi_plugin_module_get_workflow_list"
+typedef void (*mmi_plugin_module_get_workflow_list_func)();
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_PLUGIN_MODULE_H__ */
--- /dev/null
+/*
+ * 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_PLUGIN_STORAGE_H__
+#define __TIZEN_UIX_MMI_PLUGIN_STORAGE_H__
+
+
+#include <mmi.h>
+#include <mmi-defines.h>
+#include <mmi-node.h>
+#include <mmi-node-source.h>
+#include <mmi-node-processor.h>
+#include <mmi-node-logic.h>
+#include <mmi-node-controller.h>
+#include <mmi-workflow.h>
+
+/**
+* @file mmi-plugin-storage.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The functions and structs below are used by MMI framework */
+
+typedef struct {
+ mmi_node_h *nodes;
+ size_t node_count;
+} mmi_plugin_module_node_list_s;
+
+typedef struct {
+ mmi_workflow_h *workflows;
+ size_t workflow_count;
+} mmi_plugin_module_workflow_list_s;
+
+
+typedef struct {
+ char name[MMI_NAME_MAX_LENGTH];
+ mmi_port_instance_h port;
+} mmi_plugin_module_port_instance_info_s;
+
+typedef struct {
+ mmi_node_instance_h node;
+ mmi_plugin_module_port_instance_info_s port_infos[MMI_PORT_MAX_COUNT];
+ size_t port_info_count;
+} mmi_plugin_module_node_instance_info_s;
+
+typedef void (*mmi_plugin_module_port_instance_output_handler_func)(
+ mmi_port_instance_h port, mmi_data_h data, void *user_data);
+
+typedef void (*mmi_plugin_module_switch_node_event_handler_func)(
+ mmi_node_instance_h node, const char *controllee, bool state, void *user_data);
+
+typedef struct {
+ mmi_plugin_module_port_instance_output_handler_func port_instance_output_handler;
+ mmi_plugin_module_switch_node_event_handler_func switch_node_event_handler;
+} mmi_plugin_module_event_handler_info_s;
+
+/* MMI Manager will invoke this function to set the current identifier of the plugin module. */
+void mmi_plugin_storage_set_current_module_identifier(const char *identifier);
+
+/* Each plugin modules will call this functino to get the current identifier of the plugin module. */
+const char* mmi_plugin_storage_get_current_module_identifier();
+
+/* Each plugin modules will call these functions to register their nodes and workflows. */
+void mmi_plugin_storage_set_node_list(mmi_plugin_module_node_list_s node_list);
+void mmi_plugin_storage_set_workflow_list(mmi_plugin_module_workflow_list_s workflow_list);
+
+/* MMI Manager will invoke these functions to get the node list of the plugin module. */
+mmi_plugin_module_node_list_s mmi_plugin_storage_get_node_list(const char *identifier);
+mmi_plugin_module_workflow_list_s mmi_plugin_storage_get_workflow_list(const char *identifier);
+
+/* MMI Manager will invoke these function to notify the node instance addition and removal. */
+void mmi_plugin_storage_add_node_instance_info(mmi_plugin_module_node_instance_info_s *info);
+void mmi_plugin_storage_remove_node_instance_info(mmi_node_instance_h node_instance);
+
+/* Each plugin modules will call this function to find appropriate port instance */
+mmi_port_instance_h mmi_plugin_storage_find_port_instance(
+ mmi_node_instance_h node_instance, const char *port_name);
+mmi_node_instance_h mmi_plugin_storage_find_node_instance_by_port_instance(mmi_port_instance_h port_instance);
+
+/* MMI Manager will invoke these function to register / unregister the event handlers */
+void mmi_plugin_storage_set_plugin_module_event_handler(
+ mmi_plugin_module_event_handler_info_s handler_info, void *user_data);
+void mmi_plugin_storage_unset_plugin_module_event_handler();
+
+/* Each plugin modules will call this function to notify the plugin module events */
+mmi_plugin_module_event_handler_info_s mmi_plugin_storage_get_plugin_module_event_handler();
+void* mmi_plugin_storage_get_plugin_module_event_handler_user_data();
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_PLUGIN_STORAGE_H__ */
--- /dev/null
+/*
+ * 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_PORT_H__
+#define __TIZEN_UIX_MMI_PORT_H__
+
+
+#include <tizen.h>
+
+#include <mmi-data.h>
+#include <mmi-defines.h>
+#include <mmi-error.h>
+
+/**
+* @file mmi-port.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum mmi_port_type_e {
+ MMI_PORT_TYPE_IN,
+ MMI_PORT_TYPE_OUT
+};
+
+typedef void* mmi_port_instance_h;
+
+typedef int (*mmi_port_output_format_requested_cb)(mmi_port_instance_h instance, const char *format);
+typedef int (*mmi_port_input_data_received_cb)(mmi_port_instance_h instance, mmi_data_h data);
+
+typedef struct {
+ mmi_port_output_format_requested_cb output_format_requested_cb;
+ mmi_port_input_data_received_cb input_data_received_cb;
+} mmi_port_callbacks;
+
+typedef struct {
+ char name[MMI_NAME_MAX_LENGTH];
+ mmi_port_type_e type;
+ mmi_data_type_e data_type;
+ mmi_port_callbacks callbacks;
+} mmi_port_s;
+
+typedef mmi_port_s* mmi_port_h;
+
+/* Create a port */
+int mmi_port_create(mmi_port_h *port);
+
+/* Get the name of a port */
+int mmi_port_get_name(mmi_port_h port, char **name, size_t *length);
+
+/* Get the type of a port */
+int mmi_port_get_type(mmi_port_h port, mmi_port_type_e *type);
+
+/* Get the data type of a port */
+int mmi_port_get_data_type(mmi_port_h port, mmi_data_type_e *data_type);
+
+/* Get the callbacks of a port */
+int mmi_port_get_callbacks(mmi_port_h port, mmi_port_callbacks *callbacks);
+
+/* Set the name of a port */
+int mmi_port_set_name(mmi_port_h port, const char *name);
+
+/* Set the type of a port */
+int mmi_port_set_type(mmi_port_h port, mmi_port_type_e type);
+
+/* Set the data type of a port */
+int mmi_port_set_data_type(mmi_port_h port, mmi_data_type_e data_type);
+
+/* Set the callbacks of a port */
+int mmi_port_set_callbacks(mmi_port_h port, mmi_port_callbacks callbacks);
+
+/* Clones a port */
+int mmi_port_clone(mmi_port_h port, mmi_port_h *cloned);
+
+/* Destroy a port */
+int mmi_port_destroy(mmi_port_h port);
+
+/* Provide a link information between two static ports. */
+// int mmi_port_link(mmi_port_h out, mmi_port_h in);
+
+/* Registers a port with the given type, data type, and callbacks. */
+// int mmi_port_register(mmi_port_type_e port_type, mmi_data_type_e data_type, mmi_port_callbacks *callbacks, mmi_port_h port);
+
+/* Generates data to the port with the given port instance. */
+int mmi_port_instance_generate_output(mmi_port_instance_h instance, mmi_data_h data);
+
+/* Requests the port instance to transform the data to the given format. */
+int mmi_port_instance_request_auto_transform(mmi_port_instance_h instance, const char *from_format, const char *to_format);
+
+/* Requests the port instance to retrieve the data with the given format. */
+int mmi_port_instance_request_input_data_format(mmi_port_instance_h instance, const char *format);
+
+/* Announce the data format to the port instance. */
+int mmi_port_instance_announce_output_data_format(mmi_port_instance_h instance, const char *format);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_PORT_H__ */
--- /dev/null
+/*
+ * 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_PRIMITIVE_VALUE_H__
+#define __TIZEN_UIX_MMI_PRIMITIVE_VALUE_H__
+
+
+#include <tizen.h>
+#include <stdlib.h>
+
+
+/**
+* @file mmi-primitive-value.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef enum {
+ MMI_PRIMITIVE_VALUE_TYPE_INT,
+ MMI_PRIMITIVE_VALUE_TYPE_FLOAT,
+ MMI_PRIMITIVE_VALUE_TYPE_STRING,
+ MMI_PRIMITIVE_VALUE_TYPE_BOOL,
+ MMI_PRIMITIVE_VALUE_TYPE_ARRAY,
+} mmi_primitive_value_type_e;
+
+
+typedef struct mmi_primitive_value_s* mmi_primitive_value_h;
+
+
+int mmi_primitive_value_create_int(int data, mmi_primitive_value_h *handle);
+
+int mmi_primitive_value_create_float(float data, mmi_primitive_value_h *handle);
+
+int mmi_primitive_value_create_string(const char *data, mmi_primitive_value_h *handle);
+
+int mmi_primitive_value_create_bool(bool data, mmi_primitive_value_h *handle);
+
+int mmi_primitive_value_create_array(mmi_primitive_value_h *handle);
+
+int mmi_primitive_value_add_array_element(mmi_primitive_value_h array, mmi_primitive_value_h element);
+
+int mmi_primitive_value_get_type(mmi_primitive_value_h handle, mmi_primitive_value_type_e *type);
+
+int mmi_primitive_value_get_int(mmi_primitive_value_h handle, int *value);
+
+int mmi_primitive_value_get_float(mmi_primitive_value_h handle, float *value);
+
+int mmi_primitive_value_get_string(mmi_primitive_value_h handle, const char **string);
+
+int mmi_primitive_value_get_bool(mmi_primitive_value_h handle, bool *value);
+
+int mmi_primitive_value_get_array_count(mmi_primitive_value_h array, size_t *count);
+
+int mmi_primitive_value_get_array_element(mmi_primitive_value_h array, size_t index, mmi_primitive_value_h *element);
+
+int mmi_primitive_value_clone(mmi_primitive_value_h handle, mmi_primitive_value_h *cloned);
+
+int mmi_primitive_value_destroy(mmi_primitive_value_h handle);
+
+int mmi_primitive_value_to_bytes(mmi_primitive_value_h handle, unsigned char **bytes, size_t *size);
+
+int mmi_primitive_value_from_bytes(unsigned char *bytes, size_t size, mmi_primitive_value_h *handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_PRIMITIVE_VALUE_H__ */
--- /dev/null
+/*
+ * 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_SIGNAL_H__
+#define __TIZEN_UIX_MMI_SIGNAL_H__
+
+
+#include <tizen.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <mmi-defines.h>
+#include <mmi-primitive-value.h>
+
+/**
+* @file mmi-port.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct {
+ char name[MMI_NAME_MAX_LENGTH];
+ mmi_primitive_value_h value;
+} mmi_signal_parameter_s;
+
+typedef mmi_signal_parameter_s* mmi_signal_parameter_h;
+
+typedef struct {
+ char name[MMI_NAME_MAX_LENGTH];
+ mmi_signal_parameter_h parameters[MMI_PARAMETER_MAX_COUNT];
+ int parameter_count;
+} mmi_signal_s;
+
+typedef mmi_signal_s* mmi_signal_h;
+
+int mmi_signal_parameter_create(mmi_primitive_value_h value, const char *name, mmi_signal_parameter_h *parameter);
+
+int mmi_signal_parameter_get_name(mmi_signal_parameter_h parameter, char **name);
+
+int mmi_signal_parameter_get_value(mmi_signal_parameter_h parameter, mmi_primitive_value_h *value);
+
+int mmi_signal_parameter_clone(mmi_signal_parameter_h parameter, mmi_signal_parameter_h *cloned);
+
+int mmi_signal_parameter_destroy(mmi_signal_parameter_h parameter);
+
+int mmi_signal_create(const char *name, mmi_signal_h *handle);
+
+int mmi_signal_add_parameter(mmi_signal_h handle, mmi_signal_parameter_h parameter);
+
+int mmi_signal_get_name(mmi_signal_h handle, char **name);
+
+int mmi_signal_get_parameter_count(mmi_signal_h handle, int *count);
+
+int mmi_signal_get_parameter(mmi_signal_h handle, int index, mmi_signal_parameter_h *parameter);
+
+int mmi_signal_destroy(mmi_signal_h handle);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_SIGNAL_H__ */
--- /dev/null
+/*
+ * 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_WORKFLOW_H__
+#define __TIZEN_UIX_MMI_WORKFLOW_H__
+
+
+#include <tizen.h>
+
+#include <mmi-attribute.h>
+#include <mmi-data.h>
+#include <mmi-node.h>
+
+
+/**
+* @file mmi-workflow.h
+*/
+
+
+/**
+* @addtogroup CAPI_UIX_MMI_MODULE
+* @{
+*/
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ MMI_STANDARD_WORKFLOW_NONE,
+ MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND,
+ MMI_STANDARD_WORKFLOW_VOICE_TOUCH,
+ MMI_STANDARD_WORKFLOW_USER_RECOGNITION,
+} mmi_standard_workflow_type_e;
+
+
+/* Functions to define a workflow prototype. Mostly used by workflow developers. */
+
+typedef struct {
+ char name[MMI_NAME_MAX_LENGTH];
+ mmi_node_h node;
+} mmi_workflow_node_info_s;
+
+typedef struct {
+ char from_node_name[MMI_NAME_MAX_LENGTH];
+ char from_port_name[MMI_NAME_MAX_LENGTH];
+ char to_node_name[MMI_NAME_MAX_LENGTH];
+ char to_port_name[MMI_NAME_MAX_LENGTH];
+} mmi_workflow_link_info_s;
+
+typedef struct {
+ char attribute_name[MMI_NAME_MAX_LENGTH];
+ char target_node_name[MMI_NAME_MAX_LENGTH];
+ char target_attribute_name[MMI_NAME_MAX_LENGTH];
+} mmi_workflow_attribute_assignment_info_s;
+
+typedef struct {
+ size_t serialized_default_value_size;
+ unsigned char *serialized_default_value;
+} mmi_workflow_attribute_default_value_info_s;
+
+typedef struct {
+ char output_name[MMI_NAME_MAX_LENGTH];
+ char from_node_name[MMI_NAME_MAX_LENGTH];
+ char from_port_name[MMI_NAME_MAX_LENGTH];
+} mmi_workflow_output_assignment_info_s;
+
+typedef struct {
+ mmi_standard_workflow_type_e type;
+ mmi_workflow_node_info_s *node_infos;
+ size_t node_info_count;
+ mmi_workflow_link_info_s *link_infos;
+ size_t link_info_count;
+ mmi_workflow_attribute_assignment_info_s *attribute_assignment_infos;
+ 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_output_assignment_info_s *output_assignment_infos;
+ size_t output_assignment_info_count;
+} mmi_workflow_s;
+
+typedef mmi_workflow_s* mmi_workflow_h;
+
+/* Create a workflow prototype */
+int mmi_workflow_create(mmi_workflow_h *workflow);
+
+/* Set the type of a workflow prototype */
+int mmi_workflow_set_type(mmi_workflow_h workflow, mmi_standard_workflow_type_e type);
+
+/* Get the type of a workflow prototype */
+int mmi_workflow_get_type(mmi_workflow_h workflow, mmi_standard_workflow_type_e *type);
+
+/* Add a node to a workflow prototype */
+int mmi_workflow_node_add(mmi_workflow_h workflow, const char *node_name, mmi_node_h node);
+
+/* A convinience function to link two nodes by automatically finding the appropriate ports in the nodes. */
+/* The linking succeeds only if there is exactly one pair of compatible input and output ports in the nodes. */
+/* int mmi_workflow_link_nodes(mmi_node_h from_node, mmi_node_h to_node); */
+
+/* Link two nodes with specifying the port names. */
+/* FIXME: It would be better to use handles instead of names. */
+int mmi_workflow_link_nodes_by_names(mmi_workflow_h workflow, const char *from_node_name, const char *from_port_name, const char *to_node_name, const char *to_port_name);
+
+/* Assign an attribute of a workflow to an attribute of a specific node in a workflow prototype */
+/* FIXME: It would be better to use handles instead of names. */
+int mmi_workflow_attribute_assign(mmi_workflow_h workflow, const char *attribute_name, const char *target_node_name, const char *target_attribute_name);
+
+/* Set the default value of an attribute of a workflow */
+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);
+
+/* 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. */
+int mmi_workflow_output_assign(mmi_workflow_h workflow, const char *workflow_output, const char *out_node_name, const char *node_out_port_name);
+
+/* Assign an output of a workflow to a OUT port of a specific node in a workflow prototype, with a port handle */
+int mmi_workflow_output_assign_by_port(mmi_workflow_h workflow, const char *workflow_output, mmi_port_h port);
+
+/* Register a standard workflow prototype to the workflow manager */
+int mmi_standard_workflow_register(mmi_workflow_h workflow);
+
+/* Clones a workflow. */
+int mmi_workflow_clone(mmi_workflow_h workflow, mmi_workflow_h *cloned);
+
+/* Create a workflow prototype from a script file */
+int mmi_workflow_create_from_script(const char *script_path, mmi_workflow_h *workflow);
+
+/* Destroy a workflow prototype */
+int mmi_workflow_destroy(mmi_workflow_h workflow);
+
+/* Functions to create a workflow instance. Mostly used by application developers. */
+
+typedef void* mmi_workflow_instance_h;
+
+/* Callback function for workflow output */
+typedef void (*mmi_workflow_output_cb)(mmi_workflow_instance_h instance, const char *name, mmi_data_h data, void *user_data);
+
+/* Callback function for workflow signal */
+// typedef void (*mmi_workflow_signal_cb)(const char *name, mmi_signal_parameter_h parameter, void *user_data);
+
+/* Instantiate a workflow from a workflow prototype */
+int mmi_standard_workflow_instance_create(mmi_standard_workflow_type_e type, mmi_workflow_instance_h *instance);
+
+/* Destroy a workflow instance */
+int mmi_workflow_instance_destroy(mmi_workflow_instance_h instance);
+
+/* Start a workflow instance */
+int mmi_workflow_instance_activate(mmi_workflow_instance_h instance);
+
+/* Stop a workflow instance */
+int mmi_workflow_instance_deactivate(mmi_workflow_instance_h instance);
+
+/* Set an attribute of a workflow 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);
+
+/* 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);
+
+/* Set a callback function to receive workflow signal */
+// int mmi_workflow_instance_set_signal_callback(mmi_workflow_instance_h instance, const char *name, mmi_workflow_signal_cb callback, void *user_data);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/**
+ * @}
+ */
+
+
+#endif /* __TIZEN_UIX_MMI_WORKFLOW_H__ */
--- /dev/null
+/*
+ * 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.
+ *
+ */
+
+#ifndef __MMI_H__
+#define __MMI_H__
+
+#include <tizen.h>
+#define MMI_API __attribute__ ((visibility("default")))
+
+#include <mmi-defines.h>
+#include <mmi-error.h>
+#include <mmi-data.h>
+#include <mmi-primitive-value.h>
+#include <mmi-attribute.h>
+#include <mmi-workflow.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+typedef enum {
+ MMI_STATE_NONE = 0,
+ MMI_STATE_READY,
+} mmi_state_e;
+
+typedef int (*mmi_state_changed_cb)(mmi_state_e state, void *user_data);
+
+/** @brief Initialize MMI framework
+ *
+ * @return 0 on success, otherwise a negative error value
+ */
+int mmi_initialize();
+
+/** @brief Deinitialize MMI framework
+ *
+ * @return 0 on success, otherwise a negative error value
+ */
+int mmi_deinitialize();
+
+/** @brief Set callback for state change
+ *
+ * @param[in] callback The callback function to be called when state is changed
+ * @param[in] user_data The user data to be passed to the callback function
+ *
+ * @return 0 on success, otherwise a negative error value
+ * @see mmi_state_changed_cb
+ */
+int mmi_set_state_changed_cb(mmi_state_changed_cb callback, void *user_data);
+
+/** @brief Unset callback for state change
+ *
+ * @param[in] callback The callback function to be unset
+ *
+ * @return 0 on success, otherwise a negative error value
+ */
+int mmi_unset_state_changed_cb(mmi_state_changed_cb callback);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+#endif //__MMI_H__
--- /dev/null
+Copyright (c) 2016, Adi Shavit
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of nor the names of its contributors may be used to
+ endorse or promote products derived from this software without specific
+ prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
--- /dev/null
+#pragma once\r
+\r
+#include <algorithm>\r
+#include <sstream>\r
+#include <limits>\r
+#include <string>\r
+#include <vector>\r
+#include <set>\r
+#include <map>\r
+#include <cassert>\r
+\r
+namespace argh\r
+{\r
+ // Terminology:\r
+ // A command line is composed of 2 types of args:\r
+ // 1. Positional args, i.e. free standing values\r
+ // 2. Options: args beginning with '-'. We identify two kinds:\r
+ // 2.1: Flags: boolean options => (exist ? true : false)\r
+ // 2.2: Parameters: a name followed by a non-option value\r
+\r
+#if !defined(__GNUC__) || (__GNUC__ >= 5)\r
+ using string_stream = std::istringstream;\r
+#else\r
+ // Until GCC 5, istringstream did not have a move constructor.\r
+ // stringstream_proxy is used instead, as a workaround.\r
+ class stringstream_proxy\r
+ {\r
+ public:\r
+ stringstream_proxy() = default;\r
+\r
+ // Construct with a value.\r
+ stringstream_proxy(std::string const& value) :\r
+ stream_(value)\r
+ {}\r
+\r
+ // Copy constructor.\r
+ stringstream_proxy(const stringstream_proxy& other) :\r
+ stream_(other.stream_.str())\r
+ {\r
+ stream_.setstate(other.stream_.rdstate());\r
+ }\r
+\r
+ void setstate(std::ios_base::iostate state) { stream_.setstate(state); }\r
+\r
+ // Stream out the value of the parameter.\r
+ // If the conversion was not possible, the stream will enter the fail state,\r
+ // and operator bool will return false.\r
+ template<typename T>\r
+ stringstream_proxy& operator >> (T& thing)\r
+ {\r
+ stream_ >> thing;\r
+ return *this;\r
+ }\r
+\r
+\r
+ // Get the string value.\r
+ std::string str() const { return stream_.str(); }\r
+\r
+ std::stringbuf* rdbuf() const { return stream_.rdbuf(); }\r
+\r
+ // Check the state of the stream.\r
+ // False when the most recent stream operation failed\r
+ explicit operator bool() const { return !!stream_; }\r
+\r
+ ~stringstream_proxy() = default;\r
+ private:\r
+ std::istringstream stream_;\r
+ };\r
+ using string_stream = stringstream_proxy;\r
+#endif\r
+\r
+ class parser\r
+ {\r
+ public:\r
+ enum Mode { PREFER_FLAG_FOR_UNREG_OPTION = 1 << 0,\r
+ PREFER_PARAM_FOR_UNREG_OPTION = 1 << 1,\r
+ NO_SPLIT_ON_EQUALSIGN = 1 << 2,\r
+ SINGLE_DASH_IS_MULTIFLAG = 1 << 3,\r
+ };\r
+\r
+ parser() = default;\r
+\r
+ parser(std::initializer_list<char const* const> pre_reg_names)\r
+ { add_params(pre_reg_names); }\r
+\r
+ parser(const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION)\r
+ { parse(argv, mode); }\r
+\r
+ parser(int argc, const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION)\r
+ { parse(argc, argv, mode); }\r
+\r
+ void add_param(std::string const& name);\r
+ void add_params(std::initializer_list<char const* const> init_list);\r
+\r
+ void parse(const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION);\r
+ void parse(int argc, const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION);\r
+\r
+ std::multiset<std::string> const& flags() const { return flags_; }\r
+ std::map<std::string, std::string> const& params() const { return params_; }\r
+ std::vector<std::string> const& pos_args() const { return pos_args_; }\r
+\r
+ // begin() and end() for using range-for over positional args.\r
+ std::vector<std::string>::const_iterator begin() const { return pos_args_.cbegin(); }\r
+ std::vector<std::string>::const_iterator end() const { return pos_args_.cend(); }\r
+ size_t size() const { return pos_args_.size(); }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+ // Accessors\r
+\r
+ // flag (boolean) accessors: return true if the flag appeared, otherwise false.\r
+ bool operator[](std::string const& name) const;\r
+\r
+ // multiple flag (boolean) accessors: return true if at least one of the flag appeared, otherwise false.\r
+ bool operator[](std::initializer_list<char const* const> init_list) const;\r
+\r
+ // returns positional arg string by order. Like argv[] but without the options\r
+ std::string const& operator[](size_t ind) const;\r
+\r
+ // returns a std::istream that can be used to convert a positional arg to a typed value.\r
+ string_stream operator()(size_t ind) const;\r
+\r
+ // same as above, but with a default value in case the arg is missing (index out of range).\r
+ template<typename T>\r
+ string_stream operator()(size_t ind, T&& def_val) const;\r
+\r
+ // parameter accessors, give a name get an std::istream that can be used to convert to a typed value.\r
+ // call .str() on result to get as string\r
+ string_stream operator()(std::string const& name) const;\r
+\r
+ // accessor for a parameter with multiple names, give a list of names, get an std::istream that can be used to convert to a typed value.\r
+ // call .str() on result to get as string\r
+ // returns the first value in the list to be found.\r
+ string_stream operator()(std::initializer_list<char const* const> init_list) const;\r
+\r
+ // same as above, but with a default value in case the param was missing.\r
+ // Non-string def_val types must have an operator<<() (output stream operator)\r
+ // If T only has an input stream operator, pass the string version of the type as in "3" instead of 3.\r
+ template<typename T>\r
+ string_stream operator()(std::string const& name, T&& def_val) const;\r
+\r
+ // same as above but for a list of names. returns the first value to be found.\r
+ template<typename T>\r
+ string_stream operator()(std::initializer_list<char const* const> init_list, T&& def_val) const;\r
+\r
+ private:\r
+ string_stream bad_stream() const;\r
+ std::string trim_leading_dashes(std::string const& name) const;\r
+ bool is_number(std::string const& arg) const;\r
+ bool is_option(std::string const& arg) const;\r
+ bool got_flag(std::string const& name) const;\r
+ bool is_param(std::string const& name) const;\r
+\r
+ private:\r
+ std::vector<std::string> args_;\r
+ std::map<std::string, std::string> params_;\r
+ std::vector<std::string> pos_args_;\r
+ std::multiset<std::string> flags_;\r
+ std::set<std::string> registeredParams_;\r
+ std::string empty_;\r
+ };\r
+\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline void parser::parse(const char * const argv[], int mode)\r
+ {\r
+ int argc = 0;\r
+ for (auto argvp = argv; *argvp; ++argc, ++argvp);\r
+ parse(argc, argv, mode);\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline void parser::parse(int argc, const char* const argv[], int mode /*= PREFER_FLAG_FOR_UNREG_OPTION*/)\r
+ {\r
+ // convert to strings\r
+ args_.resize(static_cast<decltype(args_)::size_type>(argc));
+ std::transform(argv, argv + argc, args_.begin(), [](const char* const arg) { return arg; });\r
+\r
+ // parse line\r
+ for (auto i = 0u; i < args_.size(); ++i)\r
+ {\r
+ if (!is_option(args_[i]))\r
+ {\r
+ pos_args_.emplace_back(args_[i]);\r
+ continue;\r
+ }\r
+\r
+ auto name = trim_leading_dashes(args_[i]);\r
+\r
+ if (!(mode & NO_SPLIT_ON_EQUALSIGN))\r
+ {\r
+ auto equalPos = name.find('=');\r
+ if (equalPos != std::string::npos)\r
+ {\r
+ params_.insert({ name.substr(0, equalPos), name.substr(equalPos + 1) });\r
+ continue;\r
+ }\r
+ }\r
+\r
+ // if the option is unregistered and should be a multi-flag\r
+ if (1 == (args_[i].size() - name.size()) && // single dash\r
+ argh::parser::SINGLE_DASH_IS_MULTIFLAG & mode && // multi-flag mode\r
+ !is_param(name)) // unregistered\r
+ {\r
+ std::string keep_param;\r
+\r
+ if (!name.empty() && is_param(std::string(1ul, name.back()))) // last char is param\r
+ {\r
+ keep_param += name.back();\r
+ name.resize(name.size() - 1);\r
+ }\r
+\r
+ for (auto const& c : name)\r
+ {\r
+ flags_.emplace(std::string{ c });\r
+ }\r
+\r
+ if (!keep_param.empty())\r
+ {\r
+ name = keep_param;\r
+ }\r
+ else\r
+ {\r
+ continue; // do not consider other options for this arg\r
+ }\r
+ }\r
+\r
+ // any potential option will get as its value the next arg, unless that arg is an option too\r
+ // in that case it will be determined a flag.\r
+ if (i == args_.size() - 1 || is_option(args_[i + 1]))\r
+ {\r
+ flags_.emplace(name);\r
+ continue;\r
+ }\r
+\r
+ // if 'name' is a pre-registered option, then the next arg cannot be a free parameter to it is skipped\r
+ // otherwise we have 2 modes:\r
+ // PREFER_FLAG_FOR_UNREG_OPTION: a non-registered 'name' is determined a flag.\r
+ // The following value (the next arg) will be a free parameter.\r
+ //\r
+ // PREFER_PARAM_FOR_UNREG_OPTION: a non-registered 'name' is determined a parameter, the next arg\r
+ // will be the value of that option.\r
+\r
+ assert(!(mode & argh::parser::PREFER_FLAG_FOR_UNREG_OPTION)\r
+ || !(mode & argh::parser::PREFER_PARAM_FOR_UNREG_OPTION));\r
+\r
+ bool preferParam = mode & argh::parser::PREFER_PARAM_FOR_UNREG_OPTION;\r
+\r
+ if (is_param(name) || preferParam)\r
+ {\r
+ params_.insert({ name, args_[i + 1] });\r
+ ++i; // skip next value, it is not a free parameter\r
+ continue;\r
+ }\r
+ else\r
+ {\r
+ flags_.emplace(name);\r
+ }\r
+ };\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline string_stream parser::bad_stream() const\r
+ {\r
+ string_stream bad;\r
+ bad.setstate(std::ios_base::failbit);\r
+ return bad;\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline bool parser::is_number(std::string const& arg) const\r
+ {\r
+ // inefficient but simple way to determine if a string is a number (which can start with a '-')\r
+ std::istringstream istr(arg);\r
+ double number;\r
+ istr >> number;\r
+ return !(istr.fail() || istr.bad());\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline bool parser::is_option(std::string const& arg) const\r
+ {\r
+ assert(0 != arg.size());\r
+ if (is_number(arg))\r
+ return false;\r
+ return '-' == arg[0];\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline std::string parser::trim_leading_dashes(std::string const& name) const\r
+ {\r
+ auto pos = name.find_first_not_of('-');\r
+ return std::string::npos != pos ? name.substr(pos) : name;\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline bool argh::parser::got_flag(std::string const& name) const\r
+ {\r
+ return flags_.end() != flags_.find(trim_leading_dashes(name));\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline bool argh::parser::is_param(std::string const& name) const\r
+ {\r
+ return registeredParams_.count(name);\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline bool parser::operator[](std::string const& name) const\r
+ {\r
+ return got_flag(name);\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline bool parser::operator[](std::initializer_list<char const* const> init_list) const\r
+ {\r
+ return std::any_of(init_list.begin(), init_list.end(), [&](char const* const name) { return got_flag(name); });\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline std::string const& parser::operator[](size_t ind) const\r
+ {\r
+ if (ind < pos_args_.size())\r
+ return pos_args_[ind];\r
+ return empty_;\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline string_stream parser::operator()(std::string const& name) const\r
+ {\r
+ auto optIt = params_.find(trim_leading_dashes(name));\r
+ if (params_.end() != optIt)\r
+ return string_stream(optIt->second);\r
+ return bad_stream();\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline string_stream parser::operator()(std::initializer_list<char const* const> init_list) const\r
+ {\r
+ for (auto& name : init_list)\r
+ {\r
+ auto optIt = params_.find(trim_leading_dashes(name));\r
+ if (params_.end() != optIt)\r
+ return string_stream(optIt->second);\r
+ }\r
+ return bad_stream();\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ template<typename T>\r
+ string_stream parser::operator()(std::string const& name, T&& def_val) const\r
+ {\r
+ auto optIt = params_.find(trim_leading_dashes(name));\r
+ if (params_.end() != optIt)\r
+ return string_stream(optIt->second);\r
+\r
+ std::ostringstream ostr;\r
+ ostr.precision(std::numeric_limits<long double>::max_digits10);\r
+ ostr << def_val;\r
+ return string_stream(ostr.str()); // use default\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ // same as above but for a list of names. returns the first value to be found.\r
+ template<typename T>\r
+ string_stream parser::operator()(std::initializer_list<char const* const> init_list, T&& def_val) const\r
+ {\r
+ for (auto& name : init_list)\r
+ {\r
+ auto optIt = params_.find(trim_leading_dashes(name));\r
+ if (params_.end() != optIt)\r
+ return string_stream(optIt->second);\r
+ }\r
+ std::ostringstream ostr;\r
+ ostr.precision(std::numeric_limits<long double>::max_digits10);\r
+ ostr << def_val;\r
+ return string_stream(ostr.str()); // use default\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline string_stream parser::operator()(size_t ind) const\r
+ {\r
+ if (pos_args_.size() <= ind)\r
+ return bad_stream();\r
+\r
+ return string_stream(pos_args_[ind]);\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ template<typename T>\r
+ string_stream parser::operator()(size_t ind, T&& def_val) const\r
+ {\r
+ if (pos_args_.size() <= ind)\r
+ {\r
+ std::ostringstream ostr;\r
+ ostr.precision(std::numeric_limits<long double>::max_digits10);\r
+ ostr << def_val;\r
+ return string_stream(ostr.str());\r
+ }\r
+\r
+ return string_stream(pos_args_[ind]);\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline void parser::add_param(std::string const& name)\r
+ {\r
+ registeredParams_.insert(trim_leading_dashes(name));\r
+ }\r
+\r
+ //////////////////////////////////////////////////////////////////////////\r
+\r
+ inline void parser::add_params(std::initializer_list<char const* const> init_list)\r
+ {\r
+ for (auto& name : init_list)\r
+ registeredParams_.insert(trim_leading_dashes(name));\r
+ }\r
+}\r
--- /dev/null
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
\ No newline at end of file
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_BOOSTASIOCLIASYNCSESSION_H_
+#define CLI_BOOSTASIOCLIASYNCSESSION_H_
+
+#include "detail/genericcliasyncsession.h"
+#include "detail/boostasiolib.h"
+
+
+namespace cli { using BoostAsioCliAsyncSession = detail::GenericCliAsyncSession<detail::BoostAsioLib>; }
+
+#endif // CLI_BOOSTASIOCLIASYNCSESSION_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_BOOSTASIOREMOTECLI_H_
+#define CLI_BOOSTASIOREMOTECLI_H_
+
+#include "detail/boostasiolib.h"
+#include "detail/genericasioremotecli.h"
+
+namespace cli { using BoostAsioCliTelnetServer = detail::CliGenericTelnetServer<detail::BoostAsioLib>; }
+
+#endif // CLI_BOOSTASIOREMOTECLI_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_BOOSTASIOSCHEDULER_H_
+#define CLI_BOOSTASIOSCHEDULER_H_
+
+#include "detail/genericasioscheduler.h"
+#include "detail/boostasiolib.h"
+
+namespace cli { using BoostAsioScheduler = detail::GenericAsioScheduler<detail::BoostAsioLib>; }
+
+#endif // CLI_BOOSTASIOSCHEDULER_H_
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_CLI_H
+#define CLI_CLI_H
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <functional>
+#include <algorithm>
+#include <cctype> // std::isspace
+#include <type_traits>
+#include "colorprofile.h"
+#include "detail/history.h"
+#include "detail/split.h"
+#include "detail/fromstring.h"
+#include "historystorage.h"
+#include "volatilehistorystorage.h"
+#include <iostream>
+#include <utility>
+
+namespace cli
+{
+
+ // ********************************************************************
+
+ template < typename T > struct TypeDesc { static const char* Name() { return ""; } };
+ template <> struct TypeDesc< char > { static const char* Name() { return "<char>"; } };
+ template <> struct TypeDesc< unsigned char > { static const char* Name() { return "<unsigned char>"; } };
+ template <> struct TypeDesc< signed char > { static const char* Name() { return "<signed char>"; } };
+ template <> struct TypeDesc< short > { static const char* Name() { return "<short>"; } };
+ template <> struct TypeDesc< unsigned short > { static const char* Name() { return "<unsigned short>"; } };
+ template <> struct TypeDesc< int > { static const char* Name() { return "<int>"; } };
+ template <> struct TypeDesc< unsigned int > { static const char* Name() { return "<unsigned int>"; } };
+ template <> struct TypeDesc< long > { static const char* Name() { return "<long>"; } };
+ template <> struct TypeDesc< unsigned long > { static const char* Name() { return "<unsigned long>"; } };
+ template <> struct TypeDesc< long long > { static const char* Name() { return "<long long>"; } };
+ template <> struct TypeDesc< unsigned long long > { static const char* Name() { return "<unsigned long long>"; } };
+ template <> struct TypeDesc< float > { static const char* Name() { return "<float>"; } };
+ template <> struct TypeDesc< double > { static const char* Name() { return "<double>"; } };
+ template <> struct TypeDesc< long double > { static const char* Name() { return "<long double>"; } };
+ template <> struct TypeDesc< bool > { static const char* Name() { return "<bool>"; } };
+ template <> struct TypeDesc< std::string > { static const char* Name() { return "<string>"; } };
+ template <> struct TypeDesc< std::vector<std::string> > { static const char* Name() { return "<list of strings>"; } };
+
+ // ********************************************************************
+
+ // this class provides a global output stream
+ class OutStream : public std::basic_ostream<char>, public std::streambuf
+ {
+ public:
+ OutStream() : std::basic_ostream<char>(this)
+ {
+ }
+
+ // std::streambuf overrides
+ std::streamsize xsputn(const char* s, std::streamsize n) override
+ {
+ for (auto os: ostreams)
+ os->rdbuf()->sputn(s, n);
+ return n;
+ }
+ int overflow(int c) override
+ {
+ for (auto os: ostreams)
+ *os << static_cast<char>(c);
+ return c;
+ }
+
+ void Register(std::ostream& o)
+ {
+ ostreams.push_back(&o);
+ }
+ void UnRegister(std::ostream& o)
+ {
+ ostreams.erase(std::remove(ostreams.begin(), ostreams.end(), &o), ostreams.end());
+ }
+
+ private:
+
+ std::vector<std::ostream*> ostreams;
+ };
+
+ // forward declarations
+ class Menu;
+ class CliSession;
+
+ class Cli
+ {
+
+ public:
+ ~Cli() = default;
+ // disable value semantics
+ Cli(const Cli&) = delete;
+ Cli& operator = (const Cli&) = delete;
+ // enable move semantics
+ Cli(Cli&&) = default;
+ Cli& operator = (Cli&&) = default;
+
+ /**
+ * @brief Construct a new Cli object having a given root menu that contains the first level commands available.
+ *
+ * @param _rootMenu is the @c Menu containing the first level commands available to the user.
+ * @param historyStorage is the policy for the storage of the cli commands history. You must pass an instance of
+ * a class derived from @c HistoryStorage. The library provides these policies:
+ * - @c VolatileHistoryStorage
+ * - @c FileHistoryStorage it's a persistent history. I.e., the command history is preserved after your application
+ * is restarted.
+ *
+ * However, you can develop your own, just derive a class from @c HistoryStorage .
+ */
+ Cli(std::unique_ptr<Menu> _rootMenu, std::unique_ptr<HistoryStorage> historyStorage = std::make_unique<VolatileHistoryStorage>()) :
+ globalHistoryStorage(std::move(historyStorage)),
+ rootMenu(std::move(_rootMenu)),
+ enterAction{},
+ exitAction{}
+ {
+ }
+
+ /**
+ * @brief Add a global enter action that is called every time a session (local or remote) is established.
+ *
+ * @param action the function to be called when a session exits, taking a @c std::ostream& parameter to write on that session console.
+ */
+ void EnterAction(const std::function< void(std::ostream&)>& action) { enterAction = action; }
+
+ /**
+ * @brief Add a global exit action that is called every time a session (local or remote) gets the "exit" command.
+ *
+ * @param action the function to be called when a session exits, taking a @c std::ostream& parameter to write on that session console.
+ */
+ void ExitAction(const std::function< void(std::ostream&)>& action) { exitAction = action; }
+
+ /**
+ * @brief Add an handler that will be called when a @c std::exception (or derived) is thrown inside a command handler.
+ * If an exception handler is not set, the exception will be logget on the session output stream.
+ *
+ * @param handler the function to be called when an exception is thrown, taking a @c std::ostream& parameter to write on that session console
+ * and the exception thrown.
+ */
+ void StdExceptionHandler(const std::function< void(std::ostream&, const std::string& cmd, const std::exception&) >& handler)
+ {
+ exceptionHandler = handler;
+ }
+
+ /**
+ * @brief Get a global out stream object that can be used to print on every session currently connected (local and remote)
+ *
+ * @return OutStream& the reference to the global out stream writing on every session console.
+ */
+ static OutStream& cout()
+ {
+ return *CoutPtr();
+ }
+
+ private:
+ friend class CliSession;
+
+ static std::shared_ptr<OutStream> CoutPtr()
+ {
+ static std::shared_ptr<OutStream> s = std::make_shared<OutStream>();
+ return s;
+ }
+
+ Menu* RootMenu() { return rootMenu.get(); }
+
+ void EnterAction(std::ostream& out)
+ {
+ if (enterAction)
+ enterAction(out);
+ }
+
+ void ExitAction(std::ostream& out)
+ {
+ if (exitAction)
+ exitAction(out);
+ }
+
+ void StdExceptionHandler(std::ostream& out, const std::string& cmd, const std::exception& e)
+ {
+ if (exceptionHandler)
+ exceptionHandler(out, cmd, e);
+ else
+ out << e.what() << '\n';
+ }
+
+ void StoreCommands(const std::vector<std::string>& cmds)
+ {
+ globalHistoryStorage->Store(cmds);
+ }
+
+ std::vector<std::string> GetCommands() const
+ {
+ return globalHistoryStorage->Commands();
+ }
+
+ private:
+ std::unique_ptr<HistoryStorage> globalHistoryStorage;
+ std::unique_ptr<Menu> rootMenu; // just to keep it alive
+ std::function<void(std::ostream&)> enterAction;
+ std::function<void(std::ostream&)> exitAction;
+ std::function<void(std::ostream&, const std::string& cmd, const std::exception& )> exceptionHandler;
+ };
+
+ // ********************************************************************
+
+ class Command
+ {
+ public:
+ explicit Command(std::string _name) : name(std::move(_name)), enabled(true) {}
+ virtual ~Command() noexcept = default;
+
+ // disable copy and move semantics
+ Command(const Command&) = delete;
+ Command(Command&&) = delete;
+ Command& operator=(const Command&) = delete;
+ Command& operator=(Command&&) = delete;
+
+ virtual void Enable() { enabled = true; }
+ virtual void Disable() { enabled = false; }
+ virtual bool Exec(const std::vector<std::string>& cmdLine, CliSession& session) = 0;
+ virtual void Help(std::ostream& out) const = 0;
+ // Returns the collection of completions relatives to this command.
+ // For simple commands, provides a base implementation that use the name of the command
+ // for aggregate commands (i.e., Menu), the function is redefined to give the menu command
+ // and the subcommand recursively
+ virtual std::vector<std::string> GetCompletionRecursive(const std::string& line) const
+ {
+ if (!enabled) return {};
+ if (name.rfind(line, 0) == 0) return {name}; // name starts_with line
+ return {};
+ }
+ protected:
+ const std::string& Name() const { return name; }
+ bool IsEnabled() const { return enabled; }
+ private:
+ const std::string name;
+ bool enabled;
+ };
+
+ // ********************************************************************
+
+ // free utility function to get completions from a list of commands and the current line
+ inline std::vector<std::string> GetCompletions(
+ const std::shared_ptr<std::vector<std::shared_ptr<Command>>>& cmds,
+ const std::string& currentLine)
+ {
+ std::vector<std::string> result;
+ std::for_each(cmds->begin(), cmds->end(),
+ [¤tLine,&result](const auto& cmd)
+ {
+ auto c = cmd->GetCompletionRecursive(currentLine);
+ result.insert(
+ result.end(),
+ std::make_move_iterator(c.begin()),
+ std::make_move_iterator(c.end())
+ );
+ }
+ );
+ return result;
+ }
+
+ // ********************************************************************
+
+ class CliSession
+ {
+ public:
+ CliSession(Cli& _cli, std::ostream& _out, std::size_t historySize = 100);
+ virtual ~CliSession() noexcept { coutPtr->UnRegister(out); }
+
+ // disable value semantics
+ CliSession(const CliSession&) = delete;
+ CliSession& operator = (const CliSession&) = delete;
+ // disable move semantics
+ CliSession(CliSession&&) = delete;
+ CliSession& operator = (CliSession&&) = delete;
+
+ void Feed(const std::string& cmd);
+
+ void Prompt();
+
+ void Current(Menu* menu) { current = menu; }
+
+ std::ostream& OutStream() { return out; }
+
+ void Help() const;
+
+ void Enter()
+ {
+ cli.EnterAction(out);
+
+ if (enterAction)
+ enterAction(out);
+ }
+
+ void Exit()
+ {
+ exitAction(out);
+ cli.ExitAction(out);
+
+ auto cmds = history.GetCommands();
+ cli.StoreCommands(cmds);
+
+ exit = true; // prevent the prompt to be shown
+ }
+
+ void EnterAction(const std::function<void(std::ostream&)>& action)
+ {
+ enterAction = action;
+ }
+
+ void ExitAction(const std::function<void(std::ostream&)>& action)
+ {
+ exitAction = action;
+ }
+
+ void ShowHistory() const { history.Show(out); }
+
+ std::string PreviousCmd(const std::string& line)
+ {
+ return history.Previous(line);
+ }
+
+ std::string NextCmd()
+ {
+ return history.Next();
+ }
+
+ std::vector<std::string> GetCompletions(std::string currentLine) const;
+
+ private:
+
+ Cli& cli;
+ std::shared_ptr<cli::OutStream> coutPtr;
+ Menu* current;
+ std::unique_ptr<Menu> globalScopeMenu;
+ std::ostream& out;
+ std::function< void(std::ostream&)> enterAction = []( std::ostream& ) noexcept {};
+ std::function< void(std::ostream&)> exitAction = []( std::ostream& ) noexcept {};
+ detail::History history;
+ bool exit{ false }; // to prevent the prompt after exit command
+ };
+
+ // ********************************************************************
+
+ class CmdHandler
+ {
+ public:
+ using CmdVec = std::vector<std::shared_ptr<Command>>;
+ CmdHandler() : descriptor(std::make_shared<Descriptor>()) {}
+ CmdHandler(std::weak_ptr<Command> c, std::weak_ptr<CmdVec> v) :
+ descriptor(std::make_shared<Descriptor>(c, v))
+ {}
+ void Enable() { if (descriptor) descriptor->Enable(); }
+ void Disable() { if (descriptor) descriptor->Disable(); }
+ void Remove() { if (descriptor) descriptor->Remove(); }
+ private:
+ struct Descriptor
+ {
+ Descriptor() = default;
+ Descriptor(std::weak_ptr<Command> c, std::weak_ptr<CmdVec> v) :
+ cmd(std::move(c)), cmds(std::move(v))
+ {}
+ void Enable()
+ {
+ if (auto c = cmd.lock())
+ c->Enable();
+ }
+ void Disable()
+ {
+ if(auto c = cmd.lock())
+ c->Disable();
+ }
+ void Remove()
+ {
+ auto scmd = cmd.lock();
+ auto scmds = cmds.lock();
+ if (scmd && scmds)
+ {
+ auto i = std::find_if(
+ scmds->begin(),
+ scmds->end(),
+ [&](const auto& c){ return c.get() == scmd.get(); }
+ );
+ if (i != scmds->end())
+ scmds->erase(i);
+ }
+ }
+ std::weak_ptr<Command> cmd;
+ std::weak_ptr<CmdVec> cmds;
+ };
+ std::shared_ptr<Descriptor> descriptor;
+ };
+
+ // ********************************************************************
+
+ class Menu : public Command
+ {
+ public:
+ // disable value and move semantics
+ Menu(const Menu&) = delete;
+ Menu& operator = (const Menu&) = delete;
+ Menu(Menu&&) = delete;
+ Menu& operator = (Menu&&) = delete;
+
+ Menu() : Command({}), parent(nullptr), description(), cmds(std::make_shared<Cmds>()) {}
+
+ explicit Menu(const std::string& _name, std::string desc = "(menu)", const std::string& _prompt="") :
+ Command(_name),
+ parent(nullptr),
+ description(std::move(desc)),
+ prompt(_prompt.empty() ? _name : _prompt),
+ cmds(std::make_shared<Cmds>())
+ {}
+
+ template <typename R, typename ... Args>
+ CmdHandler Insert(const std::string& cmdName, R (*f)(std::ostream&, Args...), const std::string& help, const std::vector<std::string>& parDesc={});
+
+ template <typename F>
+ CmdHandler Insert(const std::string& cmdName, F f, const std::string& help = "", const std::vector<std::string>& parDesc={})
+ {
+ // dispatch to private Insert methods
+ return Insert(cmdName, help, parDesc, f, &F::operator());
+ }
+
+ template <typename F>
+ CmdHandler Insert(const std::string& cmdName, const std::vector<std::string>& parDesc, F f, const std::string& help = "")
+ {
+ // dispatch to private Insert methods
+ return Insert(cmdName, help, parDesc, f, &F::operator());
+ }
+
+ CmdHandler Insert(std::unique_ptr<Command>&& cmd)
+ {
+ std::shared_ptr<Command> scmd(std::move(cmd));
+ CmdHandler c(scmd, cmds);
+ cmds->push_back(scmd);
+ return c;
+ }
+
+ CmdHandler Insert(std::unique_ptr<Menu>&& menu)
+ {
+ std::shared_ptr<Menu> smenu(std::move(menu));
+ CmdHandler c(smenu, cmds);
+ smenu->parent = this;
+ cmds->push_back(smenu);
+ return c;
+ }
+
+ bool Exec(const std::vector<std::string>& cmdLine, CliSession& session) override
+ {
+ if (!IsEnabled())
+ return false;
+ if (cmdLine[0] == Name())
+ {
+ if (cmdLine.size() == 1)
+ {
+ session.Current(this);
+ return true;
+ }
+ else
+ {
+ // check also for subcommands
+ std::vector<std::string > subCmdLine(cmdLine.begin()+1, cmdLine.end());
+ for (auto& cmd: *cmds)
+ if (cmd->Exec( subCmdLine, session )) return true;
+ }
+ }
+ return false;
+ }
+
+ bool ScanCmds(const std::vector<std::string>& cmdLine, CliSession& session)
+ {
+ if (!IsEnabled())
+ return false;
+ for (auto& cmd: *cmds)
+ if (cmd->Exec(cmdLine, session))
+ return true;
+ return (parent && parent->Exec(cmdLine, session));
+ }
+
+ std::string Prompt() const
+ {
+ return prompt;
+ }
+
+ void MainHelp(std::ostream& out)
+ {
+ if (!IsEnabled()) return;
+ for (const auto& cmd: *cmds)
+ cmd->Help(out);
+ if (parent != nullptr)
+ parent->Help(out);
+ }
+
+ void Help(std::ostream& out) const override
+ {
+ if (!IsEnabled()) return;
+ out << " - " << Name() << "\n\t" << description << "\n";
+ }
+
+ // returns:
+ // - the completions of this menu command
+ // - the recursive completions of subcommands
+ // - the recursive completions of parent menu
+ std::vector<std::string> GetCompletions(const std::string& currentLine) const
+ {
+ auto result = cli::GetCompletions(cmds, currentLine);
+ if (parent != nullptr)
+ {
+ auto c = parent->GetCompletionRecursive(currentLine);
+ result.insert(result.end(), std::make_move_iterator(c.begin()), std::make_move_iterator(c.end()));
+ }
+ return result;
+ }
+
+ // returns:
+ // - the completion of this menu command
+ // - the recursive completions of the subcommands
+ std::vector<std::string> GetCompletionRecursive(const std::string& line) const override
+ {
+ if (line.rfind(Name(), 0) == 0) // line starts_with Name()
+ {
+ auto rest = line;
+ rest.erase(0, Name().size());
+ // trim_left(rest);
+ rest.erase(rest.begin(), std::find_if(rest.begin(), rest.end(), [](int ch) { return !std::isspace(ch); }));
+ std::vector<std::string> result;
+ for (const auto& cmd: *cmds)
+ {
+ auto cs = cmd->GetCompletionRecursive(rest);
+ for (const auto& c: cs)
+ result.push_back(Name() + ' ' + c); // concat submenu with command
+ }
+ return result;
+ }
+ return Command::GetCompletionRecursive(line);
+ }
+
+ private:
+
+ template <typename F, typename R, typename ... Args>
+ CmdHandler Insert(const std::string& name, const std::string& help, const std::vector<std::string>& parDesc, F& f, R (F::*)(std::ostream& out, Args...) const);
+
+ template <typename F, typename R>
+ CmdHandler Insert(const std::string& name, const std::string& help, const std::vector<std::string>& parDesc, F& f, R (F::*)(std::ostream& out, const std::vector<std::string>&) const);
+
+ template <typename F, typename R>
+ CmdHandler Insert(const std::string& name, const std::string& help, const std::vector<std::string>& parDesc, F& f, R (F::*)(std::ostream& out, std::vector<std::string>) const);
+
+ Menu* parent{ nullptr };
+ const std::string description;
+ const std::string prompt;
+ // using shared_ptr instead of unique_ptr to get a weak_ptr
+ // for the CmdHandler::Descriptor
+ using Cmds = std::vector<std::shared_ptr<Command>>;
+ std::shared_ptr<Cmds> cmds;
+ };
+
+ // ********************************************************************
+
+ template <typename ... Args>
+ struct Select;
+
+ template <typename P, typename ... Args>
+ struct Select<P, Args...>
+ {
+ template <typename F, typename InputIt>
+ static void Exec(const F& f, InputIt first, InputIt last)
+ {
+ assert( first != last );
+ assert( std::distance(first, last) == 1+sizeof...(Args) );
+ const P p = detail::from_string<typename std::decay<P>::type>(*first);
+ auto g = [&](auto ... pars){ f(p, pars...); };
+ Select<Args...>::Exec(g, std::next(first), last);
+ }
+ };
+
+ template <>
+ struct Select<>
+ {
+ template <typename F, typename InputIt>
+ static void Exec(const F& f, InputIt first, InputIt last)
+ {
+ // silence the unused warning in release mode when assert is disabled
+ static_cast<void>(first);
+ static_cast<void>(last);
+
+ assert(first == last);
+
+ f();
+ }
+ };
+
+ template <typename ... Args>
+ struct PrintDesc;
+
+ template <typename P, typename ... Args>
+ struct PrintDesc<P, Args...>
+ {
+ static void Dump(std::ostream& out)
+ {
+ out << " " << TypeDesc< typename std::decay<P>::type >::Name();
+ PrintDesc<Args...>::Dump(out);
+ }
+ };
+
+ template <>
+ struct PrintDesc<>
+ {
+ static void Dump(std::ostream& /*out*/) {}
+ };
+
+ // *******************************************
+
+ template <typename F, typename ... Args>
+ class VariadicFunctionCommand : public Command
+ {
+ public:
+ // disable value semantics
+ VariadicFunctionCommand(const VariadicFunctionCommand&) = delete;
+ VariadicFunctionCommand& operator = (const VariadicFunctionCommand&) = delete;
+
+ VariadicFunctionCommand(
+ const std::string& _name,
+ F fun,
+ std::string desc,
+ std::vector<std::string> parDesc
+ )
+ : Command(_name), func(std::move(fun)), description(std::move(desc)), parameterDesc(std::move(parDesc))
+ {
+ }
+
+ bool Exec(const std::vector< std::string >& cmdLine, CliSession& session) override
+ {
+ if (!IsEnabled()) return false;
+ const std::size_t paramSize = sizeof...(Args);
+ if (cmdLine.size() != paramSize+1) return false;
+ if (Name() == cmdLine[0])
+ {
+ try
+ {
+ auto g = [&](auto ... pars){ func( session.OutStream(), pars... ); };
+ Select<Args...>::Exec(g, std::next(cmdLine.begin()), cmdLine.end());
+ }
+ catch (std::bad_cast&)
+ {
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+
+ void Help(std::ostream& out) const override
+ {
+ if (!IsEnabled()) return;
+ out << " - " << Name();
+ if (parameterDesc.empty())
+ PrintDesc<Args...>::Dump(out);
+ for (auto& s: parameterDesc)
+ out << " <" << s << '>';
+ out << "\n\t" << description << "\n";
+ }
+
+ private:
+
+ const F func;
+ const std::string description;
+ const std::vector<std::string> parameterDesc;
+ };
+
+
+ template <typename F>
+ class FreeformCommand : public Command
+ {
+ public:
+ // disable value semantics
+ FreeformCommand(const FreeformCommand&) = delete;
+ FreeformCommand& operator = (const FreeformCommand&) = delete;
+
+ FreeformCommand(
+ const std::string& _name,
+ F fun,
+ std::string desc,
+ std::vector<std::string> parDesc
+ )
+ : Command(_name), func(std::move(fun)), description(std::move(desc)), parameterDesc(std::move(parDesc))
+ {
+ }
+
+ bool Exec(const std::vector< std::string >& cmdLine, CliSession& session) override
+ {
+ if (!IsEnabled()) return false;
+ assert(!cmdLine.empty());
+ if (Name() == cmdLine[0])
+ {
+ func(session.OutStream(), std::vector<std::string>(std::next(cmdLine.begin()), cmdLine.end()));
+ return true;
+ }
+ return false;
+ }
+ void Help(std::ostream& out) const override
+ {
+ if (!IsEnabled()) return;
+ out << " - " << Name();
+ if (parameterDesc.empty())
+ PrintDesc<std::vector<std::string>>::Dump(out);
+ for (auto& s: parameterDesc)
+ out << " <" << s << '>';
+ out << "\n\t" << description << "\n";
+ }
+
+ private:
+
+ const F func;
+ const std::string description;
+ const std::vector<std::string> parameterDesc;
+ };
+
+
+ // ********************************************************************
+
+ // CliSession implementation
+
+ inline CliSession::CliSession(Cli& _cli, std::ostream& _out, std::size_t historySize) :
+ cli(_cli),
+ coutPtr(Cli::CoutPtr()),
+ current(cli.RootMenu()),
+ globalScopeMenu(std::make_unique< Menu >()),
+ out(_out),
+ history(historySize)
+ {
+ history.LoadCommands(cli.GetCommands());
+
+ coutPtr->Register(out);
+ globalScopeMenu->Insert(
+ "help",
+ [this](std::ostream&){ Help(); },
+ "This help message"
+ );
+ globalScopeMenu->Insert(
+ "exit",
+ [this](std::ostream&){ Exit(); },
+ "Quit the session"
+ );
+#ifdef CLI_HISTORY_CMD
+ globalScopeMenu->Insert(
+ "history",
+ [this](std::ostream&){ ShowHistory(); },
+ "Show the history"
+ );
+#endif
+ }
+
+ inline void CliSession::Feed(const std::string& cmd)
+ {
+ std::vector<std::string> strs;
+ detail::split(strs, cmd);
+ if (strs.empty()) return; // just hit enter
+
+ history.NewCommand(cmd); // add anyway to history
+
+ try
+ {
+
+ // global cmds check
+ bool found = globalScopeMenu->ScanCmds(strs, *this);
+
+ // root menu recursive cmds check
+ if (!found) found = current->ScanCmds(strs, *this);
+
+ if (!found) // error msg if not found
+ out << "wrong command: " << cmd << '\n';
+ }
+ catch(const std::exception& e)
+ {
+ cli.StdExceptionHandler(out, cmd, e);
+ }
+ catch(...)
+ {
+ out << "Cli. Unknown exception caught handling command line \""
+ << cmd
+ << "\"\n";
+ }
+ }
+
+ inline void CliSession::Prompt()
+ {
+ if (exit) return;
+ out << beforePrompt
+ << current->Prompt()
+ << afterPrompt
+ << "> "
+ << std::flush;
+ }
+
+ inline void CliSession::Help() const
+ {
+ out << "Commands available:\n";
+ globalScopeMenu->MainHelp(out);
+ current -> MainHelp( out );
+ }
+
+ inline std::vector<std::string> CliSession::GetCompletions(std::string currentLine) const
+ {
+ // trim_left(currentLine);
+ currentLine.erase(currentLine.begin(), std::find_if(currentLine.begin(), currentLine.end(), [](int ch) { return !std::isspace(ch); }));
+ auto v1 = globalScopeMenu->GetCompletions(currentLine);
+ auto v3 = current->GetCompletions(currentLine);
+ v1.insert(v1.end(), std::make_move_iterator(v3.begin()), std::make_move_iterator(v3.end()));
+
+ // removes duplicates (std::unique requires a sorted container)
+ std::sort(v1.begin(), v1.end());
+ auto ip = std::unique(v1.begin(), v1.end());
+ v1.resize(static_cast<std::size_t>(std::distance(v1.begin(), ip)));
+
+ return v1;
+ }
+
+ // Menu implementation
+
+ template <typename R, typename ... Args>
+ CmdHandler Menu::Insert(const std::string& cmdName, R (*f)(std::ostream&, Args...), const std::string& help, const std::vector<std::string>& parDesc)
+ {
+ using F = R (*)(std::ostream&, Args...);
+ return Insert(std::make_unique<VariadicFunctionCommand<F, Args ...>>(cmdName, f, help, parDesc));
+ }
+
+ template <typename F, typename R, typename ... Args>
+ CmdHandler Menu::Insert(const std::string& cmdName, const std::string& help, const std::vector<std::string>& parDesc, F& f, R (F::*)(std::ostream& out, Args...) const )
+ {
+ return Insert(std::make_unique<VariadicFunctionCommand<F, Args ...>>(cmdName, f, help, parDesc));
+ }
+
+ template <typename F, typename R>
+ CmdHandler Menu::Insert(const std::string& cmdName, const std::string& help, const std::vector<std::string>& parDesc, F& f, R (F::*)(std::ostream& out, const std::vector<std::string>& args) const )
+ {
+ return Insert(std::make_unique<FreeformCommand<F>>(cmdName, f, help, parDesc));
+ }
+
+ template <typename F, typename R>
+ CmdHandler Menu::Insert(const std::string& cmdName, const std::string& help, const std::vector<std::string>& parDesc, F& f, R (F::*)(std::ostream& out, std::vector<std::string> args) const )
+ {
+ return Insert(std::make_unique<FreeformCommand<F>>(cmdName, f, help, parDesc));
+ }
+
+} // namespace cli
+
+#endif // CLI_CLI_H
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_CLIFILESESSION_H
+#define CLI_CLIFILESESSION_H
+
+#include <string>
+#include <iostream>
+#include <stdexcept> // std::invalid_argument
+#include "cli.h" // CliSession
+
+namespace cli
+{
+
+class CliFileSession : public CliSession
+{
+public:
+ /// @throw std::invalid_argument if @c _in or @c out are invalid streams
+ explicit CliFileSession(Cli& _cli, std::istream& _in=std::cin, std::ostream& _out=std::cout) :
+ CliSession(_cli, _out, 1),
+ exit(false),
+ in(_in)
+ {
+ if (!_in.good()) throw std::invalid_argument("istream invalid");
+ if (!_out.good()) throw std::invalid_argument("ostream invalid");
+ ExitAction(
+ [this](std::ostream&) noexcept
+ {
+ exit = true;
+ }
+ );
+ }
+ void Start()
+ {
+ Enter();
+
+ while(!exit)
+ {
+ Prompt();
+ std::string line;
+ if (!in.good())
+ Exit();
+ std::getline(in, line);
+ if (in.eof())
+ Exit();
+ else
+ Feed(line);
+ }
+ }
+
+private:
+ bool exit;
+ std::istream& in;
+};
+
+} // namespace cli
+
+#endif // CLI_CLIFILESESSION_H
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_CLILOCALSESSION_H
+#define CLI_CLILOCALSESSION_H
+
+#include <ostream> // std::ostream
+#include "detail/inputhandler.h"
+#include "cli.h" // CliSession
+#include "detail/keyboard.h"
+
+namespace cli
+{
+
+class Scheduler; // forward declaration
+
+/**
+ * @brief CliLocalTerminalSession represents a local session.
+ * You should instantiate it to start an interactive prompt on the standard
+ * input/output of your application.
+ * The handlers of the commands will be invoked in the same thread the @c Scheduler runs.
+ */
+class CliLocalTerminalSession : public CliSession
+{
+public:
+
+ /**
+ * @brief Construct a new Cli Local Terminal Session object that uses the specified @c std::ostream
+ * for output. You can also specify a size for the command history.
+ *
+ * @param _cli The cli object that defines the menu hierarchy for this session
+ * @param scheduler The scheduler that will process the command handlers
+ * @param _out the output stream where command output will be printed
+ * @param historySize the size of the command history
+ */
+ CliLocalTerminalSession(Cli& _cli, Scheduler& scheduler, std::ostream& _out, std::size_t historySize = 100) :
+ CliSession(_cli, _out, historySize),
+ kb(scheduler),
+ ih(*this, kb)
+ {
+ Enter();
+ Prompt();
+ }
+
+private:
+ detail::Keyboard kb;
+ detail::InputHandler ih;
+};
+
+using CliLocalSession = CliLocalTerminalSession;
+
+} // namespace cli
+
+#endif // CLI_CLILOCALSESSION_H
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_COLORPROFILE_H_
+#define CLI_COLORPROFILE_H_
+
+#include "detail/rang.h"
+
+namespace cli
+{
+
+inline bool& Color() { static bool color; return color; }
+
+inline void SetColor() { Color() = true; }
+inline void SetNoColor() { Color() = false; }
+
+enum BeforePrompt { beforePrompt };
+enum AfterPrompt { afterPrompt };
+enum BeforeInput { beforeInput };
+enum AfterInput { afterInput };
+
+inline std::ostream& operator<<(std::ostream& os, BeforePrompt)
+{
+ if ( Color() ) { os << detail::rang::control::forceColor << detail::rang::fg::green << detail::rang::style::bold; }
+ return os;
+}
+
+inline std::ostream& operator<<(std::ostream& os, AfterPrompt)
+{
+ os << detail::rang::style::reset;
+ return os;
+}
+
+inline std::ostream& operator<<(std::ostream& os, BeforeInput)
+{
+ if ( Color() ) { os << detail::rang::control::forceColor << detail::rang::fgB::gray; }
+ return os;
+}
+
+inline std::ostream& operator<<(std::ostream& os, AfterInput)
+{
+ os << detail::rang::style::reset;
+ return os;
+}
+
+} // namespace cli
+
+#endif // CLI_COLORPROFILE_H_
+
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_BOOSTASIOLIB_H_
+#define CLI_DETAIL_BOOSTASIOLIB_H_
+
+/**
+ * This header file provides the class `cli::BoostAsioLib`, using the right
+ * implementation according to the version of boost libraries included.
+ */
+
+#include <boost/version.hpp>
+
+#if BOOST_VERSION < 106600
+ #include "oldboostasiolib.h"
+ namespace cli { namespace detail { using BoostAsioLib = OldBoostAsioLib; } }
+#else
+ #include "newboostasiolib.h"
+ namespace cli { namespace detail { using BoostAsioLib = NewBoostAsioLib; } }
+#endif
+
+#endif // CLI_DETAIL_BOOSTASIOLIB_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_COMMONPREFIX_H_
+#define CLI_DETAIL_COMMONPREFIX_H_
+
+#include <cassert>
+#include <string>
+#include <vector>
+#include <algorithm>
+
+namespace cli
+{
+namespace detail
+{
+
+inline std::string CommonPrefix(const std::vector<std::string>& v)
+{
+ assert(!v.empty());
+ std::string prefix;
+
+ // find the shorter string
+ auto smin = std::min_element(v.begin(), v.end(),
+ [] (const std::string& s1, const std::string& s2)
+ {
+ return s1.size() < s2.size();
+ });
+
+ for (std::size_t i = 0; i < smin->size(); ++i)
+ {
+ // check if i-th element is equal in each input string
+ const char c = (*smin)[i];
+ for (auto& x: v)
+ if (x[i] != c) return prefix;
+ prefix += c;
+ }
+
+ return prefix;
+}
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_COMMONPREFIX_H_
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_FROMSTRING_H_
+#define CLI_DETAIL_FROMSTRING_H_
+
+// #define CLI_FROMSTRING_USE_BOOST
+
+#ifdef CLI_FROMSTRING_USE_BOOST
+
+#include <boost/lexical_cast.hpp>
+
+namespace cli
+{
+namespace detail
+{
+
+template <typename T>
+inline
+T from_string(const std::string& s)
+{
+ return boost::lexical_cast<T>(s);
+}
+
+} // namespace detail
+} // namespace cli
+
+#else
+
+#include <exception>
+#include <limits>
+#include <string>
+#include <sstream>
+
+namespace cli
+{
+
+ namespace detail
+ {
+ class bad_conversion : public std::bad_cast
+ {
+ public:
+ const char* what() const noexcept override {
+ return "bad from_string conversion: "
+ "source string value could not be interpreted as target";
+ }
+ };
+
+template <typename T>
+inline T from_string(const std::string& s);
+
+template <>
+inline std::string from_string(const std::string& s)
+{
+ return s;
+}
+
+template <>
+inline std::nullptr_t from_string(const std::string& /*s*/)
+{
+ return nullptr;
+}
+
+namespace detail
+{
+
+template <typename T>
+inline T unsigned_digits_from_string(const std::string& s)
+{
+ if (s.empty())
+ throw bad_conversion();
+ T result = 0;
+ for (char c: s)
+ {
+ if (!std::isdigit(c))
+ throw bad_conversion();
+ const T digit = static_cast<T>( c - '0' );
+ const T tmp = (result * 10) + digit;
+ if (result != ((tmp-digit)/10) || (tmp < result))
+ throw bad_conversion();
+ result = tmp;
+ }
+ return result;
+}
+
+template <typename T>
+inline T unsigned_from_string(std::string s)
+{
+ if (s.empty())
+ throw bad_conversion();
+ if (s[0] == '+')
+ {
+ s = s.substr(1);
+ }
+ return unsigned_digits_from_string<T>(s);
+}
+
+template <typename T>
+inline T signed_from_string(std::string s)
+{
+ if (s.empty())
+ throw bad_conversion();
+ using U = std::make_unsigned_t<T>;
+ if (s[0] == '-')
+ {
+ s = s.substr(1);
+ const U val = unsigned_digits_from_string<U>(s);
+ if ( val > static_cast<U>( - std::numeric_limits<T>::min() ) )
+ throw bad_conversion();
+ return (- static_cast<T>(val));
+ }
+ else if (s[0] == '+')
+ {
+ s = s.substr(1);
+ }
+ const U val = unsigned_digits_from_string<U>(s);
+ if (val > static_cast<U>( std::numeric_limits<T>::max() ))
+ throw bad_conversion();
+ return static_cast<T>(val);
+}
+
+} // namespace detail
+
+// signed
+
+template <> inline signed char
+from_string(const std::string& s) { return detail::signed_from_string<signed char>(s); }
+
+template <> inline short int
+from_string(const std::string& s) { return detail::signed_from_string<short int>(s); }
+
+template <> inline int
+from_string(const std::string& s) { return detail::signed_from_string<int>(s); }
+
+template <> inline long int
+from_string(const std::string& s) { return detail::signed_from_string<long int>(s); }
+
+template <> inline long long int
+from_string(const std::string& s) { return detail::signed_from_string<long long int>(s); }
+
+// unsigned
+
+template <> inline unsigned char
+from_string(const std::string& s) { return detail::unsigned_from_string<unsigned char>(s); }
+
+template <> inline unsigned short int
+from_string(const std::string& s) { return detail::unsigned_from_string<unsigned short int>(s); }
+
+template <> inline unsigned int
+from_string(const std::string& s) { return detail::unsigned_from_string<unsigned int>(s); }
+
+template <> inline unsigned long int
+from_string(const std::string& s) { return detail::unsigned_from_string<unsigned long int>(s); }
+
+template <> inline unsigned long long int
+from_string(const std::string& s) { return detail::unsigned_from_string<unsigned long long int>(s); }
+
+// bool
+
+template <>
+inline bool from_string(const std::string& s)
+{
+ if (s == "true") return true;
+ else if (s == "false") return false;
+ const auto value = detail::signed_from_string<long long int>(s);
+ if (value == 1) return true;
+ else if (value == 0) return false;
+ throw bad_conversion();
+}
+
+// chars
+
+template <>
+inline char from_string(const std::string& s)
+{
+ if (s.size() != 1) throw bad_conversion();
+ return s[0];
+}
+
+// floating points
+
+template <>
+inline float from_string(const std::string& s)
+{
+ if ( std::any_of(s.begin(), s.end(), [](char c){return std::isspace(c);} ) )
+ throw bad_conversion();
+ std::string::size_type sz;
+ float result = {};
+ try {
+ result = std::stof(s, &sz);
+ } catch (const std::exception&) {
+ throw bad_conversion();
+ }
+ if (sz != s.size())
+ throw bad_conversion();
+ return result;
+}
+
+template <>
+inline double from_string(const std::string& s)
+{
+ if ( std::any_of(s.begin(), s.end(), [](char c){return std::isspace(c);} ) )
+ throw bad_conversion();
+ std::string::size_type sz;
+ double result = {};
+ try {
+ result = std::stod(s, &sz);
+ } catch (const std::exception&) {
+ throw bad_conversion();
+ }
+ if (sz != s.size())
+ throw bad_conversion();
+ return result;
+}
+
+template <>
+inline long double from_string(const std::string& s)
+{
+ if ( std::any_of(s.begin(), s.end(), [](char c){return std::isspace(c);} ) )
+ throw bad_conversion();
+ std::string::size_type sz;
+ long double result = {};
+ try {
+ result = std::stold(s, &sz);
+ } catch (const std::exception&) {
+ throw bad_conversion();
+ }
+ if (sz != s.size())
+ throw bad_conversion();
+ return result;
+}
+
+// fallback: operator <<
+
+template <typename T>
+inline T from_string(const std::string& s)
+{
+ std::stringstream interpreter;
+ T result;
+
+ if(!(interpreter << s) ||
+ !(interpreter >> result) ||
+ !(interpreter >> std::ws).eof())
+ throw bad_conversion();
+
+ return result;
+}
+
+ } // namespace detail
+
+} // namespace cli
+
+
+#endif // CLI_FROMSTRING_USE_BOOST
+
+#endif // CLI_DETAIL_FROMSTRING_H_
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_GENERICASIOREMOTECLI_H_
+#define CLI_DETAIL_GENERICASIOREMOTECLI_H_
+
+#include <memory>
+#include "../cli.h"
+#include "inputhandler.h"
+#include "server.h"
+#include "inputdevice.h"
+#include "genericasioscheduler.h"
+
+namespace cli
+{
+namespace detail
+{
+
+// *******************************************************************************
+
+class TelnetSession : public Session
+{
+public:
+ explicit TelnetSession(asiolib::ip::tcp::socket _socket) :
+ Session(std::move(_socket))
+ {}
+
+protected:
+
+ std::string Encode(const std::string& _data) const override
+ {
+ std::string result;
+ for (char c: _data)
+ {
+ if (c == '\n') result += '\r';
+ result += c;
+ }
+ return result;
+ }
+
+ void OnConnect() override
+ {
+ // to specify hexadecimal value as chars we use
+ // the syntax \xVVV
+ // and the std::string ctor that takes the size,
+ // so that it's not null-terminated
+ //std::string msg{ "\x0FF\x0FD\x027", 3 };
+ //waitAck = true;
+ //std::string iacDoSuppressGoAhead{ "\x0FF\x0FD\x003", 3 };
+ //this -> OutStream() << iacDoSuppressGoAhead << std::flush;
+
+ // https://www.ibm.com/support/knowledgecenter/SSLTBW_1.13.0/com.ibm.zos.r13.hald001/telcmds.htm
+
+ static const std::string iacDoLineMode{ "\x0FF\x0FD\x022", 3 };
+ this -> OutStream() << iacDoLineMode << std::flush;
+
+ static const std::string iacSbLineMode0IacSe{ "\x0FF\x0FA\x022\x001\x000\x0FF\x0F0", 7 };
+ this -> OutStream() << iacSbLineMode0IacSe << std::flush;
+
+ static const std::string iacWillEcho{ "\x0FF\x0FB\x001", 3 };
+ this -> OutStream() << iacWillEcho << std::flush;
+
+/*
+ constexpr char IAC = '\x0FF'; // 255
+ constexpr char DO = '\x0FD'; // 253
+ constexpr char VT100 = '\x030'; // 48
+
+ this -> OutStream() << IAC << DO << VT100 << std::flush;
+*/
+ //cliSession.Prompt();
+ }
+ void OnDisconnect() override {}
+ void OnError() override {}
+#if 0
+ void OnDataReceived(const std::string& data) override
+ {
+ if (waitAck)
+ {
+ if ( data[0] == '\x0FF' )
+ {
+ // TODO
+ for (size_t i = 0; i < data.size(); ++i)
+ std::cout << static_cast<int>( data[i] & 0xFF ) << ' ';
+ std::cout << std::endl;
+
+ for (size_t i = 0; i < data.size(); ++i)
+ std::cout << "0x" << std::hex << static_cast<int>( data[i] & 0xFF ) << std::dec << ' ';
+ std::cout << std::endl;
+
+ for (size_t i = 0; i < data.size(); ++i)
+ switch (static_cast<int>( data[i] & 0xFF ))
+ {
+ case 0xFF: std::cout << "IAC "; break;
+ case 0xFE: std::cout << "DONT "; break;
+ case 0xFD: std::cout << "DO "; break;
+ case 0xFC: std::cout << "WONT "; break;
+ case 0xFB: std::cout << "WILL "; break;
+ case 0xFA: std::cout << "SB "; break;
+ case 0xF9: std::cout << "GoAhead "; break;
+ case 0xF8: std::cout << "EraseLine "; break;
+ case 0xF7: std::cout << "EraseCharacter "; break;
+ case 0xF6: std::cout << "AreYouThere "; break;
+ case 0xF5: std::cout << "AbortOutput "; break;
+ case 0xF4: std::cout << "InterruptProcess "; break;
+ case 0xF3: std::cout << "Break "; break;
+ case 0xF2: std::cout << "DataMark "; break;
+ case 0xF1: std::cout << "NOP "; break;
+ case 0xF0: std::cout << "SE "; break;
+ default: std::cout << (static_cast<int>( data[i] & 0xFF )) << ' ';
+ }
+ std::cout << std::endl;
+
+ }
+ waitAck = false;
+/*
+ std::string iacWillSuppressGoAhead{ "\x0FF\x0FB\x003", 3 };
+ if ( data == iacWillSuppressGoAhead )
+ {
+ waitAck = false;
+ cliSession.Prompt();
+ }
+
+ else
+ Disconnect();
+*/
+ }
+ else
+ {
+ for (size_t i = 0; i < data.size(); ++i)
+ Feed(data[i]);
+/*
+ auto str = data;
+ // trim trailing spaces
+ std::size_t endpos = str.find_last_not_of(" \t\r\n");
+ if( std::string::npos != endpos ) str = str.substr( 0, endpos+1 );
+
+ if ( cliSession.Feed( str ) ) cliSession.Prompt();
+ else Disconnect();
+*/
+ }
+ }
+#else
+
+ /*
+ See
+ https://www.iana.org/assignments/telnet-options/telnet-options.xhtml
+ for a list of telnet options
+ */
+
+ enum
+ {
+ SE = '\x0F0', // End of subnegotiation parameters.
+ NOP = '\x0F1', // No operation.
+ DataMark = '\x0F2', // The data stream portion of a Synch.
+ // This should always be accompanied
+ // by a TCP Urgent notification.
+ Break = '\x0F3', // NVT character BRK.
+ InterruptProcess = '\x0F4', // The function IP.
+ AbortOutput = '\x0F5', // The function AO.
+ AreYouThere = '\x0F6', // The function AYT.
+ EraseCharacter = '\x0F7', // The function EC.
+ EraseLine = '\x0F8', // The function EL.
+ GoAhead = '\x0F9', // The GA signal.
+ SB = '\x0FA', // Indicates that what follows is
+ // subnegotiation of the indicated
+ // option.
+ WILL = '\x0FB', // Indicates the desire to begin
+ // performing, or confirmation that
+ // you are now performing, the
+ // indicated option.
+ WONT = '\x0FC', // Indicates the refusal to perform,
+ // or continue performing, the
+ // indicated option.
+ DO = '\x0FD', // Indicates the request that the
+ // other party perform, or
+ // confirmation that you are expecting
+ // the other party to perform, the
+ // indicated option.
+ DONT = '\x0FE', // Indicates the demand that the
+ // other party stop performing,
+ // or confirmation that you are no
+ // longer expecting the other party
+ // to perform, the indicated option.
+ IAC = '\x0FF', // Data Byte 255.
+
+ _ECHO = '\x001',
+ SUPPRESS_GO_AHEAD = '\x003',
+ TERMINAL_TYPE = '\x018',
+ NEGOTIATE_ABOUT_WIN_SIZE = '\x01F',
+ TERMINAL_SPEED = '\x020',
+ NEW_ENV_OPTION = '\x027'
+ };
+
+ void OnDataReceived(const std::string& _data) override
+ {
+ for (auto c: _data)
+ Consume(c);
+ }
+
+private:
+
+ void Consume(signed char c)
+ {
+ if (escape)
+ {
+ if (c == IAC)
+ Data(c);
+ else
+ Command(c);
+ escape = false;
+ }
+ else
+ {
+ if (c == IAC)
+ escape = true;
+ else
+ Data(c);
+ }
+ }
+
+ void Data(signed char c)
+ {
+ switch(state)
+ {
+ case State::data:
+ Output(c);
+ break;
+ case State::sub:
+ RxSub(c);
+ break;
+ case State::wait_will:
+ RxWill(c);
+ state = State::data;
+ break;
+ case State::wait_wont:
+ RxWont(c);
+ state = State::data;
+ break;
+ case State::wait_do:
+ RxDo(c);
+ state = State::data;
+ break;
+ case State::wait_dont:
+ RxDont(c);
+ state = State::data;
+ break;
+ }
+ }
+
+ void Command(char c)
+ {
+/*
+ switch (static_cast<int>( c & 0xFF ))
+ {
+ case 0xFF: std::cout << "IAC" << std::endl; break;
+ case 0xFE: std::cout << "DONT" << std::endl; break;
+ case 0xFD: std::cout << "DO" << std::endl; break;
+ case 0xFC: std::cout << "WONT" << std::endl; break;
+ case 0xFB: std::cout << "WILL" << std::endl; break;
+ case 0xFA: std::cout << "SB" << std::endl; break;
+ case 0xF9: std::cout << "GoAhead" << std::endl; break;
+ case 0xF8: std::cout << "EraseLine" << std::endl; break;
+ case 0xF7: std::cout << "EraseCharacter" << std::endl; break;
+ case 0xF6: std::cout << "AreYouThere" << std::endl; break;
+ case 0xF5: std::cout << "AbortOutput" << std::endl; break;
+ case 0xF4: std::cout << "InterruptProcess" << std::endl; break;
+ case 0xF3: std::cout << "Break" << std::endl; break;
+ case 0xF2: std::cout << "DataMark" << std::endl; break;
+ case 0xF1: std::cout << "NOP" << std::endl; break;
+ case 0xF0: std::cout << "SE" << std::endl; break;
+ default: std::cout << (static_cast<int>( c & 0xFF )) << std::endl;;
+ }
+*/
+ switch(c)
+ {
+ case SE:
+ if (state == State::sub)
+ state = State::data;
+ else
+ std::cerr << "ERROR: received SE when not in sub state\n";
+ break;
+ case DataMark: // ?
+ case Break: // ?
+ case InterruptProcess:
+ case AbortOutput:
+ case AreYouThere:
+ case EraseCharacter:
+ case EraseLine:
+ case GoAhead:
+ case NOP:
+ state = State::data;
+ break;
+ case SB:
+ if (state != State::sub)
+ state = State::sub;
+ else
+ std::cout << "ERROR: received SB when already in sub state" << std::endl;
+ break;
+ case WILL:
+ state = State::wait_will;
+ break;
+ case WONT:
+ state = State::wait_wont;
+ break;
+ case DO:
+ state = State::wait_do;
+ break;
+ case DONT:
+ state = State::wait_dont;
+ break;
+ case IAC:
+ assert(false); // can't be here
+ state = State::data;
+ break;
+ }
+ }
+
+ void RxWill(char c)
+ {
+ #ifdef CLI_TELNET_TRACE
+ std::cout << "will " << static_cast<int>(c) << std::endl;
+ #endif
+ switch(c)
+ {
+ case SUPPRESS_GO_AHEAD:
+ SendIacCmd(WILL, SUPPRESS_GO_AHEAD);
+ break;
+ case NEGOTIATE_ABOUT_WIN_SIZE:
+ SendIacCmd(DO, NEGOTIATE_ABOUT_WIN_SIZE);
+ break;
+ default:
+ SendIacCmd(DONT, c);
+ };
+ }
+ void RxWont(char c)
+ {
+ #ifdef CLI_TELNET_TRACE
+ std::cout << "wont " << static_cast<int>(c) << std::endl;
+ #else
+ (void)c;
+ #endif
+ }
+ void RxDo(char c)
+ {
+ #ifdef CLI_TELNET_TRACE
+ std::cout << "do " << static_cast<int>(c) << std::endl;
+ #endif
+ switch (c)
+ {
+ case _ECHO:
+ SendIacCmd(DO, _ECHO);
+ break;
+ case SUPPRESS_GO_AHEAD:
+ SendIacCmd(WILL, SUPPRESS_GO_AHEAD);
+ break;
+ default:
+ SendIacCmd(WONT, c);
+ };
+ }
+ void RxDont(char c)
+ {
+ #ifdef CLI_TELNET_TRACE
+ std::cout << "dont " << static_cast<int>(c) << std::endl;
+ #else
+ (void)c;
+ #endif
+ }
+ void RxSub(char c)
+ {
+ #ifdef CLI_TELNET_TRACE
+ std::cout << "sub: " << static_cast<int>(c) << std::endl;
+ #else
+ (void)c;
+ #endif
+ }
+ void SendIacCmd(char action, char op)
+ {
+ std::string answer("\x0FF\x000\x000", 3);
+ answer[1] = action;
+ answer[2] = op;
+ this -> OutStream() << answer << std::flush;
+ }
+protected:
+ virtual void Output(signed char c)
+ {
+ #ifdef CLI_TELNET_TRACE
+ std::cout << "data: " << static_cast<int>(c) << std::endl;
+ #else
+ (void)c;
+ #endif
+ }
+private:
+ enum class State { data, sub, wait_will, wait_wont, wait_do, wait_dont };
+ State state = State::data;
+ bool escape = false;
+
+#endif
+
+private:
+ void Feed(char c)
+ {
+ if (std::isprint(c)) std::cout << c << std::endl;
+ else std::cout << "0x" << std::hex << static_cast<int>(c) << std::dec << std::endl;
+ }
+ std::string buffer;
+};
+
+template <typename ASIOLIB>
+class TelnetServer : public Server<ASIOLIB>
+{
+public:
+ TelnetServer(typename ASIOLIB::ContextType& ios, unsigned short port) :
+ Server<ASIOLIB>(ios, port)
+ {}
+ std::shared_ptr<Session> CreateSession(asiolib::ip::tcp::socket _socket) override
+ {
+ return std::make_shared<TelnetSession>(std::move(_socket));
+ }
+};
+
+//////////////
+
+class CliTelnetSession : public InputDevice, public TelnetSession, public CliSession
+{
+public:
+
+ CliTelnetSession(Scheduler& _scheduler, asiolib::ip::tcp::socket _socket, Cli& _cli, const std::function< void(std::ostream&)>& _exitAction, std::size_t historySize ) :
+ InputDevice(_scheduler),
+ TelnetSession(std::move(_socket)),
+ CliSession(_cli, TelnetSession::OutStream(), historySize),
+ poll(*this, *this)
+ {
+ ExitAction([this, _exitAction](std::ostream& _out){ _exitAction(_out), Disconnect(); } );
+ }
+protected:
+
+ void OnConnect() override
+ {
+ TelnetSession::OnConnect();
+ Enter();
+ Prompt();
+ }
+
+ void Output(signed char c) override // NB: C++ does not specify wether char is signed or unsigned
+ {
+ switch(step)
+ {
+ case Step::_1:
+ switch( c )
+ {
+ case EOF:
+ case 4: // EOT
+ Notify(std::make_pair(KeyType::eof,' ')); break;
+ case 8: // Backspace
+ case 127: // Backspace or Delete
+ Notify(std::make_pair(KeyType::backspace, ' ')); break;
+ //case 10: Notify(std::make_pair(KeyType::ret,' ')); break;
+ case 27: step = Step::_2; break; // symbol
+ case 13: step = Step::wait_0; break; // wait for 0 (ENTER key)
+ default: // ascii
+ {
+ const char ch = static_cast<char>(c);
+ Notify(std::make_pair(KeyType::ascii,ch));
+ }
+ }
+ break;
+
+ case Step::_2: // got 27 last time
+ if ( c == 91 )
+ {
+ step = Step::_3;
+ break; // arrow keys
+ }
+ else
+ {
+ step = Step::_1;
+ Notify(std::make_pair(KeyType::ignored,' '));
+ break; // unknown
+ }
+ break;
+
+ case Step::_3: // got 27 and 91
+ switch( c )
+ {
+ case 65: step = Step::_1; Notify(std::make_pair(KeyType::up,' ')); break;
+ case 66: step = Step::_1; Notify(std::make_pair(KeyType::down,' ')); break;
+ case 68: step = Step::_1; Notify(std::make_pair(KeyType::left,' ')); break;
+ case 67: step = Step::_1; Notify(std::make_pair(KeyType::right,' ')); break;
+ case 70: step = Step::_1; Notify(std::make_pair(KeyType::end,' ')); break;
+ case 72: step = Step::_1; Notify(std::make_pair(KeyType::home,' ')); break;
+ default: step = Step::_4; break; // not arrow keys
+ }
+ break;
+
+ case Step::_4:
+ if ( c == 126 ) Notify(std::make_pair(KeyType::canc,' '));
+ else Notify(std::make_pair(KeyType::ignored,' '));
+
+ step = Step::_1;
+
+ break;
+
+ case Step::wait_0:
+ if ( c == 0 /* linux */ || c == 10 /* win */ ) Notify(std::make_pair(KeyType::ret,' '));
+ else Notify(std::make_pair(KeyType::ignored,' '));
+
+ step = Step::_1;
+
+ break;
+
+ }
+ }
+
+private:
+
+ enum class Step { _1, _2, _3, _4, wait_0 };
+ Step step = Step::_1;
+ InputHandler poll;
+};
+
+template <typename ASIOLIB>
+class CliGenericTelnetServer : public Server<ASIOLIB>
+{
+public:
+ CliGenericTelnetServer(Cli& _cli, GenericAsioScheduler<ASIOLIB>& _scheduler, unsigned short port, std::size_t _historySize=100 ) :
+ Server<ASIOLIB>(_scheduler.AsioContext(), port),
+ scheduler(_scheduler),
+ cli(_cli),
+ historySize(_historySize)
+ {}
+ CliGenericTelnetServer(Cli& _cli, GenericAsioScheduler<ASIOLIB>& _scheduler, std::string address, unsigned short port, std::size_t _historySize=100 ) :
+ Server<ASIOLIB>(_scheduler.AsioContext(), address, port),
+ scheduler(_scheduler),
+ cli(_cli),
+ historySize(_historySize)
+ {}
+
+ void EnterAction(std::function< void(std::ostream&)> action)
+ {
+ enterAction = action;
+ }
+
+ void ExitAction( std::function< void(std::ostream&)> action )
+ {
+ exitAction = action;
+ }
+ std::shared_ptr<Session> CreateSession(asiolib::ip::tcp::socket _socket) override
+ {
+ return std::make_shared<CliTelnetSession>(scheduler, std::move(_socket), cli, exitAction, historySize);
+ }
+private:
+ Scheduler& scheduler;
+ Cli& cli;
+ std::function< void(std::ostream&)> enterAction;
+ std::function< void(std::ostream&)> exitAction;
+ std::size_t historySize;
+};
+
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_GENERICASIOREMOTECLI_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_GENERICASIOSCHEDULER_H_
+#define CLI_DETAIL_GENERICASIOSCHEDULER_H_
+
+#include "../scheduler.h"
+#include <memory> // unique_ptr
+
+namespace cli
+{
+namespace detail
+{
+
+template <typename ASIOLIB>
+class GenericAsioScheduler : public Scheduler
+{
+public:
+
+ using ContextType = typename ASIOLIB::ContextType;
+ using WorkGuard = typename ASIOLIB::WorkGuard;
+
+ GenericAsioScheduler() :
+ owned{true},
+ context{new ContextType()},
+ executor{*context},
+ work{std::make_unique<WorkGuard>(ASIOLIB::MakeWorkGuard(*context))}
+ {}
+
+ explicit GenericAsioScheduler(ContextType& _context) : context{&_context}, executor{*context} {}
+
+ ~GenericAsioScheduler() override
+ {
+ if (owned)
+ {
+ work.reset(); // work uses context, so it must be deleted before context
+ delete context;
+ }
+ }
+
+ // non copyable
+ GenericAsioScheduler(const GenericAsioScheduler&) = delete;
+ GenericAsioScheduler& operator=(const GenericAsioScheduler&) = delete;
+
+ void Stop()
+ {
+ if (work)
+ ASIOLIB::Reset(*work);
+ context->stop();
+ }
+
+ void Run()
+ {
+ context->run();
+ }
+
+ bool Stopped() const
+ {
+ return context->stopped();
+ }
+
+ void ExecOne() { context->run_one(); }
+
+ void PollOne() { context->poll_one(); }
+
+ void Post(const std::function<void()>& f) override
+ {
+ executor.Post(f);
+ }
+
+ ContextType& AsioContext() { return *context; }
+
+private:
+
+ using ExecutorType = typename ASIOLIB::Executor;
+
+ bool owned = false;
+ ContextType* context;
+ ExecutorType executor;
+ std::unique_ptr<WorkGuard> work;
+};
+
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_GENERICASIOSCHEDULER_H_
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_GENERICCLIASYNCSESSION_H_
+#define CLI_DETAIL_GENERICCLIASYNCSESSION_H_
+
+#include <string>
+#include "../cli.h" // CliSession
+#include "genericasioscheduler.h"
+
+namespace cli
+{
+namespace detail
+{
+
+template <typename ASIOLIB>
+class GenericCliAsyncSession : public CliSession
+{
+public:
+ GenericCliAsyncSession(GenericAsioScheduler<ASIOLIB>& _scheduler, Cli& _cli) :
+ CliSession(_cli, std::cout, 1),
+ input(_scheduler.AsioContext(), ::dup(STDIN_FILENO))
+ {
+ Read();
+ }
+ ~GenericCliAsyncSession() noexcept override
+ {
+ try { input.close(); } catch (const std::exception&) { /* do nothing */ }
+ }
+
+private:
+
+ void Read()
+ {
+ Prompt();
+ // Read a line of input entered by the user.
+ asiolib::async_read_until(
+ input,
+ inputBuffer,
+ '\n',
+ std::bind( &GenericCliAsyncSession::NewLine, this,
+ std::placeholders::_1,
+ std::placeholders::_2 )
+ );
+ }
+
+ void NewLine(const asiolibec::error_code& error, std::size_t length )
+ {
+ if ( !error || error == asiolib::error::not_found )
+ {
+ auto bufs = inputBuffer.data();
+ auto size = static_cast<long>(length);
+ if ( !error ) --size; // remove \n
+ std::string s(asiolib::buffers_begin( bufs ), asiolib::buffers_begin( bufs ) + size);
+ inputBuffer.consume( length );
+
+ Feed( s );
+ Read();
+ }
+ else
+ {
+ input.close();
+ }
+ }
+
+ asiolib::streambuf inputBuffer;
+ asiolib::posix::stream_descriptor input;
+};
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_GENERICCLIASYNCSESSION_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_HISTORY_H_
+#define CLI_DETAIL_HISTORY_H_
+
+#include <deque>
+#include <limits>
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <cassert>
+
+namespace cli
+{
+namespace detail
+{
+
+class History
+{
+public:
+
+ explicit History(std::size_t size) : maxSize(size) {}
+
+ // Insert a new item in the buffer, changing the current state to "inserting"
+ // If we're browsing the history (eg with arrow keys) the new item overwrites
+ // the current one.
+ // Otherwise, the item is added to the front of the container
+ void NewCommand(const std::string& item)
+ {
+ ++commands;
+ current = 0;
+ if (mode == Mode::browsing)
+ {
+ assert(!buffer.empty());
+ if (buffer.size() > 1 && buffer[1] == item) // try to insert an element identical to last one
+ buffer.pop_front();
+ else // the item was not identical
+ buffer[current] = item;
+ }
+ else // Mode::inserting
+ {
+ if (buffer.empty() || buffer[0] != item) // insert an element not equal to last one
+ Insert(item);
+ }
+ mode = Mode::inserting;
+ }
+
+ // Return the previous item of the history, updating the current item and
+ // changing the current state to "browsing"
+ // If we're already browsing the history (eg with arrow keys) the edit line is inserted
+ // to the front of the container.
+ // Otherwise, the line overwrites the current item.
+ std::string Previous(const std::string& line)
+ {
+ if (mode == Mode::inserting)
+ {
+ Insert(line);
+ mode = Mode::browsing;
+ current = (buffer.size() > 1) ? 1 : 0;
+ }
+ else // Mode::browsing
+ {
+ assert(!buffer.empty());
+ buffer[current] = line;
+ if (current != buffer.size()-1)
+ ++current;
+ }
+ assert(mode == Mode::browsing);
+ assert(current < buffer.size());
+ return buffer[current];
+ }
+
+ // Return the next item of the history, updating the current item.
+ std::string Next()
+ {
+ if (buffer.empty() || current == 0)
+ return {};
+ assert(current != 0);
+ --current;
+ assert(current < buffer.size());
+ return buffer[current];
+ }
+
+ // Show the whole history on the given ostream
+ void Show(std::ostream& out) const
+ {
+ out << '\n';
+ for (auto& item: buffer)
+ out << item << '\n';
+ out << '\n' << std::flush;
+ }
+
+ // cmds[0] is the oldest command, cmds[size-1] the newer
+ void LoadCommands(const std::vector<std::string>& cmds)
+ {
+ for (const auto& c: cmds)
+ Insert(c);
+ }
+
+ // result[0] is the oldest command, result[size-1] the newer
+ std::vector<std::string> GetCommands() const
+ {
+ auto numCmdsToReturn = std::min(commands, buffer.size());
+ auto start = buffer.begin();
+ if (mode == Mode::browsing)
+ {
+ numCmdsToReturn = std::min(commands, buffer.size()-1);
+ start = buffer.begin()+1;
+ }
+ std::vector<std::string> result(numCmdsToReturn);
+ assert(std::distance(start, buffer.end()) >= 0);
+ assert(numCmdsToReturn <= static_cast<std::size_t>(std::distance(buffer.end(), start)));
+ assert(numCmdsToReturn <= static_cast<unsigned long>(std::numeric_limits<long>::max()));
+ std::reverse_copy(start, start+static_cast<long>(numCmdsToReturn), result.begin());
+ return result;
+ }
+
+private:
+
+ void Insert(const std::string& item)
+ {
+ buffer.push_front(item);
+ if (buffer.size() > maxSize)
+ buffer.pop_back();
+ }
+
+ const std::size_t maxSize;
+ std::deque<std::string> buffer;
+ std::size_t current = 0;
+ std::size_t commands = 0; // number of commands issued
+ enum class Mode { inserting, browsing };
+ Mode mode = Mode::inserting;
+};
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_HISTORY_H_
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_INPUTDEVICE_H_
+#define CLI_DETAIL_INPUTDEVICE_H_
+
+#include <functional>
+#include <string>
+#include "../scheduler.h"
+
+namespace cli
+{
+namespace detail
+{
+
+enum class KeyType { ascii, up, down, left, right, backspace, canc, home, end, ret, eof, ignored };
+
+class InputDevice
+{
+public:
+ using Handler = std::function< void( std::pair<KeyType,char> ) >;
+
+ explicit InputDevice(Scheduler& _scheduler) : scheduler(_scheduler) {}
+ virtual ~InputDevice() = default;
+
+ template <typename H>
+ void Register(H&& h) { handler = std::forward<H>(h); }
+
+protected:
+
+ void Notify(std::pair<KeyType,char> k)
+ {
+ scheduler.Post([this,k](){ if (handler) handler(k); });
+ }
+
+private:
+
+ Scheduler& scheduler;
+ Handler handler;
+};
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_INPUTDEVICE_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_INPUTHANDLER_H_
+#define CLI_DETAIL_INPUTHANDLER_H_
+
+#include <functional>
+#include <string>
+#include "terminal.h"
+#include "inputdevice.h"
+#include "../cli.h" // CliSession
+#include "commonprefix.h"
+
+namespace cli
+{
+namespace detail
+{
+
+class InputHandler
+{
+public:
+ InputHandler(CliSession& _session, InputDevice& kb) :
+ session(_session),
+ terminal(session.OutStream())
+ {
+ kb.Register( [this](auto key){ this->Keypressed(key); } );
+ }
+
+private:
+
+ void Keypressed(std::pair<KeyType, char> k)
+ {
+ const std::pair<Symbol,std::string> s = terminal.Keypressed(k);
+ NewCommand(s);
+ }
+
+ void NewCommand(const std::pair<Symbol, std::string>& s)
+ {
+ switch (s.first)
+ {
+ case Symbol::nothing:
+ {
+ break;
+ }
+ case Symbol::eof:
+ {
+ session.Exit();
+ break;
+ }
+ case Symbol::command:
+ {
+ session.Feed(s.second);
+ session.Prompt();
+ break;
+ }
+ case Symbol::down:
+ {
+ terminal.SetLine(session.NextCmd());
+ break;
+ }
+ case Symbol::up:
+ {
+ auto line = terminal.GetLine();
+ terminal.SetLine(session.PreviousCmd(line));
+ break;
+ }
+ case Symbol::tab:
+ {
+ auto line = terminal.GetLine();
+ auto completions = session.GetCompletions(line);
+
+ if (completions.empty())
+ break;
+ if (completions.size() == 1)
+ {
+ terminal.SetLine(completions[0]+' ');
+ break;
+ }
+
+ auto commonPrefix = CommonPrefix(completions);
+ if (commonPrefix.size() > line.size())
+ {
+ terminal.SetLine(commonPrefix);
+ break;
+ }
+ session.OutStream() << '\n';
+ std::string items;
+ std::for_each( completions.begin(), completions.end(), [&items](auto& cmd){ items += '\t' + cmd; } );
+ session.OutStream() << items << '\n';
+ session.Prompt();
+ terminal.ResetCursor();
+ terminal.SetLine( line );
+ break;
+ }
+ }
+
+ }
+
+ CliSession& session;
+ Terminal terminal;
+};
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_INPUTHANDLER_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_KEYBOARD_H_
+#define CLI_DETAIL_KEYBOARD_H_
+
+#if defined(__unix__) || defined(__unix) || defined(__linux__)
+ #define OS_LINUX
+#elif defined(WIN32) || defined(_WIN32) || defined(_WIN64)
+ #define OS_WIN
+#elif defined(__APPLE__) || defined(__MACH__)
+ #define OS_MAC
+#else
+ #error "Platform not supported (yet)."
+#endif
+
+#if defined(OS_LINUX) || defined(OS_MAC)
+ #include "linuxkeyboard.h"
+ namespace cli { namespace detail { using Keyboard = LinuxKeyboard; } }
+#elif defined(OS_WIN)
+ #include "winkeyboard.h"
+ namespace cli { namespace detail { using Keyboard = WinKeyboard; } }
+#else
+ #error "Platform not supported (yet)."
+#endif
+
+#undef OS_LINUX
+#undef OS_WIN
+#undef OS_MAC
+
+#endif // CLI_DETAIL_KEYBOARD_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_LINUXKEYBOARD_H_
+#define CLI_DETAIL_LINUXKEYBOARD_H_
+
+#include <thread>
+#include <memory>
+
+#include <cstdio>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/select.h>
+#include <cassert>
+
+#include "inputdevice.h"
+
+
+namespace cli
+{
+namespace detail
+{
+
+class InputSource
+{
+public:
+
+ InputSource()
+ {
+ int pipes[2];
+ if (pipe(pipes) == 0)
+ {
+ shutdownPipe = pipes[1]; // we store the write end
+ readPipe = pipes[0]; // ... and the read end
+ }
+ }
+
+ void WaitKbHit()
+ {
+ fd_set rfds;
+ FD_ZERO(&rfds);
+ FD_SET(STDIN_FILENO, &rfds);
+ FD_SET(readPipe, &rfds);
+
+ while (select(readPipe + 1, &rfds, nullptr, nullptr, nullptr) == 0);
+
+ if (FD_ISSET(readPipe, &rfds)) // stop called
+ {
+ close(readPipe);
+ throw std::runtime_error("InputSource stop");
+ }
+
+ if (FD_ISSET(STDIN_FILENO, &rfds)) // char from stdinput
+ {
+ return;
+ }
+
+ // cannot reach this point
+ assert(false);
+ }
+
+ void Stop()
+ {
+ auto unused = write(shutdownPipe, " ", 1);
+ unused = close(shutdownPipe);
+ static_cast<void>(unused); // silence unused warn
+ shutdownPipe = -1;
+ }
+
+private:
+ int shutdownPipe;
+ int readPipe;
+};
+
+//
+
+
+class LinuxKeyboard : public InputDevice
+{
+public:
+ explicit LinuxKeyboard(Scheduler& _scheduler) :
+ InputDevice(_scheduler),
+ servant( [this]() noexcept { Read(); } )
+ {
+ ToManualMode();
+ }
+ ~LinuxKeyboard() override
+ {
+ ToStandardMode();
+ is.Stop();
+ servant.join();
+ }
+
+private:
+
+ void Read() noexcept
+ {
+ try
+ {
+ while (true)
+ {
+ auto k = Get();
+ Notify(k);
+ }
+ }
+ catch(const std::exception&)
+ {
+ // nothing to do: just exit
+ }
+ }
+
+ char GetChar()
+ {
+ char buffer = 0;
+ auto unused = read(0, &buffer, 1);
+ static_cast<void>(unused); // silence unused warn
+ return buffer;
+ }
+
+ std::pair<KeyType,char> Get()
+ {
+ is.WaitKbHit();
+
+ auto ch = GetChar();
+ switch(ch)
+ {
+ case EOF:
+ case 4: // EOT
+ return std::make_pair(KeyType::eof,' ');
+ break;
+ case 127:
+ case 8:
+ return std::make_pair(KeyType::backspace,' '); break;
+ case 10: return std::make_pair(KeyType::ret,' '); break;
+ case 27: // symbol
+ ch = GetChar();
+ if ( ch == 91 ) // arrow keys
+ {
+ ch = GetChar();
+ switch( ch )
+ {
+ case 51:
+ ch = GetChar();
+ if ( ch == 126 ) return std::make_pair(KeyType::canc,' ');
+ else return std::make_pair(KeyType::ignored,' ');
+ break;
+ case 65: return std::make_pair(KeyType::up,' ');
+ case 66: return std::make_pair(KeyType::down,' ');
+ case 68: return std::make_pair(KeyType::left,' ');
+ case 67: return std::make_pair(KeyType::right,' ');
+ case 70: return std::make_pair(KeyType::end,' ');
+ case 72: return std::make_pair(KeyType::home,' ');
+ default: return std::make_pair(KeyType::ignored,' ');
+ }
+ }
+ break;
+ default: // ascii
+ {
+ const char c = static_cast<char>(ch);
+ return std::make_pair(KeyType::ascii,c);
+ }
+ }
+ return std::make_pair(KeyType::ignored,' ');
+ }
+
+ void ToManualMode()
+ {
+ constexpr tcflag_t ICANON_FLAG = ICANON;
+ constexpr tcflag_t ECHO_FLAG = ECHO;
+
+ tcgetattr(STDIN_FILENO, &oldt);
+ newt = oldt;
+ newt.c_lflag &= ~( ICANON_FLAG | ECHO_FLAG );
+ tcsetattr(STDIN_FILENO, TCSANOW, &newt);
+ }
+
+ void ToStandardMode()
+ {
+ tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
+ }
+
+ termios oldt;
+ termios newt;
+ InputSource is;
+ std::thread servant;
+};
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_LINUXKEYBOARD_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_NEWBOOSTASIOLIB_H_
+#define CLI_DETAIL_NEWBOOSTASIOLIB_H_
+
+#include <boost/version.hpp>
+#include <boost/asio.hpp>
+
+namespace cli
+{
+namespace detail
+{
+
+namespace asiolib = boost::asio;
+namespace asiolibec = boost::system;
+
+class NewBoostAsioLib
+{
+public:
+
+ using ContextType = boost::asio::io_context;
+ using WorkGuard = boost::asio::executor_work_guard<boost::asio::io_context::executor_type>;
+
+ class Executor
+ {
+ public:
+ explicit Executor(ContextType& ios) :
+ executor(ios.get_executor()) {}
+ explicit Executor(boost::asio::ip::tcp::socket& socket) :
+ executor(socket.get_executor()) {}
+ template <typename T> void Post(T&& t) { boost::asio::post(executor, std::forward<T>(t)); }
+ private:
+#if BOOST_VERSION >= 107400
+ using AsioExecutor = boost::asio::any_io_executor;
+#else
+ using AsioExecutor = boost::asio::executor;
+#endif
+ AsioExecutor executor;
+ };
+
+ static boost::asio::ip::address IpAddressFromString(const std::string& address)
+ {
+ return boost::asio::ip::make_address(address);
+ }
+
+ static auto MakeWorkGuard(ContextType& context)
+ {
+ return boost::asio::make_work_guard(context);
+ }
+
+ static void Reset(WorkGuard& wg)
+ {
+ wg.reset();
+ }
+
+};
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_NEWBOOSTASIOLIB_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_NEWSTANDALONEASIOLIB_H_
+#define CLI_DETAIL_NEWSTANDALONEASIOLIB_H_
+
+#include <asio/version.hpp>
+#include <asio.hpp>
+
+namespace cli
+{
+namespace detail
+{
+
+namespace asiolib = asio;
+namespace asiolibec = asio;
+
+class NewStandaloneAsioLib
+{
+public:
+
+ using ContextType = asio::io_context;
+ using WorkGuard = asio::executor_work_guard<asio::io_context::executor_type>;
+
+ class Executor
+ {
+ public:
+ explicit Executor(ContextType& ios) :
+ executor(ios.get_executor()) {}
+ explicit Executor(asio::ip::tcp::socket& socket) :
+ executor(socket.get_executor()) {}
+ template <typename T> void Post(T&& t) { asio::post(executor, std::forward<T>(t)); }
+ private:
+#if ASIO_VERSION >= 101700
+ using AsioExecutor = asio::any_io_executor;
+#else
+ using AsioExecutor = asio::executor;
+#endif
+ AsioExecutor executor;
+ };
+
+ static asio::ip::address IpAddressFromString(const std::string& address)
+ {
+ return asio::ip::make_address(address);
+ }
+
+ static auto MakeWorkGuard(ContextType& context)
+ {
+ return asio::make_work_guard(context);
+ }
+
+ static void Reset(WorkGuard& wg)
+ {
+ wg.reset();
+ }
+
+};
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_NEWSTANDALONEASIOLIB_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_OLDBOOSTASIOLIB_H_
+#define CLI_DETAIL_OLDBOOSTASIOLIB_H_
+
+#include <boost/asio.hpp>
+
+namespace cli
+{
+namespace detail
+{
+
+namespace asiolib = boost::asio;
+namespace asiolibec = boost::system;
+
+class OldBoostAsioLib
+{
+public:
+ using ContextType = boost::asio::io_service;
+ using WorkGuard = boost::asio::io_service::work;
+
+ class Executor
+ {
+ public:
+ explicit Executor(ContextType& _ios) :
+ ios(_ios) {}
+ explicit Executor(boost::asio::ip::tcp::socket& socket) :
+ ios(socket.get_io_service()) {}
+ template <typename T> void Post(T&& t) { ios.post(std::forward<T>(t)); }
+ private:
+ ContextType& ios;
+ };
+
+ static boost::asio::ip::address IpAddressFromString(const std::string& address)
+ {
+ return boost::asio::ip::address::from_string(address);
+ }
+
+ static auto MakeWorkGuard(ContextType& context)
+ {
+ boost::asio::io_service::work work(context);
+ return work;
+ }
+
+ static void Reset(WorkGuard& /*wg*/)
+ {
+ }
+
+};
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_OLDBOOSTASIOLIB_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_OLDSTANDALONEASIOLIB_H_
+#define CLI_DETAIL_OLDSTANDALONEASIOLIB_H_
+
+#define ASIO_STANDALONE 1
+
+#include <asio.hpp>
+
+namespace cli
+{
+namespace detail
+{
+
+namespace asiolib = asio;
+namespace asiolibec = asio;
+
+class OldStandaloneAsioLib
+{
+public:
+
+ using ContextType = asio::io_service;
+ using WorkGuard = asio::io_service::work;
+
+ class Executor
+ {
+ public:
+ explicit Executor(ContextType& _ios) :
+ ios(_ios) {}
+ explicit Executor(asio::ip::tcp::socket& socket) :
+ ios(socket.get_io_service()) {}
+ template <typename T> void Post(T&& t) { ios.post(std::forward<T>(t)); }
+ private:
+ ContextType& ios;
+ };
+
+ static asio::ip::address IpAddressFromString(const std::string& address)
+ {
+ return asio::ip::address::from_string(address);
+ }
+
+ static auto MakeWorkGuard(ContextType& context)
+ {
+ asio::io_service::work work(context);
+ return work;
+ }
+
+ static void Reset(WorkGuard& /*wg*/)
+ {
+ }
+
+};
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_OLDSTANDALONEASIOLIB_H_
+
--- /dev/null
+#ifndef CLI_DETAIL_RANG_H
+#define CLI_DETAIL_RANG_H
+
+#if defined(__unix__) || defined(__unix) || defined(__linux__)
+#define OS_LINUX
+#elif defined(WIN32) || defined(_WIN32) || defined(_WIN64)
+#define OS_WIN
+#elif defined(__APPLE__) || defined(__MACH__)
+#define OS_MAC
+#else
+#error Unknown Platform
+#endif
+
+#if defined(OS_LINUX) || defined(OS_MAC)
+ #include <unistd.h>
+ #include <cstring>
+#elif defined(OS_WIN)
+ #if !defined(NOMINMAX)
+ #define NOMINMAX 1
+ #endif // !defined(NOMINMAX)
+ #include <windows.h>
+ #include <io.h>
+ #include <VersionHelpers.h>
+#endif
+
+#include <algorithm>
+#include <cstdlib>
+#include <ios>
+#include <iostream>
+#include <iterator>
+#include <type_traits>
+
+namespace cli {
+namespace detail {
+namespace rang {
+
+enum class style {
+ reset = 0,
+ bold = 1,
+ dim = 2,
+ italic = 3,
+ underline = 4,
+ blink = 5,
+ rblink = 6,
+ reversed = 7,
+ conceal = 8,
+ crossed = 9
+};
+
+enum class fg {
+ black = 30,
+ red = 31,
+ green = 32,
+ yellow = 33,
+ blue = 34,
+ magenta = 35,
+ cyan = 36,
+ gray = 37,
+ reset = 39
+};
+
+enum class bg {
+ black = 40,
+ red = 41,
+ green = 42,
+ yellow = 43,
+ blue = 44,
+ magenta = 45,
+ cyan = 46,
+ gray = 47,
+ reset = 49
+};
+
+enum class fgB {
+ black = 90,
+ red = 91,
+ green = 92,
+ yellow = 93,
+ blue = 94,
+ magenta = 95,
+ cyan = 96,
+ gray = 97
+};
+
+enum class bgB {
+ black = 100,
+ red = 101,
+ green = 102,
+ yellow = 103,
+ blue = 104,
+ magenta = 105,
+ cyan = 106,
+ gray = 107
+};
+
+enum class control { autoColor = 0, forceColor = 1 };
+
+
+namespace rang_implementation {
+
+ inline std::streambuf const *&RANG_coutbuf()
+ {
+ static std::streambuf const *pOutbuff = std::cout.rdbuf();
+ return pOutbuff;
+ }
+
+ inline std::streambuf const *&RANG_cerrbuf()
+ {
+ static std::streambuf const *pErrbuff = std::cerr.rdbuf();
+ return pErrbuff;
+ }
+
+ inline std::streambuf const *&RANG_clogbuf()
+ {
+ static std::streambuf const *pLogbuff = std::clog.rdbuf();
+ return pLogbuff;
+ }
+
+ inline int getIword()
+ {
+ static int i = std::ios_base::xalloc();
+ return i;
+ }
+
+
+ inline bool supportsColor()
+ {
+#if defined(OS_LINUX) || defined(OS_MAC)
+ static constexpr const char* Terms[] = {
+ "ansi", "color", "console", "cygwin", "gnome", "konsole", "kterm",
+ "linux", "msys", "putty", "rxvt", "screen", "vt100", "xterm"
+ };
+
+ const char *env_p = std::getenv("TERM");
+ if (env_p == nullptr) {
+ return false;
+ }
+
+ static const bool result = std::any_of(
+ std::begin(Terms), std::end(Terms), [&](const char* term) {
+ return std::strstr(env_p, term) != nullptr;
+ });
+
+#elif defined(OS_WIN)
+ static constexpr bool result = true;
+#endif
+ return result;
+ }
+
+
+ inline bool isTerminal(const std::streambuf *osbuf)
+ {
+ if (osbuf == RANG_coutbuf()) {
+#if defined(OS_LINUX) || defined(OS_MAC)
+ return isatty(fileno(stdout)) ? true : false;
+#elif defined(OS_WIN)
+ return _isatty(_fileno(stdout)) ? true : false;
+#endif
+ }
+
+ if (osbuf == RANG_cerrbuf() || osbuf == RANG_clogbuf()) {
+#if defined(OS_LINUX) || defined(OS_MAC)
+ return isatty(fileno(stderr)) ? true : false;
+#elif defined(OS_WIN)
+ return _isatty(_fileno(stderr)) ? true : false;
+#endif
+ }
+ return false;
+ }
+
+
+ template <typename T>
+ using enableStd =
+ typename std::enable_if<std::is_same<T, rang::style>::value
+ || std::is_same<T, rang::fg>::value
+ || std::is_same<T, rang::bg>::value
+ || std::is_same<T, rang::fgB>::value
+ || std::is_same<T, rang::bgB>::value,
+ std::ostream &>::type;
+
+
+#ifdef OS_WIN
+ inline HANDLE getVersionDependentHandle()
+ {
+ if (IsWindowsVersionOrGreater(10, 0, 0)) return nullptr;
+ return GetStdHandle(STD_OUTPUT_HANDLE);
+ }
+
+ inline HANDLE getConsoleHandle()
+ {
+ static HANDLE h = getVersionDependentHandle();
+ return h;
+ }
+
+ inline WORD reverseRGB(WORD rgb)
+ {
+ static const WORD rev[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
+ return rev[rgb];
+ }
+
+ inline void setWinAttribute(rang::bg col, WORD &state)
+ {
+ state &= 0xFF0F;
+ state |= reverseRGB(static_cast<WORD>(col) - 40) << 4;
+ }
+
+ inline void setWinAttribute(rang::fg col, WORD &state)
+ {
+ state &= 0xFFF0;
+ state |= reverseRGB(static_cast<WORD>(col) - 30);
+ }
+
+ inline void setWinAttribute(rang::bgB col, WORD &state)
+ {
+ state &= 0xFF0F;
+ state |= (0x8 | reverseRGB(static_cast<WORD>(col) - 100)) << 4;
+ }
+
+ inline void setWinAttribute(rang::fgB col, WORD &state)
+ {
+ state &= 0xFFF0;
+ state |= (0x8 | reverseRGB(static_cast<WORD>(col) - 90));
+ }
+
+ inline void setWinAttribute(rang::style style, WORD &state)
+ {
+ if (style == rang::style::reset) {
+ state = (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
+ }
+ }
+
+ inline WORD ¤t_state()
+ {
+ static WORD state
+ = (FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED);
+ return state;
+ }
+
+ template <typename T>
+ inline enableStd<T> setColor(std::ostream &os, T const value)
+ {
+ HANDLE h = getConsoleHandle();
+ if (h && isTerminal(os.rdbuf())) {
+ setWinAttribute(value, current_state());
+ SetConsoleTextAttribute(h, current_state());
+ return os;
+ }
+ return os << "\033[" << static_cast<int>(value) << "m";
+ }
+#else
+ template <typename T>
+ inline enableStd<T> setColor(std::ostream &os, T const value)
+ {
+ return os << "\033[" << static_cast<int>(value) << "m";
+ }
+#endif
+
+ template <typename T>
+ using enableControl =
+ typename std::enable_if<std::is_same<T, rang::control>::value,
+ std::ostream &>::type;
+} // namespace rang_implementation
+
+inline void init()
+{
+ rang_implementation::RANG_coutbuf();
+ rang_implementation::RANG_cerrbuf();
+ rang_implementation::RANG_clogbuf();
+}
+
+template <typename T>
+inline rang_implementation::enableStd<T> operator<<(
+ std::ostream &os, T const value)
+{
+ std::streambuf const *osbuf = os.rdbuf();
+ return (os.iword(rang_implementation::getIword())
+ || ((rang_implementation::supportsColor())
+ && (rang_implementation::isTerminal(osbuf))))
+ ? rang_implementation::setColor(os, value)
+ : os;
+}
+
+template <typename T>
+inline rang_implementation::enableControl<T> operator<<(
+ std::ostream &os, T const value)
+{
+ if (value == rang::control::forceColor) {
+ os.iword(rang_implementation::getIword()) = 1;
+ } else if (value == rang::control::autoColor) {
+ os.iword(rang_implementation::getIword()) = 0;
+ }
+ return os;
+}
+
+} // namespace rang
+} // namespace detail
+} // namespace cli
+
+#undef OS_LINUX
+#undef OS_WIN
+#undef OS_MAC
+
+#endif // CLI_DETAIL_RANG_H
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_SERVER_H_
+#define CLI_DETAIL_SERVER_H_
+
+#include <memory>
+#include <queue>
+
+namespace cli
+{
+namespace detail
+{
+
+class Session : public std::enable_shared_from_this<Session>, public std::streambuf
+{
+public:
+ ~Session() override = default;
+ virtual void Start()
+ {
+ OnConnect();
+ Read();
+ }
+
+protected:
+
+ explicit Session(asiolib::ip::tcp::socket _socket) : socket(std::move(_socket)), outStream( this ) {}
+
+ virtual void Disconnect()
+ {
+ socket.shutdown(asiolib::ip::tcp::socket::shutdown_both);
+ socket.close();
+ }
+
+ virtual void Read()
+ {
+ auto self( shared_from_this() );
+ socket.async_read_some(asiolib::buffer( data, max_length ),
+ [ this, self ]( asiolibec::error_code ec, std::size_t length )
+ {
+ if ( !socket.is_open() || ( ec == asiolib::error::eof ) || ( ec == asiolib::error::connection_reset ) )
+ OnDisconnect();
+ else if ( ec )
+ OnError();
+ else
+ {
+ OnDataReceived( std::string( data, length ));
+ Read();
+ }
+ });
+ }
+
+ virtual void Send(const std::string& msg)
+ {
+ asiolibec::error_code ec;
+ asiolib::write(socket, asiolib::buffer(msg), ec);
+ if ((ec == asiolib::error::eof) || (ec == asiolib::error::connection_reset))
+ OnDisconnect();
+ else if (ec)
+ OnError();
+ }
+
+ virtual std::ostream& OutStream() { return outStream; }
+
+ virtual void OnConnect() = 0;
+ virtual void OnDisconnect() = 0;
+ virtual void OnError() = 0;
+ virtual void OnDataReceived(const std::string& _data) = 0;
+
+ virtual std::string Encode(const std::string& _data) const { return _data; }
+
+private:
+
+ // std::streambuf
+ std::streamsize xsputn( const char* s, std::streamsize n ) override
+ {
+ Send(Encode(std::string(s, s+n)));
+ return n;
+ }
+ int overflow( int c ) override
+ {
+ Send(Encode(std::string(1, static_cast< char >(c))));
+ return c;
+ }
+
+ asiolib::ip::tcp::socket socket;
+ enum { max_length = 1024 };
+ char data[ max_length ];
+ std::ostream outStream;
+};
+
+
+template <typename ASIOLIB>
+class Server
+{
+public:
+ // disable value semantics
+ Server( const Server& ) = delete;
+ Server& operator = ( const Server& ) = delete;
+
+ Server(typename ASIOLIB::ContextType& ios, unsigned short port) :
+ acceptor(ios, asiolib::ip::tcp::endpoint(asiolib::ip::tcp::v4(), port))
+ {
+ Accept();
+ }
+ Server(typename ASIOLIB::ContextType& ios, std::string address, unsigned short port) :
+ acceptor(ios, asiolib::ip::tcp::endpoint(ASIOLIB::IpAddressFromString(address), port))
+ {
+ Accept();
+ }
+ virtual ~Server() = default;
+ // returns shared_ptr instead of unique_ptr because Session needs to use enable_shared_from_this
+ virtual std::shared_ptr<Session> CreateSession(asiolib::ip::tcp::socket socket) = 0;
+private:
+ void Accept()
+ {
+ acceptor.async_accept([this](asiolibec::error_code ec, asiolib::ip::tcp::socket socket)
+ {
+ if (!ec) CreateSession(std::move(socket))->Start();
+ Accept();
+ });
+ }
+ asiolib::ip::tcp::acceptor acceptor;
+};
+
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_SERVER_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_SPLIT_H_
+#define CLI_DETAIL_SPLIT_H_
+
+#include <algorithm>
+#include <string>
+#include <utility>
+#include <vector>
+#include <cassert>
+
+namespace cli
+{
+namespace detail
+{
+
+class Text
+{
+public:
+ explicit Text(std::string _input) : input(std::move(_input))
+ {
+ }
+ void SplitInto(std::vector<std::string>& strs)
+ {
+ Reset();
+ for (char c: input)
+ Eval(c);
+ RemoveEmptyEntries();
+ splitResult.swap(strs); // puts the result back in strs
+ }
+private:
+ void Reset()
+ {
+ state = State::space;
+ prev_state = State::space;
+ sentence_type = SentenceType::double_quote;
+ splitResult.clear();
+ }
+
+ void Eval(char c)
+ {
+ switch(state)
+ {
+ case State::space:
+ EvalSpace(c);
+ break;
+ case State::word:
+ EvalWord(c);
+ break;
+ case State::sentence:
+ EvalSentence(c);
+ break;
+ case State::escape:
+ EvalEscape(c);
+ break;
+ }
+ }
+
+ void EvalSpace(char c)
+ {
+ if (c == ' ' || c == '\t' || c == '\n')
+ {
+ // do nothing
+ }
+ else if (c == '"' || c == '\'')
+ {
+ NewSentence(c);
+ }
+ else if (c == '\\')
+ {
+ // This is the case where the first character of a word is escaped.
+ // Should come back into the word state after this.
+ prev_state = State::word;
+ state = State::escape;
+ splitResult.emplace_back("");
+ }
+ else
+ {
+ state = State::word;
+ splitResult.emplace_back(1, c);
+ }
+ }
+
+ void EvalWord(char c)
+ {
+ if (c == ' ' || c == '\t' || c == '\n')
+ {
+ state = State::space;
+ }
+ else if (c == '"' || c == '\'')
+ {
+ NewSentence(c);
+ }
+ else if (c == '\\')
+ {
+ prev_state = state;
+ state = State::escape;
+ }
+ else
+ {
+ assert(!splitResult.empty());
+ splitResult.back() += c;
+ }
+ }
+
+ void EvalSentence(char c)
+ {
+ if (c == '"' || c == '\'')
+ {
+ auto new_type = c == '"' ? SentenceType::double_quote : SentenceType::quote;
+ if (new_type == sentence_type)
+ state = State::space;
+ else
+ {
+ assert(!splitResult.empty());
+ splitResult.back() += c;
+ }
+ }
+ else if (c == '\\')
+ {
+ prev_state = state;
+ state = State::escape;
+ }
+ else
+ {
+ assert(!splitResult.empty());
+ splitResult.back() += c;
+ }
+ }
+
+ void EvalEscape(char c)
+ {
+ assert(!splitResult.empty());
+ if (c != '"' && c != '\'' && c != '\\')
+ splitResult.back() += "\\";
+ splitResult.back() += c;
+ state = prev_state;
+ }
+
+ void NewSentence(char c)
+ {
+ state = State::sentence;
+ sentence_type = ( c == '"' ? SentenceType::double_quote : SentenceType::quote);
+ splitResult.emplace_back("");
+ }
+
+ void RemoveEmptyEntries()
+ {
+ // remove null entries from the vector:
+ splitResult.erase(
+ std::remove_if(
+ splitResult.begin(),
+ splitResult.end(),
+ [](const std::string& s){ return s.empty(); }
+ ),
+ splitResult.end()
+ );
+ }
+
+ enum class State { space, word, sentence, escape };
+ enum class SentenceType { quote, double_quote };
+ State state = State::space;
+ State prev_state = State::space;
+ SentenceType sentence_type = SentenceType::double_quote;
+ const std::string input;
+ std::vector<std::string> splitResult;
+};
+
+// Split the string input into a vector of strings.
+// The original string is split where there are spaces.
+// Quotes and double quotes can be used to indicate a substring that should not be splitted
+// (even if it contains spaces)
+
+// split(strs, ""); => empty vector
+// split(strs, " "); => empty vector
+// split(strs, " "); => empty vector
+// split(strs, "\t"); => empty vector
+// split(strs, " \t \t "); => empty vector
+
+// split(strs, "1234567890"); => <"1234567890">
+// split(strs, " foo "); => <"foo">
+// split(strs, " foo \t \t bar \t"); => <"foo","bar">
+
+// split(strs, "\"\""); => empty vector
+// split(strs, "\"foo bar\""); => <"foo bar">
+// split(strs, " \t\t \"foo \tbar\" \t"); => <"foo \tbar">
+// split(strs, " first \t\t \"foo \tbar\" \t last"); => <"first","foo \tbar","last">
+// split(strs, "first\"foo \tbar\""); => <"first","foo \tbar">
+// split(strs, "first \"'second' 'thirdh'\""); => <"first","'second' 'thirdh'">
+
+// split(strs, "''"); => empty vector
+// split(strs, "'foo bar'"); => <"foo bar">
+// split(strs, " \t\t 'foo \tbar' \t"); => <"foo \tbar">
+// split(strs, " first \t\t 'foo \tbar' \t last"); => <"first","foo \tbar","last">
+// split(strs, "first'foo \tbar'"); => <"first","foo \tbar">
+// split(strs, "first '\"second\" \"thirdh\"'"); => <"first","\"second\" \"thirdh\"">
+
+// split(strs, R"("foo\"bar")"); // "foo\"bar" => <"foo"bar">
+// split(strs, R"('foo\'bar')"); // 'foo\'bar' => <"foo'bar">
+// split(strs, R"("foo\bar")"); // "foo\bar" => <"foo\bar">
+// split(strs, R"("foo\\"bar")"); // "foo\\"bar" => <"foo\"bar">
+
+inline void split(std::vector<std::string>& strs, const std::string& input)
+{
+ Text sentence(input);
+ sentence.SplitInto(strs);
+}
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_SPLIT_H_
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_STANDALONEASIOLIB_H_
+#define CLI_DETAIL_STANDALONEASIOLIB_H_
+
+/**
+ * This header file provides the class `cli::StandaloneAsioLib`, using the right
+ * implementation according to the version of asio libraries included.
+ */
+
+#include <asio/version.hpp>
+
+#if ASIO_VERSION < 101300
+ #include "oldstandaloneasiolib.h"
+ namespace cli { namespace detail { using StandaloneAsioLib = OldStandaloneAsioLib; } }
+#else
+ #include "newstandaloneasiolib.h"
+ namespace cli { namespace detail { using StandaloneAsioLib = NewStandaloneAsioLib; } }
+#endif
+
+#endif // CLI_DETAIL_STANDALONEASIOLIB_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_TERMINAL_H_
+#define CLI_DETAIL_TERMINAL_H_
+
+#include <string>
+#include "../colorprofile.h"
+#include "inputdevice.h"
+
+namespace cli
+{
+namespace detail
+{
+
+enum class Symbol
+{
+ nothing,
+ command,
+ up,
+ down,
+ tab,
+ eof
+};
+
+class Terminal
+{
+ public:
+ explicit Terminal(std::ostream &_out) : out(_out) {}
+
+ void ResetCursor() { position = 0; }
+
+ void SetLine(const std::string &newLine)
+ {
+ out << beforeInput
+ << std::string(position, '\b') << newLine
+ << afterInput << std::flush;
+
+ // if newLine is shorter than currentLine, we have
+ // to clear the rest of the string
+ if (newLine.size() < currentLine.size())
+ {
+ out << std::string(currentLine.size() - newLine.size(), ' ');
+ // and go back
+ out << std::string(currentLine.size() - newLine.size(), '\b') << std::flush;
+ }
+
+ currentLine = newLine;
+ position = currentLine.size();
+ }
+
+ std::string GetLine() const { return currentLine; }
+
+ std::pair<Symbol, std::string> Keypressed(std::pair<KeyType, char> k)
+ {
+ switch (k.first)
+ {
+ case KeyType::eof:
+ return std::make_pair(Symbol::eof, std::string{});
+ break;
+ case KeyType::backspace:
+ {
+ if (position == 0)
+ break;
+
+ --position;
+
+ const auto pos = static_cast<std::string::difference_type>(position);
+ // remove the char from buffer
+ currentLine.erase(currentLine.begin() + pos);
+ // go back to the previous char
+ out << '\b';
+ // output the rest of the line
+ out << std::string(currentLine.begin() + pos, currentLine.end());
+ // remove last char
+ out << ' ';
+ // go back to the original position
+ out << std::string(currentLine.size() - position + 1, '\b') << std::flush;
+ break;
+ }
+ case KeyType::up:
+ return std::make_pair(Symbol::up, std::string{});
+ break;
+ case KeyType::down:
+ return std::make_pair(Symbol::down, std::string{});
+ break;
+ case KeyType::left:
+ if (position > 0)
+ {
+ out << '\b' << std::flush;
+ --position;
+ }
+ break;
+ case KeyType::right:
+ if (position < currentLine.size())
+ {
+ out << beforeInput
+ << currentLine[position]
+ << afterInput << std::flush;
+ ++position;
+ }
+ break;
+ case KeyType::ret:
+ {
+ out << "\r\n";
+ auto cmd = currentLine;
+ currentLine.clear();
+ position = 0;
+ return std::make_pair(Symbol::command, cmd);
+ }
+ break;
+ case KeyType::ascii:
+ {
+ const char c = static_cast<char>(k.second);
+ if (c == '\t')
+ return std::make_pair(Symbol::tab, std::string());
+ else
+ {
+ const auto pos = static_cast<std::string::difference_type>(position);
+
+ // output the new char:
+ out << beforeInput << c;
+ // and the rest of the string:
+ out << std::string(currentLine.begin() + pos, currentLine.end())
+ << afterInput;
+
+ // go back to the original position
+ out << std::string(currentLine.size() - position, '\b') << std::flush;
+
+ // update the buffer and cursor position:
+ currentLine.insert(currentLine.begin() + pos, c);
+ ++position;
+ }
+
+ break;
+ }
+ case KeyType::canc:
+ {
+ if (position == currentLine.size())
+ break;
+
+ const auto pos = static_cast<std::string::difference_type>(position);
+
+ // output the rest of the line
+ out << std::string(currentLine.begin() + pos + 1, currentLine.end());
+ // remove last char
+ out << ' ';
+ // go back to the original position
+ out << std::string(currentLine.size() - position, '\b') << std::flush;
+ // remove the char from buffer
+ currentLine.erase(currentLine.begin() + pos);
+ break;
+ }
+ case KeyType::end:
+ {
+ const auto pos = static_cast<std::string::difference_type>(position);
+
+ out << beforeInput
+ << std::string(currentLine.begin() + pos, currentLine.end())
+ << afterInput << std::flush;
+ position = currentLine.size();
+ break;
+ }
+ case KeyType::home:
+ {
+ out << std::string(position, '\b') << std::flush;
+ position = 0;
+ break;
+ }
+ case KeyType::ignored:
+ // TODO
+ break;
+ }
+
+ return std::make_pair(Symbol::nothing, std::string());
+ }
+
+ private:
+ std::string currentLine;
+ std::size_t position = 0; // next writing position in currentLine
+ std::ostream &out;
+};
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_TERMINAL_H_
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_DETAIL_WINKEYBOARD_H_
+#define CLI_DETAIL_WINKEYBOARD_H_
+
+#include <functional>
+#include <string>
+#include <thread>
+#include <memory>
+#include <conio.h>
+#include <cassert>
+
+#include "inputdevice.h"
+
+#if !defined(NOMINMAX)
+#define NOMINMAX 1 // prevent windows from defining min and max macros
+#endif // !defined(NOMINMAX)
+#include <windows.h>
+
+namespace cli
+{
+namespace detail
+{
+
+class InputSource
+{
+public:
+
+ InputSource()
+ {
+ events[0] = CreateEvent(nullptr, FALSE, FALSE, nullptr); // Obtain a Windows handle to use to stop
+ events[1] = GetStdHandle(STD_INPUT_HANDLE); // Get a Windows handle to the keyboard input
+ }
+
+ void WaitKbHit()
+ {
+ // Wait for either the timer to expire or a key press event
+ DWORD dwResult = WaitForMultipleObjects(2, events, false, INFINITE);
+
+ if (dwResult == WAIT_FAILED)
+ {
+ // TODO
+ assert(false);
+ }
+ else
+ {
+ if (dwResult == WAIT_OBJECT_0) // WAIT_OBJECT_0 corresponds to the stop event
+ {
+ throw std::runtime_error("InputSource stop");
+ }
+ else
+ {
+ return;
+ }
+ }
+
+ // we can't reach this point
+ assert(false);
+ }
+
+ void Stop()
+ {
+ SetEvent(events[0]);
+ }
+
+private:
+ HANDLE events[2];
+};
+
+//
+
+class WinKeyboard : public InputDevice
+{
+public:
+ explicit WinKeyboard(Scheduler& _scheduler) :
+ InputDevice(_scheduler),
+ servant([this]() noexcept { Read(); })
+ {
+ }
+ ~WinKeyboard() override
+ {
+ is.Stop();
+ servant.join();
+ }
+
+private:
+
+ void Read() noexcept
+ {
+ try
+ {
+ while (true)
+ {
+ auto k = Get();
+ Notify(k);
+ }
+ }
+ catch (const std::exception&)
+ {
+ // nothing to do: just exit
+ }
+ }
+
+ std::pair<KeyType, char> Get()
+ {
+ is.WaitKbHit();
+
+ int c = _getch();
+ switch (c)
+ {
+ case EOF:
+ case 4: // EOT ie CTRL-D
+ case 26: // CTRL-Z
+ case 3: // CTRL-C
+ return std::make_pair(KeyType::eof, ' ');
+ break;
+
+ case 224: // symbol
+ {
+ c = _getch();
+ switch (c)
+ {
+ case 72: return std::make_pair(KeyType::up, ' ');
+ case 80: return std::make_pair(KeyType::down, ' ');
+ case 75: return std::make_pair(KeyType::left, ' ');
+ case 77: return std::make_pair(KeyType::right, ' ');
+ case 71: return std::make_pair(KeyType::home, ' ');
+ case 79: return std::make_pair(KeyType::end, ' ');
+ case 83: return std::make_pair(KeyType::canc, ' ');
+ default: return std::make_pair(KeyType::ignored, ' ');
+ }
+ }
+ case 8:
+ return std::make_pair(KeyType::backspace, c);
+ break;
+ case 13:
+ return std::make_pair(KeyType::ret, c);
+ break;
+ default: // hopefully ascii
+ {
+ const char ch = static_cast<char>(c);
+ return std::make_pair(KeyType::ascii, ch);
+ }
+ }
+ return std::make_pair(KeyType::ignored, ' ');
+ }
+
+ InputSource is;
+ std::thread servant;
+};
+
+} // namespace detail
+} // namespace cli
+
+#endif // CLI_DETAIL_WINKEYBOARD_H_
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_FILEHISTORYSTORAGE_H_
+#define CLI_FILEHISTORYSTORAGE_H_
+
+#include "historystorage.h"
+#include <fstream>
+#include <utility>
+
+namespace cli
+{
+
+class FileHistoryStorage : public HistoryStorage
+{
+public:
+ explicit FileHistoryStorage(std::string _fileName, std::size_t size = 1000) :
+ maxSize(size),
+ fileName(std::move(_fileName))
+ {
+ }
+ void Store(const std::vector<std::string>& cmds) override
+ {
+ using dt = std::vector<std::string>::difference_type;
+ auto commands = Commands();
+ commands.insert(commands.end(), cmds.begin(), cmds.end());
+ if (commands.size() > maxSize)
+ commands.erase(
+ commands.begin(),
+ commands.begin() + static_cast<dt>(commands.size() - maxSize)
+ );
+ std::ofstream f(fileName, std::ios_base::out);
+ for (const auto& line: commands)
+ f << line << '\n';
+ }
+ std::vector<std::string> Commands() const override
+ {
+ std::vector<std::string> commands;
+ std::ifstream in(fileName);
+ if (in)
+ {
+ std::string line;
+ while (std::getline(in, line))
+ commands.push_back(line);
+ }
+ return commands;
+ }
+ void Clear() override
+ {
+ std::ofstream f(fileName, std::ios_base::out | std::ios_base::trunc);
+ }
+
+private:
+ const std::size_t maxSize;
+ const std::string fileName;
+};
+
+} // namespace cli
+
+#endif // CLI_FILEHISTORYSTORAGE_H_
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_HISTORYSTORAGE_H_
+#define CLI_HISTORYSTORAGE_H_
+
+#include <vector>
+#include <string>
+
+namespace cli
+{
+
+class HistoryStorage
+{
+public:
+ virtual ~HistoryStorage() = default;
+ // Store a vector of commands in the history storage
+ virtual void Store(const std::vector<std::string>& commands) = 0;
+ // Returns all the commands stored
+ virtual std::vector<std::string> Commands() const = 0;
+ // Clear the whole content of the storage
+ // After calling this method, Commands() returns the empty vector
+ virtual void Clear() = 0;
+};
+
+} // namespace cli
+
+#endif // CLI_HISTORYSTORAGE_H_
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_LOOPSCHEDULER_H_
+#define CLI_LOOPSCHEDULER_H_
+
+#include <queue>
+#include <thread>
+#include <mutex>
+#include <condition_variable>
+#include "scheduler.h"
+
+namespace cli
+{
+
+/**
+ * @brief The LoopScheduler is a simple thread-safe scheduler
+ *
+ */
+class LoopScheduler : public Scheduler
+{
+public:
+ LoopScheduler() = default;
+ ~LoopScheduler() override
+ {
+ Stop();
+ }
+
+ // non copyable
+ LoopScheduler(const LoopScheduler&) = delete;
+ LoopScheduler& operator=(const LoopScheduler&) = delete;
+
+ void Stop()
+ {
+ std::lock_guard<std::mutex> lck (mtx);
+ running = false;
+ cv.notify_all();
+ }
+
+ void Run()
+ {
+ while( ExecOne() ) {};
+ }
+
+ bool Stopped() const
+ {
+ std::lock_guard<std::mutex> lck (mtx);
+ return !running;
+ }
+
+ void Post(const std::function<void()>& f) override
+ {
+ std::lock_guard<std::mutex> lck (mtx);
+ tasks.push(f);
+ cv.notify_all();
+ }
+
+ bool ExecOne()
+ {
+ std::function<void()> task;
+ {
+ std::unique_lock<std::mutex> lck(mtx);
+ cv.wait(lck, [this](){ return !running || !tasks.empty(); });
+ if (!running)
+ return false;
+ task = tasks.front();
+ tasks.pop();
+ }
+
+ if (task)
+ task();
+
+ return true;
+ }
+
+ bool PollOne()
+ {
+ std::function<void()> task;
+ {
+ std::lock_guard<std::mutex> lck(mtx);
+ if (!running || tasks.empty())
+ return false;
+ task = tasks.front();
+ tasks.pop();
+ }
+
+ if (task)
+ task();
+
+ return true;
+ }
+
+private:
+ std::queue<std::function<void()>> tasks;
+ bool running{ true };
+ mutable std::mutex mtx;
+ std::condition_variable cv;
+};
+
+} // namespace cli
+
+#endif // CLI_LOOPSCHEDULER_H_
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_SCHEDULER_H_
+#define CLI_SCHEDULER_H_
+
+#include <functional>
+
+namespace cli
+{
+
+/**
+ * A `Scheduler` represents an engine capable of running a task.
+ * Its method `Post` can be safely called from any thread to submit the task
+ * that will execute in an unspecified thread of execution as soon as possible
+ * (but in any case after the call to `Post` is terminated).
+ */
+class Scheduler
+{
+public:
+ virtual ~Scheduler() = default;
+
+ /// Submits a completion token or function object for execution.
+ virtual void Post(const std::function<void()>& f) = 0;
+};
+
+} // namespace cli
+
+#endif // CLI_SCHEDULER_H_
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_STANDALONEASIOCLIASYNCSESSION_H_
+#define CLI_STANDALONEASIOCLIASYNCSESSION_H_
+
+#include "detail/genericcliasyncsession.h"
+#include "detail/standaloneasiolib.h"
+
+
+namespace cli { using StandaloneAsioCliAsyncSession = detail::GenericCliAsyncSession<detail::StandaloneAsioLib>; }
+
+#endif // CLI_STANDALONEASIOCLIASYNCSESSION_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_STANDALONEASIOREMOTECLI_H_
+#define CLI_STANDALONEASIOREMOTECLI_H_
+
+#include "detail/standaloneasiolib.h"
+#include "detail/genericasioremotecli.h"
+
+namespace cli { using StandaloneAsioCliTelnetServer = detail::CliGenericTelnetServer<detail::StandaloneAsioLib>; }
+
+
+#endif // CLI_STANDALONEASIOREMOTECLI_H_
+
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_STANDALONEASIOSCHEDULER_H_
+#define CLI_STANDALONEASIOSCHEDULER_H_
+
+#include "detail/genericasioscheduler.h"
+#include "detail/standaloneasiolib.h"
+
+namespace cli { using StandaloneAsioScheduler = detail::GenericAsioScheduler<detail::StandaloneAsioLib>; }
+
+#endif // CLI_STANDALONEASIOSCHEDULER_H_
--- /dev/null
+/*******************************************************************************
+ * CLI - A simple command line interface.
+ * Copyright (C) 2016-2021 Daniele Pallastrelli
+ *
+ * Boost Software License - Version 1.0 - August 17th, 2003
+ *
+ * Permission is hereby granted, free of charge, to any person or organization
+ * obtaining a copy of the software and accompanying documentation covered by
+ * this license (the "Software") to use, reproduce, display, distribute,
+ * execute, and transmit the Software, and to prepare derivative works of the
+ * Software, and to permit third-parties to whom the Software is furnished to
+ * do so, all subject to the following:
+ *
+ * The copyright notices in the Software and this entire statement, including
+ * the above license grant, this restriction and the following disclaimer,
+ * must be included in all copies of the Software, in whole or in part, and
+ * all derivative works of the Software, unless such copies or derivative
+ * works are solely in the form of machine-executable object code generated by
+ * a source language processor.
+ *
+ * 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+ * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+ * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ ******************************************************************************/
+
+#ifndef CLI_VOLATILEHISTORYSTORAGE_H_
+#define CLI_VOLATILEHISTORYSTORAGE_H_
+
+#include "historystorage.h"
+#include <deque>
+
+namespace cli
+{
+
+class VolatileHistoryStorage : public HistoryStorage
+{
+ public:
+ explicit VolatileHistoryStorage(std::size_t size = 1000) : maxSize(size) {}
+ void Store(const std::vector<std::string>& cmds) override
+ {
+ using dt = std::deque<std::string>::difference_type;
+ commands.insert(commands.end(), cmds.begin(), cmds.end());
+ if (commands.size() > maxSize)
+ commands.erase(
+ commands.begin(),
+ commands.begin()+static_cast<dt>(commands.size()-maxSize)
+ );
+ }
+ std::vector<std::string> Commands() const override
+ {
+ return std::vector<std::string>(commands.begin(), commands.end());
+ }
+ void Clear() override
+ {
+ commands.clear();
+ }
+ private:
+ const std::size_t maxSize;
+ std::deque<std::string> commands;
+};
+
+} // namespace cli
+
+#endif // CLI_VOLATILEHISTORYSTORAGE_H_
project(
'mmi',
['c', 'cpp'],
- version : '1.0.2',
- license : 'MIT',
- default_options : ['b_pie=true']
+ version : '2.0.0',
+ license : 'Apache-2.0',
+ default_options : ['b_pie=true', 'cpp_std=c++17']
)
mmi_version = meson.project_version().split('.')
mmi_prefix = get_option('prefix')
mmi_prefix_bindir = join_paths(mmi_prefix, get_option('bindir'))
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')
pkgconfig = import('pkgconfig')
+subdir('capi')
subdir('src')
+subdir('plugins')
subdir('tests')
%define USE_GCOV 0
Name: mmi
-Version: 1.0.2
+Version: 2.0.1
Release: 0
-Summary: Multi-modal Interaction Framework Library
+Summary: Multi-modal Interaction Framework
License: MIT
URL: http://www.tizen.org
Source: %{name}-%{version}.tar.xz
BuildRequires: meson
BuildRequires: tidl
-BuildRequires: pkgconfig(libtzplatform-config)
-BuildRequires: pkgconfig(bundle)
-BuildRequires: pkgconfig(gio-2.0)
+BuildRequires: pkgconfig(libtzplatform-config)
+BuildRequires: pkgconfig(bundle)
+BuildRequires: pkgconfig(gio-2.0)
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)
#Build dependencies for tests
BuildRequires: pkgconfig(gmock)
%description
-MMI(Multi-modal Interaction) Framework Library
+MMI(Multi-modal Interaction) Framework
+
+%package plugins
+Summary: Plugins for MMI Framework
+Group: System/Libraries
+%description plugins
+Plugins for MMI Framework
+
+%package cli
+Summary: CLI for MMI Framework
+Group: System/Libraries
+%description cli
+CLI for MMI Framework
%package devel
-Summary: Development package for MMI Framework Library
+Summary: Development package for MMI Framework
Group: Development/Libraries
Requires: %{name} = %{version}-%{release}
Requires: pkgconfig(rpc-port)
%description devel
-Development package for MMI Framework Library
+Development package for MMI Framework
%package tests
-Summary: Testcases for MMI Framework Library
+Summary: Testcases for MMI Framework
Group: System/Libraries
%description tests
Testcases for testing MMI Framework APIs
#generate mmi-proxy using TIDL Compiler
tidlc -p -l C -i tidl/mmi.tidl -o mmi_proxy
-mv mmi_proxy.* src
+mv mmi_proxy.* src/mmi
+tidlc -s -l C -i tidl/mmi.tidl -o mmi_stub
+mv mmi_stub.* src/mmi-manager
%build
%if "%{USE_GCOV}" == "1"
CXXFLAGS+=" -fprofile-arcs -ftest-coverage -DTIZEN_TEST_GCOV"
LDFLAGS+=" -lgcov"
%endif
+
meson setup --prefix=/usr \
--bindir %{_bindir} \
--libdir %{_libdir} \
+ --datadir %{_datadir} \
builddir
ninja -C builddir all
%install
DESTDIR=%{buildroot} ninja -C builddir install
+%check
+%if "%{_mmi_test_enable}" == "true"
+ninja -C builddir test
+%endif
+
%post -p /sbin/ldconfig
%postun -p /sbin/ldconfig
%defattr(-,root,root,-)
%license COPYING
%{_libdir}/*.so*
+%{_bindir}/mmi-manager
+%{_datadir}/packages/mmi-manager.xml
+
+%files plugins
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%license COPYING
+%{_datadir}/mmi/plugins/*.so*
+%{_datadir}/mmi/scripts/*.mws
+%{_datadir}/face_recognition/*
+
+%files cli
+%manifest %{name}.manifest
+%defattr(-,root,root,-)
+%license COPYING
+%{_bindir}/mmi-cli
+%{_bindir}/mmi-cli-node-tester
%files devel
%manifest %{name}.manifest
%defattr(-,root,root,-)
%license COPYING
%{_bindir}/mmi-tests
+%{_bindir}/mmi-manager-tests
--- /dev/null
+subdir('nodes')
+subdir('workflows')
--- /dev/null
+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
+ )
--- /dev/null
+/*
+ * 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-node.h>
+#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<Camera *>(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);
+ }
+}
+
--- /dev/null
+/*
+ * 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 <mmi-log.h>
+#include <functional>
+
+#include <mmi-node.h>
+#include <camera_internal.h>
+
+using camera_data_callback = std::function<void(void *, size_t, unsigned long, void *)>;
+
+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);
+};
--- /dev/null
+#include <mmi.h>
+#include <mmi-plugin-storage.h>
+#include <mmi-node.h>
+#include <mmi-log.h>
+
+#include <string>
+#include <map>
+#include <camera_internal.h>
+#include "mmi-module-camera-preview.h"
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "MMI-MODULE-CAMERA"
+
+static std::map<mmi_node_instance_h, Camera *> 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<mmi_node_instance_h, Camera *>(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"
--- /dev/null
+{
+ "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
--- /dev/null
+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/')
--- /dev/null
+/*
+ * 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 <json-glib-1.0/json-glib/json-glib.h>
+#include <mmi-log.h>
+
+#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 <std::mutex> 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 <std::mutex> 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 <std::mutex> 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 <std::mutex> 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 <std::mutex> 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 <std::mutex> 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 <std::mutex> 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<FaceInfo> DataManager::get_face_list()
+{
+ _D("[FR DATAMGR] get face list");
+ std::lock_guard <std::mutex> lock(*m_mutex);
+
+ std::vector<FaceInfo> list = m_face_list;
+ return list;
+}
--- /dev/null
+/*
+ * 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 <mutex>
+#include <string>
+#include <vector>
+
+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<FaceInfo> 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<FaceInfo> m_face_list;
+ int m_max_face_count{0};
+ std::string m_info_file_path{};
+ std::mutex* m_mutex{nullptr};
+};
--- /dev/null
+#include <mmi.h>
+#include <mmi-attribute.h>
+#include <mmi-node.h>
+#include <mmi-node-processor.h>
+#include <mmi-log.h>
+#include <mmi-error.h>
+
+#include <mv_face.h>
+#include <mv_common.h>
+#include <mv_inference.h>
+#include <mv_face_recognition.h>
+#include "mv_face_recognition_internal.h"
+#include <image_util.h>
+
+#include <string>
+#include <map>
+
+#include <dirent.h>
+#include <dlfcn.h>
+#include <dlog.h>
+#include <Ecore.h>
+
+#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<char *, facedata_s *> g_registered_faces_map;
+static std::map<mmi_port_instance_h, mmi_node_instance_h> 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<FaceInfo> 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<FaceInfo> 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"
--- /dev/null
+/*
+ * 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 <mv_common.h>
+#include <mv_face_recognition_type.h>
+
+#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__ */
--- /dev/null
+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
+ )
--- /dev/null
+/*
+ * 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-log.h>
+
+#include <algorithm>
+
+#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();
+}
+
--- /dev/null
+/*
+ * 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 <vector>
+#include <string>
+
+
+class TextCandidates {
+public:
+ TextCandidates();
+ ~TextCandidates();
+
+ void append_candidate(const char *candidate);
+ bool is_exist(const char *candidate);
+ void clear_candidates();
+
+private:
+ std::vector<std::string> m_candidates;
+};
+
+#endif /* __MMI_MODULE_MATCH_TEXT_CANDIDATES_H__ */
--- /dev/null
+#include <mmi-attribute.h>
+#include <mmi-node.h>
+#include <mmi-node-logic.h>
+#include <mmi-log.h>
+
+#include <map>
+#include <memory>
+
+#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<mmi_node_instance_h, std::shared_ptr<TextCandidates>> g_node_to_text_candidates_map;
+static std::map<mmi_port_instance_h, mmi_node_instance_h> 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<TextCandidates>();
+ 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"
--- /dev/null
+subdir('mic')
+subdir('camera')
+subdir('match')
+subdir('regex-match')
+subdir('face-recognition')
+subdir('voice-touch')
--- /dev/null
+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
+ )
--- /dev/null
+/*
+ * 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-module-mic-recorder.h>
+#include <mmi-node.h>
+#include <mmi-log.h>
+
+#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<Recorder*>(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;
+}
--- /dev/null
+/*
+ * 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 <functional>
+
+#include <Ecore.h>
+#include <sound_manager.h>
+#include <audio_io.h>
+
+#include <mmi-node.h>
+
+using audio_data_callback = std::function<void(void *, size_t, void *)>;
+
+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};
+};
--- /dev/null
+#include <mmi.h>
+#include <mmi-plugin-storage.h>
+#include <mmi-node.h>
+#include <mmi-log.h>
+
+#include <string>
+#include <map>
+
+#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<mmi_node_instance_h, Recorder *> 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<mmi_node_instance_h, Recorder *>(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"
--- /dev/null
+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
+ )
--- /dev/null
+/*
+ * 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-log.h>
+
+#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<std::string> 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();
+}
+
--- /dev/null
+/*
+ * 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 <vector>
+#include <string>
+#include <regex>
+#include <optional>
+
+class RegExCandidates {
+public:
+ RegExCandidates();
+ ~RegExCandidates();
+
+ void append_candidate(const char *regex_name, const char *regex_pattern);
+ std::optional<std::string> find_matched_candidate(const char *text);
+ void clear_candidates();
+
+private:
+ std::vector<std::pair<std::regex, std::string>> m_candidates;
+};
+
+#endif /* __MMI_MODULE_REGEX_MATCH_REGEX_CANDIDATES_H__ */
--- /dev/null
+#include <mmi-attribute.h>
+#include <mmi-node.h>
+#include <mmi-node-logic.h>
+#include <mmi-log.h>
+
+#include <map>
+#include <memory>
+
+#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<mmi_node_instance_h, std::shared_ptr<RegExCandidates>> g_node_to_regex_candidates_map;
+static std::map<mmi_port_instance_h, mmi_node_instance_h> 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<RegExCandidates>();
+ 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"
--- /dev/null
+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
+ )
--- /dev/null
+/*
+ * 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-log.h>
+
+#include <algorithm>
+#include <numeric>
+
+#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<voice_touch_candidate_s> &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<voice_touch_candidate_s> VoiceTouchCandidates::find_matched_candidate(size_t index)
+{
+ _I("[VOICE TOUCH] Find matched candidate. index(%zu)", index);
+ std::optional<voice_touch_candidate_s> 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<voice_touch_candidate_s> 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<voice_touch_candidate_s> 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<voice_touch_candidate_s> 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<voice_touch_candidate_s> VoiceTouchCandidates::find_matched_candidate_by_text(const std::vector<std::string> &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<voice_touch_candidate_s> VoiceTouchCandidates::find_matched_candidate_by_word(const std::vector<std::string> &splited_text)
+{
+ _I("[VOICE TOUCH] Find matched candidate by word.");
+
+ size_t max_matching_word_num = static_cast<size_t>(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<voice_touch_candidate_s> 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<voice_touch_candidate_s> VoiceTouchCandidates::find_matched_candidate_by_char(const std::vector<std::string> &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<std::string> 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<voice_touch_candidate_s> result;
+ size_t result_score = std::numeric_limits<size_t>::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<std::string> 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<size_t>(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<size_t>(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();
+}
--- /dev/null
+/*
+ * 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 <vector>
+#include <string>
+#include <functional>
+#include <optional>
+
+#include "mmi-module-voice-touch-common.h"
+
+
+class VoiceTouchCandidates {
+public:
+ VoiceTouchCandidates();
+ ~VoiceTouchCandidates();
+
+ void set_candidates(const std::vector<voice_touch_candidate_s> &candidates);
+ std::optional<voice_touch_candidate_s> find_matched_candidate(size_t index);
+ std::optional<voice_touch_candidate_s> find_matched_candidate(const char *text);
+ void clear_candidates();
+
+private:
+ std::optional<voice_touch_candidate_s> find_matched_candidate_by_index(size_t index);
+ std::optional<voice_touch_candidate_s> find_matched_candidate_by_text(const std::vector<std::string> &splited_text);
+ std::optional<voice_touch_candidate_s> find_matched_candidate_by_word(const std::vector<std::string> &splited_text);
+ std::optional<voice_touch_candidate_s> find_matched_candidate_by_char(const std::vector<std::string> &splited_text);
+ size_t calcualte_edit_distance(const std::string &text1, const std::string &text2);
+
+private:
+ std::vector<voice_touch_candidate_s> m_candidates;
+};
+
+#endif /* __MMI_MODULE_VOICE_TOUCH_CANDIDATES_H__ */
--- /dev/null
+
+/*
+ * 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 <string>
+
+
+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__ */
--- /dev/null
+/*
+ * 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 <mmi-error.h>
+#include <mmi-log.h>
+
+#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<voice_touch_candidate_s> &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<voice_touch_candidate_s> &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);
+ }
+}
--- /dev/null
+/*
+ * 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 <vector>
+
+#include <mmi-data.h>
+#include "mmi-module-voice-touch-common.h"
+
+class MmiDataHelper {
+public:
+ MmiDataHelper(mmi_data_h data, bool ownership = false) noexcept;
+ MmiDataHelper(const std::vector<voice_touch_candidate_s> &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<voice_touch_candidate_s> &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__ */
--- /dev/null
+/*
+ * 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 <mmi-error.h>
+#include <mmi-log.h>
+
+#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);
+}
--- /dev/null
+/*
+ * 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 <mmi-primitive-value.h>
+
+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__ */
--- /dev/null
+/*
+ * 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-log.h>
+#include <mmi-error.h>
+
+#include <algorithm>
+#include <numeric>
+
+#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_information_s> &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<voice_touch_candidate_s> 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<voice_touch_candidate_s> 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<voice_touch_candidate_s> &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<int>(m_parent_grid_area.x + (x * grid_width)),
+ .y = static_cast<int>(m_parent_grid_area.y + (y * grid_height)),
+ .w = static_cast<int>((x == col_count - 1 ? grid_width + remain_width : grid_width)),
+ .h = static_cast<int>((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<voice_touch_candidate_s> &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<voice_touch_candidate_s> &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<screen_element_s> 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<screen_element_s> 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<screen_element_s> 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<screen_element_s> 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<screen_element_s> 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;
+}
--- /dev/null
+/*
+ * 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 <vector>
+#include <string>
+#include <functional>
+#include <optional>
+
+#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_information_s> &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<voice_touch_candidate_s> make_voice_touch_candidates(voice_touch_mode_e mode);
+ std::optional<screen_element_s> 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<voice_touch_candidate_s> &candidates);
+ void fill_index_label_candidates(std::vector<voice_touch_candidate_s> &candidates);
+ void fill_text_label_candidates(std::vector<voice_touch_candidate_s> &candidates);
+
+ std::optional<screen_element_s> find_exact_element_by_object_id(const std::string &object_id);
+ std::optional<screen_element_s> 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<grid_information_s> m_grid_informations;
+ area_coordinates_s m_parent_grid_area;
+ size_t m_grid_depth;
+
+ // Current screen elements
+ std::vector<screen_element_s> m_screen_elements;
+};
+
+#endif /* __MMI_MODULE_VOICE_TOUCH_SCREEN_INFO_H__ */
*
*/
-#ifndef __MMI_CLIENT_H__
-#define __MMI_CLIENT_H__
-#include <glib.h>
-#include "mmi.h"
+#include <algorithm>
+#include <sstream>
-typedef void* mmi_rpc_h;
+#include "mmi-module-voice-touch-string-utility.h"
-typedef struct {
- mmi_rpc_h rpc_h;
- const char *stub_appid;
- int state;
- GList* result_cb_list;
-} mmi_struct_s;
-typedef mmi_struct_s* mmi_handle;
-
-typedef struct {
- int input_event_type;
- mmi_result_cb result_callback;
-} mmi_result_cb_s;
+std::string StringUtility::make_lower_case(std::string text)
+{
+ transform(text.begin(), text.end(), text.begin(), ::tolower);
+ return text;
+}
-#ifdef __cplusplus
-extern "C" {
-#endif
+std::vector<std::string> StringUtility::split_text(std::string text, char delimiter)
+{
+ std::vector<std::string> result;
+ std::istringstream ss{text};
+ std::string temp;
-int mmi_client_create(void);
-int mmi_client_destroy(void);
-int mmi_client_set_result_cb(int input_event_type, mmi_result_cb callback, void* user_data);
-mmi_handle mmi_client_get(void);
+ while (getline(ss, temp, delimiter)) {
+ result.push_back(temp);
+ }
-#ifdef __cplusplus
+ return result;
}
-#endif
-
-#endif //__MMI_CLIENT_H__
\ No newline at end of file
--- /dev/null
+/*
+ * 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 <vector>
+#include <string>
+
+class StringUtility {
+public:
+ static std::string make_lower_case(std::string text);
+ static std::vector<std::string> split_text(std::string text, char delimeter);
+};
+
+#endif /* __MMI_MODULE_VOICE_TOUCH_STRING_UTILITY_H__ */
--- /dev/null
+#include <mmi-attribute.h>
+#include <mmi-node.h>
+#include <mmi-node-processor.h>
+#include <mmi-log.h>
+
+#include <map>
+#include <memory>
+
+#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<mmi_node_instance_h, std::shared_ptr<voice_touch_helper_s>> 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<voice_touch_helper_s>();
+ 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_information_s> grid_informations;
+ for (size_t i = 2; i < count; i += 2) {
+ try {
+ grid_information_s grid_information{
+ .col_count = static_cast<size_t>(attribute_value.get_array_element(i).get_integer_value()),
+ .row_count = static_cast<size_t>(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<voice_touch_candidate_s> &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<mmi_node_instance_h> 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"
--- /dev/null
+subdir('script-parser')
+subdir('wakeupless-command')
+subdir('voice-touch')
+subdir('user-recognition')
--- /dev/null
+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,
+ ]
+
+mmi_module_script_parser_include_dirs = include_directories(
+ '.',
+ '../../../capi/',
+ )
+
+mmi_module_script_parser_library = library('mmi_module_script_parser',
+ mmi_module_script_parser_library_srcs,
+ include_directories : [ mmi_module_script_parser_include_dirs ],
+ dependencies : [mmi_module_script_parser_deps],
+ install_dir : mmi_prefix_plugindir,
+ install : true
+ )
--- /dev/null
+#include <mmi.h>
+#include <mmi-plugin-storage.h>
+#include <mmi-workflow.h>
+
+#include "mmi-log.h"
+
+#include <filesystem>
+#include <string>
+#include <vector>
+
+#include <dlog.h>
+#include <Ecore.h>
+
+extern "C" {
+
+ EXPORT_API void mmi_plugin_module_get_workflow_list()
+ {
+ const std::string plugin_module_path{"/usr/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) {
+ auto const ext = entry.path().string().substr(pos + 1);
+ if (ext == "mws") {
+ mmi_workflow_h workflow = nullptr;
+ mmi_workflow_create_from_script(entry.path().string().c_str(), &workflow);
+ mmi_standard_workflow_register(workflow);
+ mmi_workflow_destroy(workflow);
+ }
+ }
+ }
+ }
+
+} // extern "C"
--- /dev/null
+install_data('user-recognition.mws', install_dir : mmi_prefix_scriptdir)
--- /dev/null
+@workflow
+name : USER_RECOGNITION
+
+@node-list
+[Source] MIC_AMBIENT as MIC
+[Source] CAMERA as CAMERA
+[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
+FACE_RECOGNITION.MATCHED_FACES -> USER_COMPARISON.PORT1
+MIC.AUDIO -> SPEAKER_RECOGNITION.AUDIO
+SPEAKER_RECOGNITION.MATCHED_SPEAKERS -> USER_COMPARISON.PORT2
+
+@attribute-list
+
+@output-list
+USER_COMPARISON.BYPASS_RESULT as SINGLE_MODAL_USER_ID
+USER_COMPARISON.COMPARISON_RESULT as MULTI_MODAL_USER_ID
--- /dev/null
+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,
+ ]
+
+mmi_module_voice_touch_include_dirs = include_directories(
+ '.',
+ '../../../capi/',
+ )
+
+mmi_module_voice_touch_library = library('mmi_module_voice_touch',
+ mmi_module_voice_touch_library_srcs,
+ include_directories : [ mmi_module_voice_touch_include_dirs ],
+ dependencies : [mmi_module_voice_touch_deps],
+ install_dir : mmi_prefix_plugindir,
+ install : true
+ )
--- /dev/null
+#include <mmi.h>
+#include <mmi-plugin-storage.h>
+#include <mmi-workflow.h>
+
+#include "mmi-log.h"
+
+#include <string>
+#include <map>
+
+#include <dlog.h>
+#include <Ecore.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "MMI-MODULE-VOICE-TOUCH"
+
+#define ENABLE_TEMP_RESCAN
+
+extern "C" {
+
+ EXPORT_API void mmi_plugin_module_get_workflow_list()
+ {
+ const char *NODE_NAME_MIC = "MIC";
+ const char *NODE_NAME_ASR = "ASR";
+ const char *NODE_NAME_MATCH_MODE_COMMANDS = "MATCH_MODE_COMMANDS";
+ const char *NODE_NAME_MATCH_PREDEFINED_COMMANDS = "MATCH_PREDEFINED_COMMANDS";
+ const char *NODE_NAME_VOICE_TOUCH_PROCESSOR = "VOICE_TOUCH_PROCESSOR";
+ const char *NODE_NAME_SCREEN_ANALYZER = "SCREEN_ANALYZER";
+
+ mmi_workflow_h workflow = nullptr;
+ mmi_workflow_create(&workflow);
+
+ mmi_workflow_set_type(workflow, MMI_STANDARD_WORKFLOW_VOICE_TOUCH);
+
+ mmi_node_h node_mic = nullptr;
+ mmi_standard_node_create_source(MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT, &node_mic);
+ mmi_workflow_node_add(workflow, NODE_NAME_MIC, node_mic);
+
+ mmi_node_h node_asr = nullptr;
+ mmi_standard_node_create_processor(MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR, &node_asr);
+ mmi_workflow_node_add(workflow, NODE_NAME_ASR, node_asr);
+
+ mmi_node_h node_match_mode_commands = nullptr;
+ mmi_standard_node_create_logic(MMI_STANDARD_NODE_LOGIC_TYPE_FIXED_STRING_MATCH, &node_match_mode_commands);
+ mmi_workflow_node_add(workflow, NODE_NAME_MATCH_MODE_COMMANDS, node_match_mode_commands);
+
+ mmi_node_h node_match_predefined_commands = nullptr;
+ mmi_standard_node_create_logic(MMI_STANDARD_NODE_LOGIC_TYPE_FIXED_STRING_MATCH, &node_match_predefined_commands);
+ mmi_workflow_node_add(workflow, NODE_NAME_MATCH_PREDEFINED_COMMANDS, node_match_predefined_commands);
+
+ mmi_node_h node_voice_touch = nullptr;
+ mmi_standard_node_create_processor(MMI_STANDARD_NODE_PROCESSOR_TYPE_VOICE_TOUCH, &node_voice_touch);
+ mmi_workflow_node_add(workflow, NODE_NAME_VOICE_TOUCH_PROCESSOR, node_voice_touch);
+
+ mmi_node_h node_screen_analyzer = nullptr;
+ mmi_standard_node_create_source(MMI_STANDARD_NODE_SOURCE_TYPE_SCREEN_ANALYZER, &node_screen_analyzer);
+ mmi_workflow_node_add(workflow, NODE_NAME_SCREEN_ANALYZER, node_screen_analyzer);
+
+#ifdef ENABLE_TEMP_RESCAN
+ /* This is a temporary node for rescanning the screen, it will be removed when the signal mechanism is ready */
+ mmi_node_h temp_node_match_rescan_command = nullptr;
+ mmi_standard_node_create_logic(MMI_STANDARD_NODE_LOGIC_TYPE_FIXED_STRING_MATCH, &temp_node_match_rescan_command);
+ mmi_workflow_node_add(workflow, "TEMP_RESCAN", temp_node_match_rescan_command);
+#endif
+
+ mmi_workflow_link_nodes_by_names(workflow, NODE_NAME_MIC, "AUDIO", NODE_NAME_ASR, "AUDIO");
+
+ mmi_workflow_link_nodes_by_names(workflow, NODE_NAME_ASR, "FINAL_ASR", NODE_NAME_MATCH_MODE_COMMANDS, "TEXT");
+
+ 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");
+
+ mmi_workflow_link_nodes_by_names(workflow, NODE_NAME_MATCH_PREDEFINED_COMMANDS, "REJECTED", NODE_NAME_VOICE_TOUCH_PROCESSOR, "UTTERANCE");
+
+ mmi_workflow_link_nodes_by_names(workflow, NODE_NAME_SCREEN_ANALYZER, "SCREEN_INFO", NODE_NAME_VOICE_TOUCH_PROCESSOR, "SCREEN_INFO");
+
+#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
+
+ mmi_workflow_attribute_assign(workflow, "PREDEFINED_COMMANDS", NODE_NAME_MATCH_PREDEFINED_COMMANDS, "CANDIDATES");
+
+ mmi_workflow_attribute_assign(workflow, "GRID_CONFIGURATION", NODE_NAME_VOICE_TOUCH_PROCESSOR, "GRID_CONFIGURATION");
+
+#ifdef ENABLE_TEMP_RESCAN
+ /* These are temporary attributes for rescanning the screen, it will be removed when the signal mechanism is ready */
+ mmi_workflow_attribute_assign(workflow, "REFRESH", NODE_NAME_SCREEN_ANALYZER, "RESCANNING");
+ mmi_workflow_attribute_assign(workflow, "TEMP_RESCAN_COMMAND", "TEMP_RESCAN", "CANDIDATES");
+#endif
+
+ 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, "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);
+
+ mmi_attribute_h attribute = nullptr;
+ mmi_attribute_create(primitive_array, "PREDEFINED_COMMANDS", &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);
+ mmi_attribute_h temp_attribute = nullptr;
+ mmi_attribute_create(temp_rescan_command, "TEMP_RESCAN_COMMAND", &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);
+
+#ifdef ENABLE_TEMP_RESCAN
+ /* This is a temporary node for rescanning the screen, it will be removed when the signal mechanism is ready */
+ mmi_node_destroy(temp_node_match_rescan_command);
+#endif
+
+ mmi_node_destroy(node_mic);
+ mmi_node_destroy(node_asr);
+ mmi_node_destroy(node_match_mode_commands);
+ mmi_node_destroy(node_match_predefined_commands);
+ mmi_node_destroy(node_voice_touch);
+ mmi_node_destroy(node_screen_analyzer);
+
+ mmi_workflow_destroy(workflow);
+ }
+
+} // extern "C"
--- /dev/null
+@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
--- /dev/null
+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,
+ ]
+
+mmi_module_wakeupless_command_include_dirs = include_directories(
+ '.',
+ '../../../capi/',
+ )
+
+mmi_module_wakeupless_command_library = library('mmi_module_wakeupless_command',
+ mmi_module_wakeupless_command_library_srcs,
+ include_directories : [ mmi_module_wakeupless_command_include_dirs ],
+ dependencies : [mmi_module_wakeupless_command_deps],
+ install_dir : mmi_prefix_plugindir,
+ install : true
+ )
--- /dev/null
+#include <mmi.h>
+#include <mmi-plugin-storage.h>
+#include <mmi-workflow.h>
+
+#include <string>
+#include <map>
+
+#include <dlog.h>
+#include <Ecore.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#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()
+ {
+ mmi_workflow_h workflow = nullptr;
+ mmi_workflow_create(&workflow);
+
+ mmi_workflow_set_type(workflow, MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND);
+
+ mmi_node_h node_mic = nullptr;
+ /* FIXME: node should be 'found' instead of 'created' */
+ mmi_standard_node_create_source(MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT, &node_mic);
+ mmi_workflow_node_add(workflow, "MIC", node_mic);
+
+ mmi_node_h node_asr = nullptr;
+ mmi_standard_node_create_processor(MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR, &node_asr);
+ mmi_workflow_node_add(workflow, "ASR", node_asr);
+
+ mmi_node_h node_match = nullptr;
+ mmi_standard_node_create_logic(MMI_STANDARD_NODE_LOGIC_TYPE_FIXED_STRING_MATCH, &node_match);
+ mmi_workflow_node_add(workflow, "MATCH", node_match);
+
+ mmi_workflow_link_nodes_by_names(workflow, "MIC", "AUDIO", "ASR", "AUDIO");
+ mmi_workflow_link_nodes_by_names(workflow, "ASR", "FINAL_ASR", "MATCH", "TEXT");
+
+ mmi_workflow_attribute_assign(workflow, "COMMANDS", "MATCH", "CANDIDATES");
+ mmi_workflow_attribute_assign(workflow, "LANGUAGE", "ASR", "LANGUAGE");
+ mmi_workflow_attribute_assign(workflow, "STOP_METHOD", "ASR", "STOP_METHOD");
+ mmi_workflow_attribute_assign(workflow, "ASR_START", "ASR", "ASR_START");
+
+ mmi_workflow_output_assign(workflow, "COMMAND", "MATCH", "MATCHED_CANDIDATE");
+ mmi_workflow_output_assign(workflow, "UTTERANCE", "ASR", "PARTIAL_ASR");
+ mmi_workflow_output_assign(workflow, "UTTERANCE", "ASR", "FINAL_ASR");
+
+ mmi_standard_workflow_register(workflow);
+
+ mmi_node_destroy(node_mic);
+ mmi_node_destroy(node_asr);
+ mmi_node_destroy(node_match);
+
+ mmi_workflow_destroy(workflow);
+ }
+
+} // extern "C"
--- /dev/null
+/*
+ * 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 "mmi-event-observer.h"
+#include "mmi-communication-message.h"
+#include "mmi-workflow-output-event.h"
+
+#include <memory>
+
+namespace mmi {
+
+namespace communication {
+
+enum class COMMUNICATION_CHANNEL_EVENT_TYPE {
+ CONNECTED,
+ DISCONNECTED,
+ MESSAGE_RECEIVED,
+};
+
+class CommunicationChannel : public SimpleEventObservable<COMMUNICATION_CHANNEL_EVENT_TYPE> {
+public:
+ CommunicationChannel() = default;
+ virtual ~CommunicationChannel() = default;
+
+ virtual int connect() = 0;
+ virtual int disconnect() = 0;
+ virtual int send(Message *message) = 0;
+};
+
+class CommunicationChannelManager : public CommunicationChannel,
+ public SimpleEventObserver<WORKFLOW_OUTPUT_EVENT_TYPE> {
+public:
+ CommunicationChannelManager() = default;
+ virtual ~CommunicationChannelManager() = default;
+};
+
+class CommunicationChannelClient : public CommunicationChannel {
+public:
+ CommunicationChannelClient() = default;
+ virtual ~CommunicationChannelClient() = default;
+};
+
+struct CommunicationChannelManagerFactory {
+ CommunicationChannelManagerFactory() = default;
+ virtual ~CommunicationChannelManagerFactory() = default;
+
+ virtual std::shared_ptr<CommunicationChannelManager> create_channel() = 0;
+};
+
+struct CommunicationChannelClientFactory {
+ CommunicationChannelClientFactory() = default;
+ virtual ~CommunicationChannelClientFactory() = default;
+
+ virtual std::shared_ptr<CommunicationChannelClient> create_channel() = 0;
+};
+
+}; // namespace communication
+
+}; // namespace mmi
--- /dev/null
+/*
+ * 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 <list>
+#include <string>
+#include <vector>
+#include <functional>
+
+#include <bundle.h>
+
+#include "mmi.h"
+
+namespace mmi {
+
+namespace communication {
+
+enum class MESSAGE_GROUP {
+ CLIENT,
+ WORKFLOW,
+ NODE,
+};
+
+/* Client Messages */
+enum class CLIENT_MESSAGE_TYPE {
+ /* Client to Manager */
+ WORKFLOW_INSTANCE_CREATE,
+ WORKFLOW_INSTANCE_DESTROY,
+ WORKFLOW_INSTANCE_SET_ATTRIBUTE,
+ WORKFLOW_INSTANCE_ACTIVATE,
+ WORKFLOW_INSTANCE_DEACTIVATE,
+ /* Manager to Client */
+};
+
+struct Message {
+ Message(MESSAGE_GROUP group) : message_group{group} {}
+ virtual ~Message() {}
+ MESSAGE_GROUP message_group;
+ std::string sender;
+};
+
+struct ClientMessage : public Message {
+ ClientMessage(CLIENT_MESSAGE_TYPE type) : Message(MESSAGE_GROUP::CLIENT), message_type{type} {}
+ virtual ~ClientMessage() {}
+ CLIENT_MESSAGE_TYPE message_type;
+};
+
+struct ClientMessageWorkflowInstanceCreate : public ClientMessage {
+ ClientMessageWorkflowInstanceCreate() : ClientMessage{CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_CREATE} {}
+ mmi_standard_workflow_type_e workflow_type{MMI_STANDARD_WORKFLOW_NONE};
+ int local_workflow_instance_id{0};
+ void *user_data{nullptr};
+};
+
+struct ClientMessageWorkflowInstanceDestroy : public ClientMessage {
+ ClientMessageWorkflowInstanceDestroy() : ClientMessage{CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_DESTROY} {}
+ int local_workflow_instance_id{0};
+};
+
+struct ClientMessageWorkflowInstanceSetAttribute : public ClientMessage {
+ ClientMessageWorkflowInstanceSetAttribute() : ClientMessage{CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_SET_ATTRIBUTE} {}
+ int local_workflow_instance_id{0};
+ mmi_attribute_h attribute{nullptr};
+};
+
+struct ClientMessageWorkflowInstanceActivate : public ClientMessage {
+ ClientMessageWorkflowInstanceActivate() : ClientMessage{CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_ACTIVATE} {}
+ int local_workflow_instance_id{0};
+};
+
+struct ClientMessageWorkflowInstanceDeactivate : public ClientMessage {
+ ClientMessageWorkflowInstanceDeactivate() : ClientMessage{CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_DEACTIVATE} {}
+ int local_workflow_instance_id{0};
+};
+
+}; // namespace communication
+
+}; // namespace mmi
--- /dev/null
+/*
+ * 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 <algorithm>
+#include <string>
+#include <vector>
+#include <any>
+
+namespace mmi {
+
+/* SimpleEventObserver / SimpleEventObservable do not require EventSource to be specified. */
+
+template <typename EventType>
+class SimpleEventObserver {
+public:
+ SimpleEventObserver() = default;
+ virtual ~SimpleEventObserver() = default;
+
+ virtual void on_observer_event(const EventType &event, std::any data = std::any(nullptr)) = 0;
+};
+
+template <typename EventType>
+class SimpleEventObservable {
+public:
+ SimpleEventObservable() = default;
+ virtual ~SimpleEventObservable() = default;
+
+ void notify_observers(const EventType &event, std::any data = std::any(nullptr)) {
+ for (auto observer : m_observers) {
+ if (observer) {
+ observer->on_observer_event(event, data);
+ }
+ }
+ }
+ void add_observer(SimpleEventObserver<EventType> *observer) {
+ if (observer) {
+ m_observers.push_back(observer);
+ }
+ }
+ void remove_observer(SimpleEventObserver<EventType> *observer) {
+ m_observers.erase(
+ std::remove(m_observers.begin(), m_observers.end(), observer),
+ m_observers.end());
+ };
+
+private:
+ std::vector<SimpleEventObserver<EventType>*> m_observers;
+};
+
+/* EventObserver / EventObservable require EventSource to be specified.
+ * This is useful when you want to know which object triggered the event. */
+
+template <typename ObservableType, typename EventType>
+class EventObserver {
+public:
+ EventObserver() = default;
+ virtual ~EventObserver() = default;
+
+ virtual void on_observer_event(const ObservableType &source, const EventType &event, std::any data = std::any(nullptr)) = 0;
+};
+
+template <typename ObservableType, typename EventType>
+class EventObservable {
+public:
+ EventObservable() = default;
+ virtual ~EventObservable() = default;
+
+ void notify_observers(const ObservableType &source, const EventType &event, std::any data = std::any(nullptr)) {
+ for (auto observer : m_observers) {
+ if (observer) {
+ observer->on_observer_event(source, event, data);
+ }
+ }
+ }
+ void add_observer(EventObserver<ObservableType, EventType> *observer) {
+ if (observer) {
+ m_observers.push_back(observer);
+ }
+ }
+ void remove_observer(EventObserver<ObservableType, EventType> *observer) {
+ m_observers.erase(
+ std::remove(m_observers.begin(), m_observers.end(), observer),
+ m_observers.end());
+ };
+
+private:
+ std::vector<EventObserver<ObservableType, EventType>*> m_observers;
+};
+
+}
--- /dev/null
+/*
+ * 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 "mmi-event-observer.h"
+#include "mmi-node.h"
+#include "mmi-port.h"
+
+#include <memory>
+
+namespace mmi {
+
+enum class PLUGIN_MODULE_EVENT_TYPE {
+ OUTPUT_GENERATED,
+ SWITCH_EVENT_EMITTED,
+};
+
+struct PluginModuleEvent {
+ PluginModuleEvent(PLUGIN_MODULE_EVENT_TYPE type) : type(type) {}
+ virtual ~PluginModuleEvent() = default;
+
+ PLUGIN_MODULE_EVENT_TYPE type;
+};
+
+struct PluginModuleEventOutputGenerated : public PluginModuleEvent {
+ PluginModuleEventOutputGenerated() : PluginModuleEvent(PLUGIN_MODULE_EVENT_TYPE::OUTPUT_GENERATED) {}
+ virtual ~PluginModuleEventOutputGenerated() {}
+
+ mmi_port_instance_h port_instance{nullptr};
+ mmi_data_h data{nullptr};
+};
+
+struct PluginModuleEventSwitchEventEmitted : public PluginModuleEvent {
+ PluginModuleEventSwitchEventEmitted() : PluginModuleEvent(PLUGIN_MODULE_EVENT_TYPE::SWITCH_EVENT_EMITTED) {}
+ virtual ~PluginModuleEventSwitchEventEmitted() {}
+
+ mmi_node_instance_h node_instance{nullptr};
+ std::string controllee;
+ bool state{false};
+};
+
+}; // namespace mmi
--- /dev/null
+/*
+ * 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 "mmi-event-observer.h"
+
+namespace mmi {
+
+enum class WORKFLOW_EVENT_TYPE {
+ WORKFLOW_CREATED,
+};
+
+struct WorkflowEvent {
+ WorkflowEvent(WORKFLOW_EVENT_TYPE type) : type(type) {}
+ virtual ~WorkflowEvent() = default;
+
+ WORKFLOW_EVENT_TYPE type;
+};
+
+struct WorkflowEventWorkflowCreated : public WorkflowEvent {
+ WorkflowEventWorkflowCreated() : WorkflowEvent(WORKFLOW_EVENT_TYPE::WORKFLOW_CREATED) {}
+ virtual ~WorkflowEventWorkflowCreated() {}
+
+ std::any workflow_instance{nullptr};
+};
+
+}; // namespace mmi
--- /dev/null
+/*
+ * 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 "mmi-event-observer.h"
+
+#include <memory>
+#include <bundle.h>
+
+namespace mmi {
+
+enum class WORKFLOW_OUTPUT_EVENT_TYPE {
+ OUTPUT_GENERATED,
+};
+
+struct WorkflowOutputEvent {
+ WorkflowOutputEvent(WORKFLOW_OUTPUT_EVENT_TYPE type) : type(type) {}
+ virtual ~WorkflowOutputEvent() = default;
+
+ WORKFLOW_OUTPUT_EVENT_TYPE type;
+};
+
+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};
+};
+
+}; // namespace mmi
-mmi_srcs = [
- 'mmi.h',
- 'mmi.c',
- 'mmi-ipc.h',
- 'mmi-ipc.c',
- 'mmi-dbg.h',
- 'mmi_proxy.h',
- 'mmi_proxy.c',
- 'mmi-client.h',
- 'mmi-client.c',
- ]
-
-install_headers(
- 'mmi.h',
- )
-
-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')
-
-mmi_deps = [
- ecore_dep,
- glib_dep,
- gio_dep,
- bundle_dep,
- dlog_dep,
- rpc_port_dep,
- libtzplatform_config_dep]
-
-mmi_include_dirs = include_directories(
- '.'
- )
-
-mmi_lib = shared_library(
- 'mmi',
- mmi_srcs,
- dependencies : [mmi_deps],
- include_directories : [mmi_include_dirs],
- version : meson.project_version(),
- install : true
- )
-
-pkgconfig.generate(
- filebase : 'mmi',
- name : 'mmi',
- description : 'Multi-modal Interaction Framework Library',
- version : meson.project_version(),
- libraries : mmi_lib
- )
-
-mmi_declared_dep = declare_dependency(
- link_with : mmi_lib,
- dependencies : [mmi_deps],
- include_directories : [mmi_include_dirs]
- )
+subdir('mmi')
+subdir('mmi-manager')
+subdir('mmi-cli')
--- /dev/null
+#include "cli/cli.h"
+
+#include <string>
+#include <iostream>
+#include <stdexcept> // std::invalid_argument
+
+#include <Ecore.h>
+
+namespace cli
+{
+
+class CliEcoreSession : public CliSession
+{
+public:
+ /// @throw std::invalid_argument if @c _in or @c out are invalid streams
+ explicit CliEcoreSession(Cli& _cli, std::istream& _in=std::cin, std::ostream& _out=std::cout) :
+ CliSession(_cli, _out, 1),
+ exit(false),
+ loop(false),
+ in(_in),
+ handler(nullptr)
+ {
+ if (!_in.good()) throw std::invalid_argument("istream invalid");
+ if (!_out.good()) throw std::invalid_argument("ostream invalid");
+ ExitAction(
+ [this](std::ostream&) noexcept
+ {
+ exit = true;
+ ecore_main_loop_quit();
+ }
+ );
+ }
+ std::istream& GetInputStream() {
+ return in;
+ }
+ static Eina_Bool Handler(void *data, int type, void *event)
+ {
+ CliEcoreSession* session = static_cast<CliEcoreSession*>(data);
+ if (session->exit) return ECORE_CALLBACK_CANCEL;
+
+ if (type == ECORE_EVENT_SIGNAL_EXIT)
+ {
+ session->Prompt();
+
+ std::string line;
+ std::istream& in = session->GetInputStream();
+ if (!in.good())
+ session->Exit();
+ std::getline(in, line);
+ if (in.eof())
+ session->Exit();
+ else
+ session->Feed(line);
+ }
+
+ return ECORE_CALLBACK_RENEW;
+ }
+ void Start()
+ {
+ Enter();
+
+ ecore_init();
+
+ handler = ecore_event_handler_add(
+ ECORE_EVENT_SIGNAL_EXIT, Handler, this);
+
+ while(!exit && !loop) {
+ Prompt();
+
+ std::string line;
+ if (!in.good())
+ Exit();
+ std::getline(in, line);
+ if (in.eof())
+ Exit();
+ else
+ Feed(line);
+ }
+ }
+ void Loop()
+ {
+ if (loop) {
+ std::cout << "Already looping" << std::endl;
+ return;
+ }
+
+ std::cout << "Running ecore main loop, please press <Ctrl+C> to enter commands" << std::endl;
+
+ loop = true;
+ ecore_main_loop_begin();
+ }
+ void Finish()
+ {
+ if (handler) ecore_event_handler_del(handler);
+
+ ecore_shutdown();
+ }
+
+private:
+ bool exit;
+ bool loop;
+ std::istream& in;
+ Ecore_Event_Handler *handler;
+};
+
+} // namespace cli
--- /dev/null
+dlog_dep = dependency('dlog', method : 'pkg-config')
+ecore_dep = dependency('ecore', method : 'pkg-config')
+rpc_port_dep = dependency('rpc-port')
+
+mmi_cli_deps = [
+ mmi_declared_dep,
+ dlog_dep,
+ ecore_dep,
+ rpc_port_dep,
+ ]
+
+mmi_cli_include_dirs = include_directories(
+ '.',
+ '../common/',
+ '../../capi/',
+ '../../external/',
+ )
+
+mmi_cli_declared_dep = declare_dependency(
+ dependencies : [mmi_cli_deps],
+ include_directories : [mmi_cli_include_dirs]
+ )
+
+mmi_cli_program_srcs = [
+ 'mmi-cli.cpp'
+ ]
+
+mmi_cli_program_deps = [
+ mmi_cli_declared_dep
+ ]
+
+executable('mmi-cli',
+ mmi_cli_program_srcs,
+ include_directories : [ mmi_cli_include_dirs ],
+ dependencies : [mmi_cli_program_deps],
+ install_dir : mmi_prefix_bindir,
+ install : true,
+ pie : true
+ )
+
+mmi_cli_node_tester_program_srcs = [
+ 'mmi-cli-node-tester.cpp'
+ ]
+
+mmi_cli_node_tester_program_deps = [
+ mmi_cli_declared_dep
+ ]
+
+executable('mmi-cli-node-tester',
+ mmi_cli_node_tester_program_srcs,
+ include_directories : [ mmi_cli_include_dirs ],
+ dependencies : [mmi_cli_program_deps],
+ install_dir : mmi_prefix_bindir,
+ install : true,
+ pie : true
+ )
--- /dev/null
+#include <iostream>
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include <dlfcn.h>
+
+#include "cliecoresession.h"
+
+#include "cli/cli.h"
+
+#include "mmi.h"
+#include "mmi-plugin-module.h"
+#include "mmi-plugin-storage.h"
+
+#define MMI_CLI_LOG_(fmt, arg...) \
+ ({ do { \
+ printf("%s(%d) > " fmt "\n", __func__, __LINE__, ##arg); \
+ } while (0); })
+
+#define _D(fmt, args...) MMI_CLI_LOG_(fmt, ##args)
+#define _I(fmt, args...) MMI_CLI_LOG_(fmt, ##args)
+#define _W(fmt, args...) MMI_CLI_LOG_(fmt, ##args)
+#define _E(fmt, args...) MMI_CLI_LOG_(fmt, ##args)
+
+class Program;
+
+struct PortInstance
+{
+ std::string m_name;
+ mmi_port_type_e m_port_type;
+ mmi_data_type_e m_data_type;
+ mmi_port_callbacks m_callbacks{nullptr,};
+};
+
+struct NodeInstance
+{
+ mmi_standard_node_type_e m_node_type;
+
+ mmi_node_callbacks m_callbacks{nullptr,};
+
+ std::vector<PortInstance*> m_ports;
+};
+
+enum class AttributeTestType {
+ Int,
+ Text,
+ Bool,
+ TextArray,
+
+ MaxCount,
+};
+
+typedef struct {
+ std::string name;
+ AttributeTestType type;
+ std::string description;
+ std::function<void(Program*, mmi_attribute_h*)> attribute_generator;
+} AttributeTestEntry;
+
+enum class DataTestType {
+ Int,
+ Text,
+ Bool,
+ TextArray,
+ ScreenInfo,
+ UserRecognition,
+ Audio,
+ Video,
+
+ MaxCount,
+};
+
+typedef struct {
+ std::string name;
+ DataTestType type;
+ std::string description;
+ std::function<void(Program*, PortInstance*)> data_generator;
+} DataTestEntry;
+
+class Program
+{
+public:
+ Program();
+ ~Program();
+
+ static void log_mmi_data(PortInstance *port_instance, mmi_data_h data);
+ static void port_instance_output_handler(mmi_port_instance_h port, mmi_data_h data, void *user_data);
+ void load_module(std::string path);
+ void unload_module();
+ std::string read_string_value(std::string prompt);
+ int read_int_value(std::string prompt);
+ void create_node_instance();
+ NodeInstance* get_node_instance();
+ void destroy_node_instance();
+ void activate_node_instance();
+ void deactivate_node_instance();
+ void set_attribute(AttributeTestType type);
+ void push_data(DataTestType type);
+ void set_ecore_session(cli::CliEcoreSession *session);
+
+private:
+ cli::CliEcoreSession *m_session{nullptr};
+ void* m_handle{nullptr};
+ mmi_plugin_module_node_list_s m_node_list;
+
+ std::map<int, NodeInstance*> m_node_instance_map;
+ int m_node_instance_index{0};
+};
+
+static Program g_program;
+
+AttributeTestEntry g_attribute_test_entries[] = {
+ {"int", AttributeTestType::Int, "Set an integer attribute",
+ [](Program *program, mmi_attribute_h *attribute) {
+ if (!program || !attribute) {
+ return;
+ }
+ std::string name = program->read_string_value("Enter attribute name: ");
+ std::string input = program->read_string_value("Enter attribute value: ");
+ int value = 0;
+ try {
+ value = std::stoi(input);
+ } catch (std::invalid_argument& e) {
+ _E("Invalid argument: %s", e.what());
+ return;
+ } catch (std::out_of_range& e) {
+ _E("Out of range: %s", e.what());
+ return;
+ }
+ mmi_primitive_value_h primitive_value = nullptr;
+
+ mmi_primitive_value_create_int(value, &primitive_value);
+ mmi_attribute_create(primitive_value, name.c_str(), attribute);
+
+ mmi_primitive_value_destroy(primitive_value);
+ }
+ },
+ {"text", AttributeTestType::Text, "Set a text attribute",
+ [](Program *program, mmi_attribute_h *attribute) {
+ if (!program || !attribute) {
+ return;
+ }
+ std::string name = program->read_string_value("Enter attribute name: ");
+ std::string value = program->read_string_value("Enter attribute value: ");
+ mmi_primitive_value_h primitive_value = nullptr;
+
+ mmi_primitive_value_create_string(value.c_str(), &primitive_value);
+ mmi_attribute_create(primitive_value, name.c_str(), attribute);
+
+ mmi_primitive_value_destroy(primitive_value);
+ }
+ },
+ {"bool", AttributeTestType::Bool, "Set a boolean attribute",
+ [](Program *program, mmi_attribute_h *attribute) {
+ if (!program || !attribute) {
+ return;
+ }
+ std::string name = program->read_string_value("Enter attribute name: ");
+ std::string input = program->read_string_value("Enter attribute value: ");
+ int value = 0;
+ try {
+ value = std::stoi(input);
+ } catch (std::invalid_argument& e) {
+ _E("Invalid argument: %s", e.what());
+ return;
+ } catch (std::out_of_range& e) {
+ _E("Out of range: %s", e.what());
+ return;
+ }
+ mmi_primitive_value_h primitive_value = nullptr;
+
+ mmi_primitive_value_create_bool((value != 0), &primitive_value);
+ mmi_attribute_create(primitive_value, name.c_str(), attribute);
+
+ mmi_primitive_value_destroy(primitive_value);
+ }
+ },
+ {"text_array", AttributeTestType::TextArray, "Set a text array attribute",
+ [](Program *program, mmi_attribute_h *attribute) {
+ if (!program || !attribute) {
+ return;
+ }
+ std::string name = program->read_string_value("Enter attribute name: ");
+ /* Currently we only support predefined array with string type */
+ constexpr size_t COMMAND_NUM = 2;
+ const char *commands[] = {"Open", "Close"};
+ mmi_attribute_create_string_array(name.c_str(), commands, COMMAND_NUM, attribute);
+ }
+ },
+};
+
+DataTestEntry g_data_test_entries[] = {
+ {"int", DataTestType::Int, "Push an integer data",
+ [](Program *program, PortInstance *port_instance) {
+ if (!program || !port_instance) {
+ return;
+ }
+ mmi_data_h data = nullptr;
+ int value = program->read_int_value("Enter data value: ");
+ mmi_data_create_int(value, &data);
+ if (data) {
+ port_instance->m_callbacks.input_data_received_cb(static_cast<mmi_port_instance_h>(port_instance), data);
+ mmi_data_destroy(data);
+ }
+ }
+ },
+ {"text", DataTestType::Text, "Push a text data",
+ [](Program *program, PortInstance *port_instance) {
+ if (!program || !port_instance) {
+ return;
+ }
+ mmi_data_h data = nullptr;
+ std::string value = program->read_string_value("Enter data value: ");
+ mmi_data_create_text(value.c_str(), &data);
+ if (data) {
+ port_instance->m_callbacks.input_data_received_cb(static_cast<mmi_port_instance_h>(port_instance), data);
+ mmi_data_destroy(data);
+ }
+ }
+ },
+ {"screen_info", DataTestType::ScreenInfo, "Push a screen info data",
+ [](Program *program, PortInstance *port_instance) {
+ if (!program || !port_instance) {
+ return;
+ }
+ mmi_data_h data = nullptr;
+ /* Currently we only support predefined screen info */
+ mmi_data_create_array(&data);
+ for (size_t loop = 0;loop < 5;loop++) {
+ mmi_data_h struct_data;
+ mmi_data_create_struct(&struct_data);
+
+ mmi_data_h coord_x;
+ mmi_data_create_int(10 * loop, &coord_x);
+ mmi_data_set_struct_element(struct_data, "coord_x", coord_x);
+
+ mmi_data_h coord_y;
+ mmi_data_create_int(10 * loop, &coord_y);
+ mmi_data_set_struct_element(struct_data, "coord_y", coord_y);
+
+ mmi_data_h width;
+ mmi_data_create_int(100, &width);
+ mmi_data_set_struct_element(struct_data, "width", width);
+
+ mmi_data_h height;
+ mmi_data_create_int(100, &height);
+ mmi_data_set_struct_element(struct_data, "height", height);
+
+ mmi_data_h object_id;
+ mmi_data_create_text(
+ (std::string("id_") + std::to_string(loop)).c_str(), &object_id);
+ mmi_data_set_struct_element(struct_data, "object_id", object_id);
+
+ mmi_data_h label;
+ mmi_data_create_text(
+ (std::string("label") + std::to_string(loop)).c_str(), &label);
+ mmi_data_set_struct_element(struct_data, "label", label);
+
+ mmi_data_h role;
+ mmi_data_create_text(
+ (std::string("role") + std::to_string(loop)).c_str(), &role);
+ mmi_data_set_struct_element(struct_data, "role", role);
+
+ mmi_data_add_array_element(data, struct_data);
+ }
+ if (data) {
+ port_instance->m_callbacks.input_data_received_cb(static_cast<mmi_port_instance_h>(port_instance), data);
+ mmi_data_destroy(data);
+ }
+ }
+ },
+ {"user_recognition", DataTestType::UserRecognition, "Push a user recognition info data",
+ [](Program *program, PortInstance *port_instance) {
+ if (!program || !port_instance) {
+ return;
+ }
+ mmi_data_h data = nullptr;
+ mmi_data_create_struct(&data);
+
+ std::string value = program->read_string_value("Enter fromNode name: ");
+ mmi_data_h from_node = nullptr;
+ mmi_data_create_text(value.c_str(), &from_node);
+ mmi_data_set_struct_element(data, "fromNode", from_node);
+
+ /* Currently we only support predefined user recognition info */
+ mmi_data_h candidates = nullptr;
+ mmi_data_create_array(&candidates);
+ for (size_t loop = 0;loop < 2;loop++) {
+ mmi_data_h struct_data;
+ mmi_data_create_struct(&struct_data);
+
+ mmi_data_h user_id;
+ mmi_data_create_text(
+ (std::string("user") + std::to_string(loop)).c_str(), &user_id);
+ mmi_data_set_struct_element(struct_data, "id", user_id);
+
+ mmi_data_h user_name;
+ mmi_data_create_text(
+ (std::string("name") + std::to_string(loop)).c_str(), &user_name);
+ mmi_data_set_struct_element(struct_data, "name", user_name);
+
+ mmi_data_h score;
+ mmi_data_create_float(91.5f + loop, &score);
+ mmi_data_set_struct_element(struct_data, "confidence", score);
+
+ mmi_data_add_array_element(candidates, struct_data);
+ }
+ mmi_data_set_struct_element(data, "recognizedCandidates", candidates);
+
+ if (data) {
+ port_instance->m_callbacks.input_data_received_cb(static_cast<mmi_port_instance_h>(port_instance), data);
+ mmi_data_destroy(data);
+ }
+ }
+ },
+ {"audio", DataTestType::Audio, "Push audio data from file",
+ [](Program *program, PortInstance *port_instance) {
+ if (!program || !port_instance) {
+ return;
+ }
+ std::string value = program->read_string_value("Enter audio file path : ");
+ const size_t read_size = 640;
+ char frame_buf[read_size];
+ FILE *fp = fopen(value.c_str(), "rb");
+ if (fp) {
+ size_t size = 0;
+ while ((size = fread(frame_buf, sizeof(char), read_size, fp)) > 0) {
+ mmi_data_h data = nullptr;
+ mmi_data_create_audio(frame_buf, size, &data);
+ if (data) {
+ port_instance->m_callbacks.input_data_received_cb(static_cast<mmi_port_instance_h>(port_instance), data);
+ mmi_data_destroy(data);
+ }
+ }
+ fclose(fp);
+ } else {
+ _E("Failed to open file %s", value.c_str());
+ }
+ }
+ },
+ {"video", DataTestType::Video, "Push video data from file",
+ [](Program *program, PortInstance *port_instance) {
+ if (!program || !port_instance) {
+ return;
+ }
+ std::string value = program->read_string_value("Enter video file path : ");
+ const size_t read_size = 921600; // 640*480*3
+ char frame_buf[read_size];
+ FILE *fp = fopen(value.c_str(), "rb");
+ if (fp) {
+ size_t size;
+ while ((size = fread(frame_buf, sizeof(char), read_size, fp)) > 0) {
+ mmi_data_h data = nullptr;
+ mmi_data_create_video(frame_buf, size, &data);
+ if (data) {
+ port_instance->m_callbacks.input_data_received_cb(static_cast<mmi_port_instance_h>(port_instance), data);
+ mmi_data_destroy(data);
+ }
+ }
+ fclose(fp);
+ } else {
+ _E("Failed to open file %s", value.c_str());
+ }
+ }
+ },
+};
+
+Program::Program() {
+ memset(&m_node_list, 0, sizeof(mmi_plugin_module_node_list_s));
+}
+Program::~Program() {
+ unload_module();
+}
+
+void Program::log_mmi_data(PortInstance *port_instance, mmi_data_h data) {
+ mmi_data_type_e type;
+ mmi_data_get_type(data, &type);
+ switch(type) {
+ case MMI_DATA_TYPE_BOOLEAN:
+ {
+ bool value;
+ mmi_data_get_bool(data, &value);
+ _D("Port %s generated data type %d (BOOLEAN), value %d", port_instance->m_name.c_str(), type, value);
+ }
+ break;
+ case MMI_DATA_TYPE_INTEGER:
+ {
+ int value;
+ mmi_data_get_int(data, &value);
+ _D("Port %s generated data type %d (INTEGER), value %d", port_instance->m_name.c_str(), type, value);
+ }
+ break;
+ case MMI_DATA_TYPE_FLOAT:
+ {
+ float value;
+ mmi_data_get_float(data, &value);
+ _D("Port %s generated data type %d (FLOAT), value %f", port_instance->m_name.c_str(), type, value);
+ }
+ break;
+ case MMI_DATA_TYPE_TEXT:
+ {
+ const char *value = nullptr;
+ mmi_data_get_text(data, &value);
+ _D("Port %s generated data type %d (TEXT), value %s", port_instance->m_name.c_str(), type, value);
+ }
+ break;
+ case MMI_DATA_TYPE_USER_IDENTIFICATION:
+ {
+ const void *ptr = nullptr;
+ size_t len = 0;
+ mmi_data_get_user_identification(data, &ptr, &len);
+ std::string hex_string;
+ for (size_t i = 0; i < len; i++) {
+ char buf[3] = {0, };
+ snprintf(buf, sizeof(buf), "%02x", ((unsigned char*)ptr)[i]);
+ hex_string += buf;
+ }
+ _D("Port %s generated data type %d (USER_IDENTIFICATION), size %zu, hex %s",
+ port_instance->m_name.c_str(), type, len, hex_string.c_str());
+ }
+ break;
+ case MMI_DATA_TYPE_ARRAY:
+ {
+ size_t count = 0;
+ mmi_data_get_array_count(data, &count);
+
+ for (size_t i = 0; i < count; i++) {
+ mmi_data_h element = nullptr;
+ mmi_data_get_array_element(data, i, &element);
+ _D("Array Element %zu", i);
+ log_mmi_data(port_instance, element);
+ }
+ }
+ break;
+ case MMI_DATA_TYPE_STRUCT:
+ {
+ size_t count;
+ mmi_data_get_struct_count(data, &count);
+
+ for (size_t i = 0; i < count; i++) {
+ const char *element_name = nullptr;
+ mmi_data_get_struct_element_name(data, i, &element_name);
+ _D("Struct Element %zu : %s", i, element_name);
+ mmi_data_h element_value = nullptr;
+ mmi_data_get_struct_element_value(data, i, &element_value);
+ log_mmi_data(port_instance, element_value);
+ }
+ }
+ break;
+ default:
+ _D("Port %s generated data type %d", port_instance->m_name.c_str(), type);
+ break;
+ }
+}
+
+void Program::port_instance_output_handler(mmi_port_instance_h port, mmi_data_h data, void *user_data) {
+ if (port == nullptr || data == nullptr) {
+ _E("Invalid parameter : port(%p), data(%p)", port, data);
+ return;
+ }
+
+ PortInstance *port_instance = static_cast<PortInstance*>(port);
+ log_mmi_data(port_instance, data);
+}
+
+void Program::load_module(std::string path) {
+ mmi_plugin_module_event_handler_info_s module_event_handler_info{nullptr, };
+ module_event_handler_info.port_instance_output_handler = port_instance_output_handler;
+
+ mmi_plugin_storage_set_plugin_module_event_handler(module_event_handler_info, nullptr);
+
+ m_handle = dlopen(path.c_str(), RTLD_NOW);
+ if (!m_handle) {
+ _E("Failed to load plugin module: %s", dlerror());
+ return;
+ }
+
+ mmi_plugin_storage_set_current_module_identifier(path.c_str());
+ auto prepare_node_list = reinterpret_cast<mmi_plugin_module_get_node_list_func>(
+ dlsym(m_handle, MMI_PLUGIN_MODULE_GET_NODE_LIST_FUNC_NAME));
+ if (!prepare_node_list) {
+ _E("Failed to find symbol: %s", dlerror());
+ return;
+ }
+
+ prepare_node_list();
+
+ m_node_list = mmi_plugin_storage_get_node_list(path.c_str());
+
+ /* Dump node_list */
+ _D("node_list.count: %zu", m_node_list.node_count);
+ for (size_t i = 0;i < m_node_list.node_count;i++) {
+ mmi_node_h node = m_node_list.nodes[i];
+ mmi_standard_node_type_e type;
+ mmi_node_get_type(node, &type);
+ mmi_node_callbacks callbacks;
+ mmi_node_get_callbacks(node, &callbacks);
+ size_t port_count;
+ _D("node_info[%zu].type: %d", i, type);
+ _D("node_info[%zu].callbacks : %p %p %p %p %p %p", i,
+ callbacks.initialized_cb,
+ callbacks.deinitialized_cb,
+ callbacks.attribute_set_cb,
+ callbacks.activated_cb,
+ callbacks.deactivated_cb,
+ callbacks.signal_received_cb);
+ mmi_node_get_port_count(node, &port_count);
+ _D("node_info[%zu].port_list.count: %zu", i, port_count);
+ for (size_t j = 0;j < port_count;j++) {
+ mmi_port_h port;
+ mmi_node_get_port(node, j, &port);
+ char *name = nullptr;
+ size_t length = 0;
+ mmi_port_get_name(port, &name, &length);
+ mmi_port_type_e port_type;
+ mmi_port_get_type(port, &port_type);
+ mmi_data_type_e data_type;
+ mmi_port_get_data_type(port, &data_type);
+ mmi_port_callbacks port_callbacks;
+ mmi_port_get_callbacks(port, &port_callbacks);
+ _D("node_info[%zu].port_info[%zu].name: %s", i, j, name);
+ _D("node_info[%zu].port_info[%zu].type: %d", i, j, port_type);
+ _D("node_info[%zu].port_info[%zu].data_type: %d", i, j, data_type);
+ _D("node_info[%zu].port_info[%zu].callbacks: %p %p", i, j,
+ port_callbacks.output_format_requested_cb,
+ port_callbacks.input_data_received_cb);
+ }
+ }
+}
+
+void Program::unload_module() {
+ if (m_handle) dlclose(m_handle);
+ m_handle = nullptr;
+}
+
+std::string Program::read_string_value(std::string prompt) {
+ if (!m_session) {
+ _E("Session is not created");
+ return "";
+ }
+ std::cout << prompt;
+ std::string value;
+ std::getline(m_session->GetInputStream(), value);
+ return value;
+}
+
+int Program::read_int_value(std::string prompt) {
+ int value = -1;
+ std::string string_value = read_string_value(prompt);
+ try {
+ value = std::stoi(string_value);
+ } catch (std::invalid_argument& e) {
+ _E("Invalid argument: %s", e.what());
+ return -1;
+ } catch (std::out_of_range& e) {
+ _E("Out of range: %s", e.what());
+ return -1;
+ }
+ return value;
+}
+
+void Program::create_node_instance() {
+ NodeInstance *node_instance = new NodeInstance();
+
+ /* Currently only one node is supported */
+ mmi_node_h node = m_node_list.nodes[0];
+ mmi_standard_node_type_e type;
+ mmi_node_get_type(node, &type);
+ mmi_node_callbacks callbacks;
+ mmi_node_get_callbacks(node, &callbacks);
+
+ node_instance->m_node_type = type;
+ node_instance->m_callbacks = callbacks;
+
+ mmi_plugin_module_node_instance_info_s node_instance_info;
+ node_instance_info.node = static_cast<mmi_node_instance_h>(node_instance);
+ node_instance_info.port_info_count = 0;
+
+ size_t port_count;
+ mmi_node_get_port_count(node, &port_count);
+ for (size_t j = 0;j < port_count;j++) {
+ mmi_port_h port;
+ mmi_node_get_port(node, j, &port);
+ char *name = nullptr;
+ size_t length = 0;
+ mmi_port_get_name(port, &name, &length);
+ mmi_port_type_e port_type;
+ mmi_port_get_type(port, &port_type);
+ mmi_data_type_e data_type;
+ mmi_port_get_data_type(port, &data_type);
+ mmi_port_callbacks port_callbacks;
+ mmi_port_get_callbacks(port, &port_callbacks);
+
+ PortInstance *port_instance = new PortInstance();
+ port_instance->m_name = name;
+ port_instance->m_port_type = port_type;
+ port_instance->m_data_type = data_type;
+ port_instance->m_callbacks = port_callbacks;
+
+ node_instance->m_ports.push_back(port_instance);
+
+ node_instance_info.port_infos[node_instance_info.port_info_count].port =
+ static_cast<mmi_port_instance_h>(port_instance);
+ snprintf(node_instance_info.port_infos[node_instance_info.port_info_count].name, MMI_NAME_MAX_LENGTH, "%s", name);
+
+ node_instance_info.port_info_count++;
+ }
+
+ mmi_plugin_storage_add_node_instance_info(&node_instance_info);
+
+ m_node_instance_map[m_node_instance_index] = node_instance;
+ node_instance->m_callbacks.initialized_cb(static_cast<mmi_node_instance_h>(node_instance));
+
+ _D("Created node instance: %zu", m_node_instance_index);
+
+ m_node_instance_index++;
+}
+
+NodeInstance* Program::get_node_instance() {
+ NodeInstance *node_instance = nullptr;
+ if (m_node_instance_map.size() == 1) {
+ node_instance = m_node_instance_map.begin()->second;
+ } else {
+ int index = read_int_value("Enter instance id: ");
+ auto it = m_node_instance_map.find(index);
+ if (it == m_node_instance_map.end()) {
+ _E("Failed to find node instance: %d", index);
+ return nullptr;
+ }
+ node_instance = it->second;
+ }
+ return node_instance;
+}
+
+void Program::destroy_node_instance() {
+ NodeInstance *node_instance = get_node_instance();
+ if (!node_instance) return;
+
+ node_instance->m_callbacks.deinitialized_cb(static_cast<mmi_node_instance_h>(node_instance));
+ mmi_plugin_storage_remove_node_instance_info(static_cast<mmi_node_instance_h>(node_instance));
+ for (auto port_instance : node_instance->m_ports) {
+ delete port_instance;
+ }
+ delete node_instance;
+
+ /* Erase node_instance from map */
+ for (auto it = m_node_instance_map.begin();it != m_node_instance_map.end();it++) {
+ if (it->second == node_instance) {
+ m_node_instance_map.erase(it);
+ break;
+ }
+ }
+}
+
+void Program::activate_node_instance() {
+ NodeInstance *node_instance = get_node_instance();
+ if (!node_instance) return;
+
+ node_instance->m_callbacks.activated_cb(static_cast<mmi_node_instance_h>(node_instance));
+}
+
+void Program::deactivate_node_instance() {
+ NodeInstance *node_instance = get_node_instance();
+ if (!node_instance) return;
+
+ node_instance->m_callbacks.deactivated_cb(static_cast<mmi_node_instance_h>(node_instance));
+}
+
+void Program::set_attribute(AttributeTestType type) {
+ NodeInstance *node_instance = get_node_instance();
+ if (!node_instance) return;
+
+ mmi_attribute_h attribute = nullptr;
+
+ if (type >= AttributeTestType::MaxCount) {
+ _E("Invalid attribute type");
+ return;
+ }
+
+ size_t entry_index = static_cast<size_t>(AttributeTestType::MaxCount);
+ for (size_t i = 0;i < sizeof(g_attribute_test_entries) / sizeof(g_attribute_test_entries[0]);i++) {
+ if (g_attribute_test_entries[i].type == type) {
+ entry_index = i;
+ break;
+ }
+ }
+ if (entry_index == static_cast<size_t>(AttributeTestType::MaxCount)) {
+ _E("Failed to find attribute type: %d", type);
+ return;
+ }
+ g_attribute_test_entries[entry_index].attribute_generator(this, &attribute);
+
+ node_instance->m_callbacks.attribute_set_cb(static_cast<mmi_node_instance_h>(node_instance), attribute);
+ mmi_attribute_destroy(attribute);
+}
+
+void Program::push_data(DataTestType type) {
+ NodeInstance *node_instance = get_node_instance();
+ if (!node_instance) return;
+
+ if (type >= DataTestType::MaxCount) {
+ _E("Invalid data type");
+ return;
+ }
+
+ std::string name = read_string_value("Enter port name: ");
+ for (auto port_instance : node_instance->m_ports) {
+ if (port_instance->m_name == name) {
+ mmi_data_h data = nullptr;
+
+ size_t entry_index = static_cast<size_t>(DataTestType::MaxCount);
+ for (size_t i = 0;i < sizeof(g_data_test_entries) / sizeof(g_data_test_entries[0]);i++) {
+ if (g_data_test_entries[i].type == type) {
+ entry_index = i;
+ break;
+ }
+ }
+ if (entry_index == static_cast<size_t>(DataTestType::MaxCount)) {
+ _E("Failed to find data type");
+ return;
+ }
+ g_data_test_entries[entry_index].data_generator(this, port_instance);
+
+ break;
+ }
+ }
+}
+
+void Program::set_ecore_session(cli::CliEcoreSession *session) {
+ m_session = session;
+}
+
+int main(int argc, char **argv)
+{
+ if (argc < 2) {
+ std::cout << "Usage: " << argv[0] << " <plugin module path>" << std::endl;
+ return 0;
+ }
+ std::string path = argv[1];
+ try {
+ cli::SetColor();
+
+ cli::CliEcoreSession *ref = nullptr;
+ auto rootMenu = std::make_unique<cli::Menu>( "tester" );
+
+ rootMenu->Insert("loop", [&ref](std::ostream& out) {
+ if (ref) {
+ ref->Loop();
+ }
+ },
+ "Start ecore main loop");
+
+ rootMenu->Insert("load", [path](std::ostream& out) {
+ g_program.load_module(path);
+ },
+ "Load the node module that needs to be tested");
+
+ rootMenu->Insert("unload", [](std::ostream& out) {
+ g_program.unload_module();
+ },
+ "Unload the currently loaded node module");
+
+ rootMenu->Insert("create", [](std::ostream& out) {
+ g_program.create_node_instance();
+ },
+ "Create a new node instance");
+
+ rootMenu->Insert("destroy", [](std::ostream& out) {
+ g_program.destroy_node_instance();
+ },
+ "Destroy the node instance with the given index");
+
+ rootMenu->Insert("activate", [](std::ostream& out) {
+ g_program.activate_node_instance();
+ },
+ "Activate the node instance with the given index");
+
+ rootMenu->Insert("deactivate", [](std::ostream& out) {
+ g_program.deactivate_node_instance();
+ },
+ "Dectivate the node instance with the given index");
+
+ auto attributeMenu = std::make_unique<cli::Menu>("set_attribute");
+ for (auto &entry : g_attribute_test_entries) {
+ attributeMenu->Insert(entry.name, [entry](std::ostream& out) {
+ g_program.set_attribute(entry.type);
+ },
+ entry.description);
+ }
+
+ rootMenu->Insert(std::move(attributeMenu));
+
+ auto dataMenu = std::make_unique<cli::Menu>("push_data");
+ for (auto &entry : g_data_test_entries) {
+ dataMenu->Insert(entry.name, [entry](std::ostream& out) {
+ g_program.push_data(entry.type);
+ },
+ entry.description);
+ }
+
+ rootMenu->Insert(std::move(dataMenu));
+
+ cli::Cli cli(std::move(rootMenu));
+
+ cli::CliEcoreSession session(cli);
+ ref = &session;
+
+ g_program.set_ecore_session(&session);
+
+ session.Start();
+ session.Finish();
+
+ g_program.set_ecore_session(nullptr);
+ } catch (const std::exception& e) {
+ std::cout << "Exception: " << e.what() << std::endl;
+ }
+
+ return 0;
+}
+
--- /dev/null
+#include <iostream>
+#include <memory>
+
+#include "cliecoresession.h"
+
+#include "cli/cli.h"
+
+#include "mmi.h"
+
+class Program
+{
+public:
+ Program() {
+ mmi_initialize();
+ mmi_set_state_changed_cb(state_changed_cb, this);
+ }
+ ~Program() {
+ mmi_unset_state_changed_cb(state_changed_cb);
+ mmi_deinitialize();
+ }
+
+ void create_instance(int type) {
+ if (m_instance) {
+ std::cout << "Instance already created" << std::endl;
+ return;
+ }
+
+ std::cout << "Creating instance of type " << type << std::endl;
+ mmi_standard_workflow_instance_create(
+ static_cast<mmi_standard_workflow_type_e>(type), &m_instance);
+ mmi_workflow_instance_set_output_callback(m_instance, "COMMAND",
+ [](mmi_workflow_instance_h instance, const char *name, mmi_data_h data, void *user_data) {
+ std::cout << "OUTPUT data received : " << std::string(name ? name : "") << std::endl;
+ },
+ nullptr);
+ mmi_workflow_instance_set_output_callback(m_instance, "UTTERANCE",
+ [](mmi_workflow_instance_h instance, const char *name, mmi_data_h data, void *user_data) {
+ const char *value = nullptr;
+ mmi_data_get_text(data, &value);
+ std::cout << "OUTPUT data received : " << std::string(name ? name : "") << " : " << value << std::endl;
+ },
+ nullptr);
+ }
+ void destroy_instance() {
+ if (!m_instance) {
+ std::cout << "No instance to destroy" << std::endl;
+ return;
+ }
+
+ std::cout << "Destroying instance" << std::endl;
+ mmi_workflow_instance_destroy(m_instance);
+ m_instance = nullptr;
+ }
+ void activate_instance() {
+ if (!m_instance) {
+ std::cout << "No instance to activate" << std::endl;
+ return;
+ }
+
+ std::cout << "Activating instance" << std::endl;
+ mmi_workflow_instance_activate(m_instance);
+ }
+ void deactivate_instance() {
+ if (!m_instance) {
+ std::cout << "No instance to deactivate" << std::endl;
+ return;
+ }
+
+ std::cout << "Deactivating instance" << std::endl;
+ mmi_workflow_instance_deactivate(m_instance);
+ }
+ void set_attribute() {
+ if (!m_instance) {
+ std::cout << "No instance to set attribute" << std::endl;
+ return;
+ }
+
+ std::cout << "Setting attribute " << std::endl;
+
+ mmi_attribute_h attribute = nullptr;
+ constexpr size_t COMMAND_NUM = 2;
+ const char *commands[] = {"Open", "Close"};
+ mmi_attribute_create_string_array("COMMANDS", commands, COMMAND_NUM, &attribute);
+
+ mmi_workflow_instance_set_attribute(m_instance, attribute);
+
+ mmi_attribute_destroy(attribute);
+
+ attribute = nullptr;
+ mmi_primitive_value_h lang_value = nullptr;
+ mmi_primitive_value_create_string("ko-KR", &lang_value);
+ mmi_attribute_create(lang_value, "LANGUAGE", &attribute);
+ mmi_workflow_instance_set_attribute(m_instance, attribute);
+ mmi_attribute_destroy(attribute);
+ mmi_primitive_value_destroy(lang_value);
+
+ attribute = nullptr;
+ mmi_primitive_value_h stop_method_value = nullptr;
+ mmi_primitive_value_create_int(1, &stop_method_value); // 1 : silence detection
+ mmi_attribute_create(stop_method_value, "STOP_METHOD", &attribute);
+ mmi_workflow_instance_set_attribute(m_instance, attribute);
+ mmi_attribute_destroy(attribute);
+ mmi_primitive_value_destroy(stop_method_value);
+ }
+
+ static int state_changed_cb(mmi_state_e state, void *user_data) {
+ Program *program = static_cast<Program*>(user_data);
+ program->m_state = state;
+ std::cout << "State changed to " << state << std::endl;
+ return 0;
+ }
+private:
+ mmi_state_e m_state{MMI_STATE_NONE};
+ mmi_workflow_instance_h m_instance{nullptr};
+};
+
+static Program g_program;
+
+int main(void)
+{
+ try {
+ cli::SetColor();
+
+ cli::CliEcoreSession *ref = nullptr;
+ auto rootMenu = std::make_unique<cli::Menu>( "cli" );
+
+ rootMenu->Insert("loop", [&ref](std::ostream& out) {
+ if (ref) {
+ ref->Loop();
+ }
+ },
+ "Start ecore main loop");
+
+ rootMenu->Insert("create", [](std::ostream& out, int type) {
+ g_program.create_instance(type);
+ },
+ "Creates a new workflow instance");
+
+ rootMenu->Insert("destroy", [](std::ostream& out) {
+ g_program.destroy_instance();
+ },
+ "Destroys the current workflow instance");
+
+ rootMenu->Insert("set_attribute", [](std::ostream& out) {
+ g_program.set_attribute();
+ },
+ "Set attributes for the current workflow instance");
+
+ rootMenu->Insert("activate", [](std::ostream& out) {
+ g_program.activate_instance();
+ },
+ "Activates the current workflow instance");
+
+ rootMenu->Insert("deactivate", [](std::ostream& out) {
+ g_program.deactivate_instance();
+ },
+ "Deactivates the current workflow instance");
+
+ cli::Cli cli(std::move(rootMenu));
+
+ cli::CliEcoreSession session(cli);
+ ref = &session;
+
+ session.Start();
+ session.Finish();
+ } catch (const std::exception& e) {
+ std::cout << "Exception: " << e.what() << std::endl;
+ }
+
+ return 0;
+}
+
+++ /dev/null
-/*
- * 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 "mmi-ipc.h"
-#include "mmi-dbg.h"
-#include "mmi-client.h"
-
-static mmi_handle mmi_h = NULL;
-
-int mmi_client_create(void)
-{
- mmi_h = (mmi_handle)calloc(1, sizeof(mmi_struct_s));
-
- if (mmi_h == NULL) {
- LOGE("Failed to allocate memory for mmi_h !\n");
- return MMI_ERROR_OUT_OF_MEMORY;
- }
-
- if (mmi_ipc_initialize()) {
- LOGE("Failed to init mmi ipc !\n");
- if(mmi_h != NULL) {
- free(mmi_h);
- mmi_h = NULL;
- }
- return MMI_ERROR_NOT_SUPPORTED;
- }
-
- mmi_h->rpc_h = mmi_ipc_get_rpc_h();
- mmi_h->stub_appid = mmi_ipc_get_stub_appid();
- mmi_h->result_cb_list = NULL;
-
- return MMI_ERROR_NONE;
-}
-
-int mmi_client_destroy(void)
-{
- if (mmi_h == NULL) {
- LOGE("A mmi_h is already NULL");
- return MMI_ERROR_NONE;
- }
-
- mmi_ipc_deinitialize();
- mmi_h->rpc_h = NULL;
-
- GList *iter = NULL;
- mmi_result_cb_s *data = NULL;
-
- if (g_list_length(mmi_h->result_cb_list) > 0) {
- iter = g_list_first(mmi_h->result_cb_list);
- while (iter != NULL) {
- data = iter->data;
- if (data != NULL) {
- data->input_event_type = 0;
- data->result_callback = NULL;
- free(data);
- data = NULL;
-
- GList *temp = iter;
- iter = g_list_next(iter);
- mmi_h->result_cb_list = g_list_remove_link(mmi_h->result_cb_list, temp);
- }
- }
- }
-
- free(mmi_h);
- mmi_h = NULL;
-
- return MMI_ERROR_NONE;
-}
-
-static const char* __mmi_client_convert_error_code(int err)
-{
- switch (err) {
- case MMI_ERROR_NONE: return "MMI_ERROR_NONE";
- case MMI_ERROR_OUT_OF_MEMORY: return "MMI_ERROR_OUT_OF_MEMORY";
- case MMI_ERROR_IO_ERROR: return "MMI_ERROR_IO_ERROR";
- case MMI_ERROR_INVALID_PARAMETER: return "MMI_ERROR_INVALID_PARAMETER";
- case MMI_ERROR_OUT_OF_NETWORK: return "MMI_ERROR_OUT_OF_NETWORK";
- case MMI_ERROR_TIMED_OUT: return "MMI_ERROR_TIMED_OUT";
- case MMI_ERROR_PERMISSION_DENIED: return "MMI_ERROR_PERMISSION_DENIED";
- case MMI_ERROR_NOT_SUPPORTED: return "MMI_ERROR_NOT_SUPPORTED";
- case MMI_ERROR_OPERATION_FAILED: return "MMI_ERROR_OPERATION_FAILED";
- default:
- return "Invalid error code";
- }
- return NULL;
-}
-
-int mmi_client_set_result_cb(int input_event_type, mmi_result_cb callback, void* user_data)
-{
- LOGI("Set result cb about input event type(%d) to client", input_event_type);
-
- if (callback == NULL) {
- LOGE("Callback is invalid");
- return MMI_ERROR_INVALID_PARAMETER;
- }
-
- if (mmi_h == NULL) {
- LOGE("Fail to get client");
- return MMI_ERROR_OPERATION_FAILED;
- }
-
- mmi_result_cb_s* input_result_callback = (mmi_result_cb_s*)calloc(1, sizeof(mmi_result_cb_s));
- if (input_result_callback == NULL) {
- LOGE("[ERROR] Fail to allocate memory");
- return MMI_ERROR_OUT_OF_MEMORY;
- }
-
- input_result_callback->input_event_type = input_event_type;
- input_result_callback->result_callback = callback;
- mmi_h->result_cb_list = g_list_append(mmi_h->result_cb_list, input_result_callback);
-
- int ret = mmi_ipc_register_input_event_result_cb(input_event_type, callback);
- if (ret != MMI_ERROR_NONE) {
- LOGE("Fail to register input event's result callback(%d), reason(%s)", ret, __mmi_client_convert_error_code(ret));
- callback(input_event_type, __mmi_client_convert_error_code(ret), NULL);
- return ret;
- }
-
- return MMI_ERROR_NONE;
-}
-
-mmi_handle mmi_client_get(void)
-{
- return mmi_h;
-}
+++ /dev/null
-/*
- * 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 "mmi-ipc.h"
-#include "mmi-dbg.h"
-#include "mmi-client.h"
-
-#include <tzplatform_config.h>
-#include <unistd.h>
-#include <rpc-port.h>
-#include <rpc-port-internal.h>
-
-static rpc_port_proxy_mmi_h _rpc_h;
-static const char* _stub_appid = "mmi-manager";
-static int _connected = 0;
-
-rpc_port_proxy_mmi_h mmi_ipc_get_rpc_h(void)
-{
- return _rpc_h;
-}
-
-bool mmi_ipc_is_connected(void)
-{
- return _connected ? true : false;
-}
-
-const char * mmi_ipc_get_stub_appid(void)
-{
- return _stub_appid;
-}
-
-static void _on_connected(rpc_port_proxy_mmi_h h, void *user_data)
-{
- int r;
- _connected = 1;
-
- LOGI("...");
- return;
-}
-
-static void _on_disconnected(rpc_port_proxy_mmi_h h, void *user_data)
-{
- _connected = 0;
-
- LOGI("...");
-}
-static void _on_rejected(rpc_port_proxy_mmi_h h, void *user_data)
-{
- LOGI("...");
- _connected = 0;
-}
-
-int mmi_ipc_retry_connection(rpc_port_proxy_mmi_h h)
-{
- LOGI("Retry connection");
-
- int ret = rpc_port_proxy_mmi_connect_sync(h);
- if (ret != RPC_PORT_ERROR_NONE) {
- LOGE("Fail to retry connection(%d)", ret);
- return MMI_ERROR_OPERATION_FAILED;
- }
-
- return MMI_ERROR_NONE;
-}
-
-int mmi_ipc_initialize(void)
-{
- /* initialize handles */
- _rpc_h = NULL;
- int ret;
-
- rpc_port_proxy_mmi_callback_s callback = {
- .connected = _on_connected,
- .disconnected = _on_disconnected,
- .rejected = _on_rejected
- };
-
- ret = rpc_port_proxy_mmi_create(_stub_appid, &callback, NULL, &_rpc_h);
- if (ret != RPC_PORT_ERROR_NONE) {
- LOGE("Failed to create mmi proxy handle ! (error:%d)\n", ret);
- return MMI_ERROR_OPERATION_FAILED;
- }
-
- ret = rpc_port_proxy_mmi_connect_sync(_rpc_h);
- if (ret != RPC_PORT_ERROR_NONE) {
- LOGE("Try to connect again");
- //Retry
- ret = mmi_ipc_retry_connection(_rpc_h);
- if (ret != RPC_PORT_ERROR_NONE) {
- LOGE("Fail to retry connection(%d)", ret);
- return MMI_ERROR_OPERATION_FAILED;
- }
- }
-
- LOGI("connect mmi ipc");
-
- return MMI_ERROR_NONE;
-}
-
-void mmi_ipc_deinitialize(void)
-{
- if (!_rpc_h)
- return;
-
- LOGI("disconnect mmi ipc");
-
- rpc_port_proxy_mmi_destroy(_rpc_h);
- rpc_port_deregister_proc_info();
- _rpc_h = NULL;
-
- _connected = 0;
-}
-
-int mmi_ipc_register_input_event_result_cb(int input_event_type, rpc_port_proxy_mmi_result_cb_cb callback)
-{
- LOGI("Register input event(%d) result cb to MMI Service", input_event_type);
- int ret;
-
- if (callback == NULL) {
- LOGE("Parameter callback is NULL");
- return MMI_ERROR_INVALID_PARAMETER;
- }
-
- if (input_event_type == MMI_INPUT_EVENT_TYPE_NONE) {
- LOGE("Parameter input event type is NULL");
- return MMI_ERROR_INVALID_PARAMETER;
- }
-
- mmi_handle client = mmi_client_get();
- if (client == NULL) {
- LOGE("Fail to get client");
- return MMI_ERROR_OPERATION_FAILED;
- }
-
- rpc_port_proxy_mmi_h rpc_h = client->rpc_h;
- if (rpc_h == NULL) {
- LOGE("Fail to get tidl rpc info");
- return MMI_ERROR_OPERATION_FAILED;
- }
-
- if (mmi_ipc_is_connected() == false) {
- LOGE("Try to connect again");
- ret = mmi_ipc_retry_connection(rpc_h);
- if (ret != RPC_PORT_ERROR_NONE) {
- LOGE("Fail to retry connection(%d)", ret);
- return MMI_ERROR_OPERATION_FAILED;
- }
- }
-
- rpc_port_proxy_mmi_result_cb_h result_cb_h;
- ret = rpc_port_proxy_mmi_result_cb_create(&result_cb_h);
- if (ret != RPC_PORT_ERROR_NONE) {
- LOGE("Failed to create result callback handle (error:%d)\n", ret);
- return MMI_ERROR_OPERATION_FAILED;
- }
- rpc_port_proxy_mmi_result_cb_set_callback(result_cb_h, callback, NULL);
- rpc_port_proxy_mmi_result_cb_set_once(result_cb_h, false);
- if (result_cb_h == NULL) {
- LOGE("Failed to create event callbacks");
- return MMI_ERROR_OPERATION_FAILED;
- }
-
- ret = rpc_port_proxy_mmi_invoke_register_input_event(rpc_h, input_event_type, result_cb_h);
- if (ret != RPC_PORT_ERROR_NONE) {
- LOGE("Failed to register event callbacks(%d)\n", ret);
- return MMI_ERROR_OPERATION_FAILED;
- }
-
- return MMI_ERROR_NONE;
-}
-
-int mmi_ipc_activate_input_event(int input_event_type)
-{
- LOGI("Activate about input event type(%d)", input_event_type);
-
- int ret;
-
- if (input_event_type == MMI_INPUT_EVENT_TYPE_NONE) {
- LOGE("Parameter input event type is NULL");
- return MMI_ERROR_INVALID_PARAMETER;
- }
-
- mmi_handle client = mmi_client_get();
- if (client == NULL) {
- LOGE("Fail to get client");
- return MMI_ERROR_OPERATION_FAILED;
- }
-
- rpc_port_proxy_mmi_h rpc_h = client->rpc_h;
- if (rpc_h == NULL) {
- LOGE("Fail to get tidl rpc info");
- return MMI_ERROR_OPERATION_FAILED;
- }
-
- if (mmi_ipc_is_connected() == false) {
- LOGE("Try to connect again");
- ret = mmi_ipc_retry_connection(_rpc_h);
- if (ret != RPC_PORT_ERROR_NONE) {
- LOGE("Fail to retry connection(%d)", ret);
- return MMI_ERROR_OPERATION_FAILED;
- }
- }
-
- ret = rpc_port_proxy_mmi_invoke_activate_input_event(rpc_h, input_event_type);
- if (ret != RPC_PORT_ERROR_NONE) {
- LOGE("Fail to invoke activate input event");
- return MMI_ERROR_OPERATION_FAILED;
- }
-
- return MMI_ERROR_NONE;
-}
-
-int mmi_ipc_deactivate_input_event(int input_event_type)
-{
- LOGE("Dectivate about input event type(%d)", input_event_type);
-
- int ret;
- rpc_port_proxy_mmi_h rpc_h = NULL;
-
- if (input_event_type == MMI_INPUT_EVENT_TYPE_NONE) {
- LOGE("Parameter input event type is NULL");
- return MMI_ERROR_INVALID_PARAMETER;
- }
-
- rpc_h = mmi_ipc_get_rpc_h();
- if (rpc_h == NULL) {
- LOGE("Fail to get tidl rpc info");
- return MMI_ERROR_OPERATION_FAILED;
- }
-
- ret = rpc_port_proxy_mmi_invoke_deactivate_input_event(rpc_h, input_event_type);
- if (ret != RPC_PORT_ERROR_NONE) {
- LOGE("Fail to invoke activate input event");
- return MMI_ERROR_OPERATION_FAILED;
- }
-
- return MMI_ERROR_NONE;
-}
--- /dev/null
+/*
+* Copyright © 2021 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 <Ecore.h>
+
+#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<mmi::communication::CommunicationChannelManager> create_channel() override {
+ return std::make_shared<mmi::communication::CommunicationChannelTIDL>();
+ }
+};
+
+static Ecore_Event_Handler *exit_signal_event_handler = nullptr;
+
+static Eina_Bool
+exit_signal_cb(void *data EINA_UNUSED, int type, void *event) {
+ ecore_main_loop_quit();
+
+ return ECORE_CALLBACK_PASS_ON;
+}
+
+int main(int argc, char *argv[]) {
+ ecore_init();
+
+ std::shared_ptr<mmi::communication::CommunicationChannelManagerFactory> communication_channel_factory;
+ std::shared_ptr<mmi::IPluginModuleProxyFactory> plugin_module_proxy_factory;
+
+ argh::parser cmdl(argv);
+
+ if (cmdl["--self-container-test"]) {
+ plugin_module_proxy_factory = std::make_shared<mmi::PluginModuleProxyFactorySelfContainerTest>();
+ } else {
+ plugin_module_proxy_factory = std::make_shared<mmi::PluginModuleProxyFactoryDefault>();
+ }
+
+ communication_channel_factory = std::make_shared<CommunicationChannelFactoryTIDL>();
+
+ mmi::Manager manager(communication_channel_factory, plugin_module_proxy_factory);
+
+ manager.initialize();
+
+ exit_signal_event_handler = ecore_event_handler_add(
+ ECORE_EVENT_SIGNAL_EXIT, exit_signal_cb, nullptr);
+
+ ecore_main_loop_begin();
+
+ ecore_main_loop_thread_safe_call_wait(1.0f);
+
+ ecore_event_handler_del(exit_signal_event_handler);
+ exit_signal_event_handler = nullptr;
+
+ manager.deinitialize();
+
+ ecore_shutdown();
+ return 0;
+}
+
--- /dev/null
+mmi_manager_library_srcs = [
+ 'mmi-manager.cpp',
+ 'mmi-ipc-tidl.cpp',
+ 'mmi-client.cpp',
+ 'mmi-common.cpp',
+ 'mmi-data-gateway.cpp',
+ 'mmi-port-instance.cpp',
+ 'mmi-port-instance-manager.cpp',
+ 'mmi-node-prototype.cpp',
+ 'mmi-node-prototype-manager.cpp',
+ 'mmi-node-instance.cpp',
+ 'mmi-node-instance-manager.cpp',
+ 'mmi-workflow-prototype.cpp',
+ 'mmi-workflow-prototype-manager.cpp',
+ 'mmi-workflow-instance.cpp',
+ 'mmi-workflow-instance-manager.cpp',
+ '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')
+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')
+
+mmi_manager_deps = [
+ mmi_declared_dep,
+ bundle_dep,
+ dlog_dep,
+ ecore_dep,
+ glib_dep,
+ rpc_port_dep,
+ libtzplatform_config_dep,
+ ]
+
+mmi_manager_include_dirs = include_directories(
+ '.',
+ '../common/',
+ '../../capi/',
+ '../../external/',
+ )
+
+mmi_manager_library = library('mmi_manager',
+ mmi_manager_library_srcs,
+ include_directories : [ mmi_manager_include_dirs ],
+ dependencies : [mmi_manager_deps],
+ install_dir : mmi_prefix_libdir,
+ install : true
+ )
+
+mmi_manager_declared_dep = declare_dependency(
+ link_with : mmi_manager_library,
+ dependencies : [mmi_manager_deps],
+ include_directories : [mmi_manager_include_dirs]
+ )
+
+mmi_manager_program_srcs = [
+ 'main.cpp'
+ ]
+
+mmi_manager_program_deps = [
+ mmi_manager_declared_dep
+ ]
+
+executable('mmi-manager',
+ mmi_manager_program_srcs,
+ include_directories : [ mmi_manager_include_dirs ],
+ dependencies : [mmi_manager_program_deps],
+ install_dir : mmi_prefix_bindir,
+ install : true,
+ pie : true
+ )
+
+install_data('mmi-manager.xml', install_dir:'/usr/share/packages/')
--- /dev/null
+/*
+* Copyright © 2021 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 "mmi-client.h"
+#include "mmi-common.h"
+#include "mmi-manager-log.h"
+#include "mmi_stub.h"
+
+namespace mmi {
+
+ClientManager::ClientManager() {
+}
+
+ClientManager::~ClientManager() {
+}
+
+void ClientManager::on_observer_event(
+ const COMMUNICATION_CHANNEL_EVENT_TYPE &event, std::any data) {
+ try {
+ if (event == COMMUNICATION_CHANNEL_EVENT_TYPE::CONNECTED) {
+ std::string sender = std::any_cast<std::string>(data);
+ add_client(sender);
+ } else if (event == COMMUNICATION_CHANNEL_EVENT_TYPE::DISCONNECTED) {
+ std::string sender = std::any_cast<std::string>(data);
+ remove_client(sender);
+ }
+ } catch (const std::bad_any_cast &e) {
+ LOGE("Failed to cast message data: %s", e.what());
+ }
+}
+
+int ClientManager::initialize() {
+ return MMI_ERROR_NONE;
+}
+
+int ClientManager::deinitialize() {
+ for (auto it = m_clients.begin(); it != m_clients.end(); it++) {
+ delete it->second;
+ }
+ m_clients.clear();
+
+ return MMI_ERROR_NONE;
+}
+
+Client* ClientManager::add_client(std::string sender) {
+ LOGI("Add client(%s)\n", sender.c_str());
+
+ Client *client = new Client(sender);
+ if (!client) {
+ LOGE("Failed to allocate memory for client !\n");
+ return nullptr;
+ }
+
+ m_clients.insert(std::pair<std::string, Client*>(sender, client));
+
+ return client;
+}
+
+Client* ClientManager::get_client(std::string sender) {
+ auto it = m_clients.find(sender);
+
+ if (it == m_clients.end()) {
+ LOGE("Failed to find client info from sender(%s)\n", sender.c_str());
+ return nullptr;
+ }
+
+ return it->second;
+}
+
+int ClientManager::remove_client(std::string sender) {
+ LOGI("Remove client(%s)\n", sender.c_str());
+
+ auto it = m_clients.find(sender);
+
+ if (it == m_clients.end()) {
+ LOGE("Failed to find client info from sender(%s)\n", sender.c_str());
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ delete it->second;
+ m_clients.erase(it);
+
+ return MMI_ERROR_NONE;
+}
+
+
+int ClientManager::set_client_uid(Client *client, uid_t uid) {
+ if (!client) {
+ LOGE("client is NULL\n");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ client->set_uid(uid);
+
+ return MMI_ERROR_NONE;
+}
+
+uid_t ClientManager::get_client_uid(Client *client) {
+ uid_t uid = 0;
+
+ if (!client) {
+ LOGE("client is NULL\n");
+ return uid;
+ }
+
+ uid = client->get_uid();
+
+ return uid;
+}
+
+int ClientManager::set_client_pid(Client *client, pid_t pid) {
+ if (!client) {
+ LOGE("client is NULL\n");
+ return MMI_ERROR_INVALID_PARAMETER;;
+ }
+
+ client->set_pid(pid);
+
+ return MMI_ERROR_NONE;
+}
+
+pid_t ClientManager::get_client_pid(Client *client) {
+ pid_t pid = 0;
+
+ if (!client) {
+ LOGE("client is NULL\n");
+ return pid;
+ }
+
+ pid = client->get_pid();
+
+ return pid;
+}
+
+std::string ClientManager::get_client_sender(Client *client) {
+ std::string sender;
+
+ if (!client) {
+ LOGE("client is NULL\n");
+ return sender;
+ }
+
+ sender = client->get_sender();
+
+ return sender;
+}
+
+} // namespace mmi
--- /dev/null
+/*
+* Copyright © 2021 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_CLIENT_H__
+#define __MMI_CLIENT_H__
+
+#include <stdlib.h>
+
+#include <string>
+#include <map>
+
+#include <mmi.h>
+
+#include "mmi-common.h"
+#include "mmi-communication-channel.h"
+#include "mmi_stub.h"
+
+namespace mmi {
+
+using namespace communication;
+
+class Client {
+public:
+ Client(std::string sender) : m_sender(sender) {
+ }
+ virtual ~Client() {
+ }
+
+ std::string get_sender() {
+ return m_sender;
+ }
+
+ uid_t get_uid() {
+ return m_uid;
+ }
+ pid_t get_pid() {
+ return m_pid;
+ }
+
+ void set_uid(uid_t uid) {
+ m_uid = uid;
+ }
+ void set_pid(pid_t pid) {
+ m_pid = pid;
+ }
+
+private:
+ std::string m_sender;
+ uid_t m_uid{0};
+ pid_t m_pid{0};
+};
+
+class ClientManager :
+ public SimpleEventObserver<COMMUNICATION_CHANNEL_EVENT_TYPE> {
+public:
+ ClientManager();
+ virtual ~ClientManager();
+
+ void on_observer_event(
+ const COMMUNICATION_CHANNEL_EVENT_TYPE &event, std::any data) override;
+
+ int initialize();
+ int deinitialize();
+
+ Client* add_client(std::string sender);
+ Client* get_client(std::string sender);
+ int remove_client(std::string sender);
+
+ int set_client_uid(Client *client, uid_t uid);
+ uid_t get_client_uid(Client *client);
+
+ int set_client_pid(Client *client, pid_t pid);
+ pid_t get_client_pid(Client *client);
+
+ std::string get_client_sender(Client *client);
+
+private:
+ std::map<std::string, Client*> m_clients;
+};
+
+} // namespace mmi
+
+#endif //__MMI_CLIENT_H__
--- /dev/null
+/*
+* Copyright © 2021 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 "mmi-common.h"
+
--- /dev/null
+/*
+* Copyright © 2021 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_COMMON_H__
+#define __MMI_COMMON_H__
+
+#include <stdbool.h>
+#include <tizen.h>
+
+#ifndef MMI_API
+#define MMI_API __attribute__ ((visibility("default")))
+#endif
+
+#endif //__MMI_COMMON_H__
--- /dev/null
+/*
+ * 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 "mmi-data-gateway.h"
+
+#include "mmi-manager-log.h"
+
+namespace mmi {
+
+DataGateway::DataGateway(std::string name)
+ : m_name(name) {
+ _D("Data Gateway is created: %s", m_name.c_str());
+}
+
+DataGateway::~DataGateway() {
+ _D("Data Gateway is destroyed: %s", m_name.c_str());
+}
+
+bool DataGateway::initialize() {
+ _D("Data Gateway is initialized: %s", m_name.c_str());
+ return true;
+}
+
+bool DataGateway::deinitialize() {
+ _D("Data Gateway is deinitialized: %s", m_name.c_str());
+ return true;
+}
+
+bool DataGateway::set_name(std::string name) {
+ m_name = name;
+ return true;
+}
+
+bool DataGateway::set_callback(mmi_data_transfer_callback callback) {
+ _D("[DataGateway] set data transfer callback");
+ m_data_transfer_callback = callback;
+ return true;
+}
+
+void DataGateway::send_data(mmi_data_h data) {
+ _D("[DataGateway] Send Data: %s", m_name.c_str());
+
+ if (m_data_transfer_callback) {
+ m_data_transfer_callback(data, m_name);
+ }
+ else {
+ _E("Data Gateway is not set callback: %s", m_name.c_str());
+ }
+}
+
+} // namespace mmi
\ No newline at end of file
--- /dev/null
+/*
+* 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_DATA_GATEWAY_H__
+#define __MMI_DATA_GATEWAY_H__
+
+#include "mmi-data.h"
+
+#include <string>
+#include <functional>
+
+namespace mmi {
+
+using mmi_data_transfer_callback = std::function<void(mmi_data_h, std::string)>;
+
+class DataGateway {
+public:
+ DataGateway(std::string name);
+ virtual ~DataGateway();
+
+ bool initialize();
+ bool deinitialize();
+
+ bool set_name(std::string name);
+ bool set_callback(mmi_data_transfer_callback callback);
+
+ void send_data(mmi_data_h data);
+
+private:
+ std::string m_name;
+ mmi_data_transfer_callback m_data_transfer_callback;
+};
+
+} // namesapce mmi
+
+#endif // __MMI_DATA_GATEWAY_H__
\ No newline at end of file
--- /dev/null
+/*
+* Copyright © 2021 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 "mmi-ipc-tidl.h"
+
+#include "mmi-manager-log.h"
+#include "mmi-client.h"
+#include "mmi-common.h"
+
+#include <tuple>
+
+#include <bundle.h>
+#include <rpc-port.h>
+#include <rpc-port-internal.h>
+
+namespace mmi {
+
+namespace communication {
+
+CommunicationChannelTIDL::CommunicationChannelTIDL() {
+}
+
+CommunicationChannelTIDL::~CommunicationChannelTIDL() {
+}
+
+int CommunicationChannelTIDL::connect() {
+ int r;
+ LOGD("mmi_api_handler_initialize");
+
+ if (m_initialized) {
+ LOGE("Already initialized");
+ return MMI_ERROR_NONE;
+ }
+
+ r = rpc_port_register_proc_info(m_stub_appid.c_str(), nullptr);
+ if (r != RPC_PORT_ERROR_NONE) {
+ LOGE("Failed to register proc info ! (error:%d)", r);
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ rpc_port_stub_mmi_callback_s callback = {
+ on_create,
+ on_terminate,
+ workflow_instance_create,
+ workflow_instance_destroy,
+ workflow_instance_set_attribute,
+ workflow_instance_activate,
+ workflow_instance_deactivate,
+ workflow_instance_register_result_callback,
+ };
+
+ r = rpc_port_stub_mmi_register(&callback, this);
+ if (r != RPC_PORT_ERROR_NONE) {
+ LOGE("Failed to register callbacks (error:%d)", r);
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ m_initialized = true;
+ return MMI_ERROR_NONE;
+}
+
+int CommunicationChannelTIDL::disconnect() {
+ if (!m_initialized)
+ return MMI_ERROR_OPERATION_FAILED;
+
+ clear_invoke_callbacks();
+
+ rpc_port_stub_mmi_unregister();
+ rpc_port_deregister_proc_info();
+
+ m_initialized = false;
+
+ return MMI_ERROR_NONE;
+}
+
+int CommunicationChannelTIDL::send(communication::Message *message) {
+ return 0;
+}
+
+static bool get_sender_string(rpc_port_stub_mmi_context_h context,
+ CommunicationChannelTIDL *channel, std::string &sender) {
+ char *buf = nullptr;
+
+ //int res = rpc_port_stub_mmi_context_get_sender(context, &buf);
+ int res = rpc_port_stub_mmi_context_get_instance(context, &buf);
+ if (res != MMI_ERROR_NONE || !buf) {
+ LOGE("Failed to get sender from context ! (error:%d)", res);
+ free(buf);
+ return false;
+ }
+
+ sender = std::string{buf};
+ free(buf);
+ buf = nullptr;
+
+ return true;
+}
+
+static int notify_connection_changes(CommunicationChannelTIDL *channel, bool connected, std::string sender) {
+ if (nullptr == channel) {
+ LOGE("Failed to get channel information !");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ channel->notify_observers(
+ connected ?
+ COMMUNICATION_CHANNEL_EVENT_TYPE::CONNECTED :
+ COMMUNICATION_CHANNEL_EVENT_TYPE::DISCONNECTED,
+ sender);
+
+ return MMI_ERROR_NONE;
+}
+
+static int notify_message_received(CommunicationChannelTIDL *channel, Message *message) {
+ if (nullptr == channel) {
+ LOGE("Failed to get channel information !");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ channel->notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, message);
+
+ return MMI_ERROR_NONE;
+}
+
+void CommunicationChannelTIDL::on_create(rpc_port_stub_mmi_context_h context, void *user_data) {
+ CommunicationChannelTIDL *channel = static_cast<CommunicationChannelTIDL*>(user_data);
+
+ std::string sender;
+ if (!get_sender_string(context, channel, sender))
+ return;
+
+ LOGI("Client(%s) has been connected !", sender.c_str());
+
+ //TODO: set additional information of client
+ notify_connection_changes(channel, true, sender);
+}
+
+void CommunicationChannelTIDL::on_terminate(rpc_port_stub_mmi_context_h context, void *user_data) {
+ CommunicationChannelTIDL *channel = static_cast<CommunicationChannelTIDL*>(user_data);
+
+ std::string sender;
+ if (!get_sender_string(context, channel, sender))
+ return;
+
+ LOGI("Client(%s) has been disconnected !", sender.c_str());
+
+ channel->clear_invoke_callbacks();
+
+ notify_connection_changes(channel, false, sender);
+}
+
+int CommunicationChannelTIDL::workflow_instance_create(rpc_port_stub_mmi_context_h context,
+ int local_workflow_instance_id, int workflow_type, void *user_data) {
+ CommunicationChannelTIDL *channel = static_cast<CommunicationChannelTIDL*>(user_data);
+
+ std::string sender;
+ if (!get_sender_string(context, channel, sender))
+ return MMI_ERROR_INVALID_PARAMETER;
+
+ ClientMessageWorkflowInstanceCreate msg;
+ msg.sender = sender;
+ msg.local_workflow_instance_id = local_workflow_instance_id;
+ msg.workflow_type = static_cast<mmi_standard_workflow_type_e>(workflow_type);
+
+ return notify_message_received(channel, static_cast<Message*>(&msg));
+}
+
+int CommunicationChannelTIDL::workflow_instance_destroy(rpc_port_stub_mmi_context_h context,
+ int local_workflow_instance_id, void *user_data) {
+ CommunicationChannelTIDL *channel = static_cast<CommunicationChannelTIDL*>(user_data);
+
+ std::string sender;
+ if (!get_sender_string(context, channel, sender))
+ return MMI_ERROR_INVALID_PARAMETER;
+
+ ClientMessageWorkflowInstanceDestroy msg;
+ msg.sender = sender;
+ msg.local_workflow_instance_id = local_workflow_instance_id;
+
+ channel->remove_invoke_callbacks(sender, local_workflow_instance_id);
+
+ return notify_message_received(channel, static_cast<Message*>(&msg));
+}
+
+int CommunicationChannelTIDL::workflow_instance_set_attribute(rpc_port_stub_mmi_context_h context,
+ int local_workflow_instance_id, bundle *attribute, void *user_data) {
+ CommunicationChannelTIDL *channel = static_cast<CommunicationChannelTIDL*>(user_data);
+
+ std::string sender;
+ if (!get_sender_string(context, channel, sender))
+ return MMI_ERROR_INVALID_PARAMETER;
+
+ mmi_attribute_h restored_attribute;
+
+ unsigned char *bytes = nullptr;
+ size_t returned_size = 0;
+
+ if (BUNDLE_ERROR_NONE != bundle_get_byte(attribute, "data", (void**)&bytes, &returned_size)) {
+ _E("Bundle does not contain 'data' field");
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+ if (nullptr == bytes || 0 == returned_size) {
+ _E("Bundle does not contain 'data' field");
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ if (MMI_ERROR_NONE != mmi_attribute_from_bytes(bytes, returned_size, &restored_attribute)) {
+ _E("Failed to restore attribute from bytes");
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ ClientMessageWorkflowInstanceSetAttribute msg;
+ msg.sender = sender;
+ msg.local_workflow_instance_id = local_workflow_instance_id;
+ msg.attribute = restored_attribute;
+
+ notify_message_received(channel, static_cast<Message*>(&msg));
+
+ mmi_attribute_destroy(restored_attribute);
+
+ 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<CommunicationChannelTIDL*>(user_data);
+
+ std::string sender;
+ if (!get_sender_string(context, channel, sender))
+ return MMI_ERROR_INVALID_PARAMETER;
+
+ ClientMessageWorkflowInstanceActivate msg;
+ msg.sender = sender;
+ msg.local_workflow_instance_id = local_workflow_instance_id;
+
+ return notify_message_received(channel, static_cast<Message*>(&msg));
+}
+
+int CommunicationChannelTIDL::workflow_instance_deactivate(rpc_port_stub_mmi_context_h context,
+ int local_workflow_instance_id, void *user_data) {
+ CommunicationChannelTIDL *channel = static_cast<CommunicationChannelTIDL*>(user_data);
+
+ std::string sender;
+ if (!get_sender_string(context, channel, sender))
+ return MMI_ERROR_INVALID_PARAMETER;
+
+ ClientMessageWorkflowInstanceDeactivate msg;
+ msg.sender = sender;
+ msg.local_workflow_instance_id = local_workflow_instance_id;
+
+ return notify_message_received(channel, static_cast<Message*>(&msg));
+}
+
+int CommunicationChannelTIDL::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) {
+ CommunicationChannelTIDL *channel = static_cast<CommunicationChannelTIDL*>(user_data);
+
+ std::string sender;
+ if (!get_sender_string(context, channel, sender))
+ return MMI_ERROR_INVALID_PARAMETER;
+
+ rpc_port_stub_mmi_result_cb_h result_cb_h = nullptr;
+ int ret = rpc_port_stub_mmi_result_cb_clone(callback, &result_cb_h);
+
+ if (RPC_PORT_ERROR_NONE != ret) {
+ LOGE("Fail to clone invoke callback(%d)", ret);
+ rpc_port_stub_mmi_result_cb_destroy(result_cb_h);
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+ channel->set_invoke_callbacks(sender, local_workflow_instance_id, result_cb_h);
+
+ return MMI_ERROR_NONE;
+}
+
+void CommunicationChannelTIDL::on_observer_event(
+ const WORKFLOW_OUTPUT_EVENT_TYPE &event, std::any data) {
+ try {
+ WorkflowOutputEventOutputGenerated *output_generated = std::any_cast<WorkflowOutputEventOutputGenerated*>(data);
+
+ 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<bundle*>(output_generated->data);
+
+ int ret = rpc_port_stub_mmi_result_cb_invoke(callback, source_name.c_str(), data_b);
+ if (ret != RPC_PORT_ERROR_NONE) {
+ LOGE("Failed to send result to client !");
+ }
+ } catch (const std::bad_any_cast &e) {
+ LOGE("Failed to cast message data: %s", e.what());
+ }
+}
+
+void CommunicationChannelTIDL::set_invoke_callbacks(std::string client_id, int local_workflow_instance_id, rpc_port_stub_mmi_result_cb_h callback) {
+ std::string key = client_id + "_" + std::to_string(local_workflow_instance_id);
+ m_invoke_callbacks[key] = callback;
+}
+
+void CommunicationChannelTIDL::remove_invoke_callbacks(std::string client_id, int local_workflow_instance_id) {
+ std::string key = client_id + "_" + std::to_string(local_workflow_instance_id);
+ rpc_port_stub_mmi_result_cb_destroy(m_invoke_callbacks[key]);
+ m_invoke_callbacks.erase(key);
+}
+
+rpc_port_stub_mmi_result_cb_h CommunicationChannelTIDL::get_invoke_callbacks(std::string client_id, int local_workflow_instance_id) {
+ std::string key = client_id + "_" + std::to_string(local_workflow_instance_id);
+ return m_invoke_callbacks[key];
+}
+
+void CommunicationChannelTIDL::clear_invoke_callbacks() {
+ for (auto &it : m_invoke_callbacks) {
+ rpc_port_stub_mmi_result_cb_destroy(it.second);
+ }
+ m_invoke_callbacks.clear();
+}
+
+} // namespace communication
+//
+} // namespace mmi
--- /dev/null
+/*
+* Copyright © 2021 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_IPC_TIDL_H__
+#define __MMI_IPC_TIDL_H__
+
+#include "mmi_stub.h"
+#include "mmi-communication-channel.h"
+#include "mmi-workflow-output-event.h"
+
+#include <map>
+namespace mmi {
+
+namespace communication {
+
+class CommunicationChannelTIDL : public CommunicationChannelManager {
+public:
+ CommunicationChannelTIDL();
+ ~CommunicationChannelTIDL();
+
+ int connect() override;
+ int disconnect() override;
+ int send(communication::Message *message) override;
+
+ void on_observer_event(
+ const WORKFLOW_OUTPUT_EVENT_TYPE &event, std::any data) override;
+
+private:
+ static void on_create(rpc_port_stub_mmi_context_h context, void *user_data);
+ 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);
+ static int workflow_instance_destroy(rpc_port_stub_mmi_context_h context,
+ 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);
+ static int workflow_instance_activate(rpc_port_stub_mmi_context_h context,
+ 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);
+ 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);
+
+ void set_invoke_callbacks(std::string appid, int local_workflow_instance_id,
+ rpc_port_stub_mmi_result_cb_h callback);
+ rpc_port_stub_mmi_result_cb_h get_invoke_callbacks(std::string appid, int local_workflow_instance_id);
+ void remove_invoke_callbacks(std::string appid, int local_workflow_instance_id);
+ void clear_invoke_callbacks();
+
+private:
+ bool m_initialized{false};
+ const std::string m_stub_appid{"mmi-manager"};
+ std::map<std::string, rpc_port_stub_mmi_result_cb_h> m_invoke_callbacks;
+};
+
+} // namespace communication
+
+} // namespace mmi
+
+#endif //__MMI_IPC_TIDL_H__
--- /dev/null
+/*
+* Copyright © 2021 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_MANAGER_LOG_H__
+#define __MMI_MANAGER_LOG_H__
+
+#include <dlog.h>
+
+#ifdef LOG_TAG
+#undef LOG_TAG
+#endif
+#define LOG_TAG "MMIMGR"
+
+#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_MANAGER_LOG_H__
--- /dev/null
+/*
+* Copyright © 2021 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 "mmi-manager.h"
+
+namespace mmi {
+
+Manager::Manager(
+ std::shared_ptr<CommunicationChannelManagerFactory> communication_channel_factory,
+ std::shared_ptr<IPluginModuleProxyFactory> plugin_module_proxy_factory) :
+ m_communication_channel_factory(communication_channel_factory),
+ m_plugin_module_proxy_factory(plugin_module_proxy_factory) {
+}
+
+Manager::~Manager() {
+}
+
+int Manager::initialize() {
+ if (nullptr == m_communication_channel_factory) {
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ m_plugin_module_registry = std::make_shared<PluginModuleRegistry>();
+ if (nullptr == m_plugin_module_registry) {
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ m_client_manager = std::make_shared<ClientManager>();
+
+ m_port_instance_manager = std::make_shared<PortInstanceManager>();
+
+ m_node_prototype_manager = std::make_shared<NodePrototypeManager>();
+ m_node_instance_manager = std::make_shared<NodeInstanceManager>();
+ if (nullptr == m_node_instance_manager) {
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ m_node_instance_manager->set_plugin_module_proxy_provider(m_plugin_module_registry);
+ m_node_instance_manager->set_node_prototype_store(m_node_prototype_manager);
+ m_node_instance_manager->set_port_instance_manager(m_port_instance_manager);
+
+ m_workflow_prototype_manager = std::make_shared<WorkflowPrototypeManager>();
+ m_workflow_instance_manager = std::make_shared<WorkflowInstanceManager>();
+ if (nullptr == m_workflow_instance_manager) {
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ m_workflow_instance_manager->set_workflow_prototype_store(m_workflow_prototype_manager);
+ m_workflow_instance_manager->set_plugin_module_proxy_provider(m_plugin_module_registry);
+ m_workflow_instance_manager->set_node_instance_manager(m_node_instance_manager);
+ m_workflow_instance_manager->add_observer(this);
+
+ m_communication_channel = m_communication_channel_factory->create_channel();
+ if (m_communication_channel) {
+ m_communication_channel->add_observer(m_client_manager.get());
+ m_communication_channel->add_observer(m_workflow_instance_manager.get());
+
+ m_communication_channel->connect();
+ } else {
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ m_plugin_module_proxy_factory->add_observer(m_node_instance_manager.get());
+
+ m_plugin_module_registry->set_plugin_module_proxy_factory(m_plugin_module_proxy_factory);
+ m_plugin_module_registry->set_node_prototype_store(m_node_prototype_manager);
+ m_plugin_module_registry->set_workflow_prototype_store(m_workflow_prototype_manager);
+
+ m_plugin_module_registry->initialize();
+
+ return MMI_ERROR_NONE;
+}
+
+int Manager::deinitialize() {
+ if (m_communication_channel) {
+ m_communication_channel->disconnect();
+
+ m_communication_channel->remove_observer(m_client_manager.get());
+ m_communication_channel->remove_observer(m_workflow_instance_manager.get());
+ }
+
+ m_communication_channel.reset();
+ m_communication_channel_factory.reset();
+
+ m_plugin_module_proxy_factory.reset();
+
+ m_workflow_instance_manager.reset();
+ m_workflow_prototype_manager.reset();
+
+ m_node_instance_manager.reset();
+
+ m_port_instance_manager.reset();
+
+ m_client_manager.reset();
+
+ if (m_plugin_module_registry) {
+ m_plugin_module_registry->deinitialize();
+ }
+ m_plugin_module_registry.reset();
+
+ return MMI_ERROR_NONE;
+}
+
+void Manager::on_observer_event(
+ const WORKFLOW_EVENT_TYPE &event, std::any data) {
+ try {
+ WorkflowEventWorkflowCreated *workflow_created = std::any_cast<WorkflowEventWorkflowCreated*>(data);
+ std::shared_ptr<WorkflowInstance> workflow_instance = std::any_cast<std::shared_ptr<WorkflowInstance>>(workflow_created->workflow_instance);
+ workflow_instance->add_observer(m_communication_channel.get());
+ } catch (const std::bad_any_cast &e) {
+ LOGE("Failed to cast message data: %s", e.what());
+ }
+}
+
+
+} // namespace mmi
--- /dev/null
+/*
+* Copyright © 2021 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_MANAGER_H__
+#define __MMI_MANAGER_H__
+
+#include <memory>
+
+#include "mmi-client.h"
+#include "mmi-communication-channel.h"
+#include "mmi-plugin-module-registry.h"
+#include "mmi-node-instance-manager.h"
+#include "mmi-node-prototype-manager.h"
+#include "mmi-port-instance-manager.h"
+#include "mmi-workflow-instance-manager.h"
+#include "mmi-workflow-prototype-manager.h"
+#include "mmi-workflow-event.h"
+
+namespace mmi {
+
+using namespace mmi::communication;
+
+class Manager : SimpleEventObserver<WORKFLOW_EVENT_TYPE> {
+public:
+ Manager(std::shared_ptr<CommunicationChannelManagerFactory> communication_channel_factory,
+ std::shared_ptr<IPluginModuleProxyFactory> plugin_module_proxy_factory);
+ virtual ~Manager();
+
+ int initialize();
+ int deinitialize();
+
+ void on_observer_event(
+ const WORKFLOW_EVENT_TYPE &event, std::any data) override;
+
+private:
+ std::shared_ptr<CommunicationChannelManagerFactory> m_communication_channel_factory;
+ std::shared_ptr<CommunicationChannelManager> m_communication_channel;
+
+ std::shared_ptr<IPluginModuleProxyFactory> m_plugin_module_proxy_factory;
+ std::shared_ptr<PluginModuleRegistry> m_plugin_module_registry;
+
+ std::shared_ptr<ClientManager> m_client_manager;
+
+ std::shared_ptr<PortInstanceManager> m_port_instance_manager;
+
+ std::shared_ptr<NodePrototypeManager> m_node_prototype_manager;
+ std::shared_ptr<NodeInstanceManager> m_node_instance_manager;
+
+ std::shared_ptr<WorkflowPrototypeManager> m_workflow_prototype_manager;
+ std::shared_ptr<WorkflowInstanceManager> m_workflow_instance_manager;
+};
+
+} // namespace mmi
+
+#endif //__MMI_MANAGER_H__
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns="http://tizen.org/ns/packages" api-version="7" package="mmi-manager" version="1.0.3">
+ <label>mmi-manager</label>
+ <author email="dyamy.lee@samsung.com" href="www.samsung.com">DaYe Lee</author>
+ <description>autofilld</description>
+ <ui-application appid="mmi-manager" exec="/usr/bin/mmi-manager" multiple="false" nodisplay="false" taskmanage="false" type="capp">
+ <label>mmi-manager</label>
+ </ui-application>
+ <privileges>
+ <privilege>http://tizen.org/privilege/inputgenerator</privilege>
+ <privilege>http://tizen.org/privilege/datasharing</privilege>
+ <privilege>http://tizen.org/privilege/externalstroage</privilege>
+ <privilege>http://tizen.org/privilege/mediastorage</privilege>
+ </privileges>
+</manifest>
--- /dev/null
+/*
+ * Copyright © 2021 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 "mmi-node-instance-manager.h"
+
+#include "mmi-manager-log.h"
+
+#include <algorithm>
+
+namespace mmi {
+
+NodeInstanceManager::NodeInstanceManager() {
+}
+
+NodeInstanceManager::~NodeInstanceManager() {
+}
+
+std::shared_ptr<NodeInstance> NodeInstanceManager::create_node_instance(
+ mmi_standard_node_type_e node_type,
+ mmi_standard_node_sub_type_e node_sub_type) {
+ std::shared_ptr<NodeInstance> ret;
+
+ ret = std::make_shared<NodeInstance>(node_type, node_sub_type);
+ if (ret == nullptr) {
+ _E("Failed to create node instance");
+ return ret;
+ }
+
+ ret->set_node_prototype_store(m_prototype_store);
+ ret->set_plugin_module_proxy_provider(m_plugin_module_proxy_provider);
+ ret->set_port_instance_manager(m_port_instance_manager);
+
+ ret->initialize();
+
+ m_node_instances.push_back(ret);
+
+ return ret;
+}
+
+bool NodeInstanceManager::destroy_node_instance(
+ std::shared_ptr<NodeInstance> node_instance) {
+ if (node_instance) {
+ node_instance->deinitialize();
+ }
+
+ auto &instances = m_node_instances;
+
+ auto it = std::find(instances.begin(), instances.end(), node_instance);
+ if (it == instances.end()) {
+ _E("Node instance is not found");
+ return false;
+ }
+
+ instances.erase(it);
+
+ return true;
+}
+
+bool NodeInstanceManager::link_node_instances(
+ std::shared_ptr<NodeInstance> from_node_instance,
+ std::shared_ptr<NodeInstance> to_node_instance,
+ std::optional<std::string> from_port_name,
+ std::optional<std::string> to_port_name) {
+ if (nullptr == from_node_instance || nullptr == to_node_instance) {
+ LOGE("Failed to find node instances : from(%p) to(%p)",
+ from_node_instance.get(), to_node_instance.get());
+ return false;
+ }
+
+ if (false == from_port_name.has_value() || false == to_port_name.has_value() ) {
+ LOGE("Failed to find port names : from(%s) to(%s)",
+ from_port_name.has_value() ? from_port_name.value().c_str() : "null",
+ to_port_name.has_value() ? to_port_name.value().c_str() : "null");
+ return false;
+ }
+
+ std::shared_ptr<PortInstance> from_port_instance =
+ from_node_instance->get_port_instance(from_port_name.value());
+ std::shared_ptr<PortInstance> to_port_instance =
+ to_node_instance->get_port_instance(to_port_name.value());
+
+ if (nullptr == from_port_instance || nullptr == to_port_instance) {
+ LOGE("Failed to find port instance : %s(%p) %s(%p)",
+ from_port_name.value().c_str(), from_port_instance.get(),
+ to_port_name.value().c_str(), to_port_instance.get());
+ return false;
+ }
+
+ LOGD("Linking port instances : [%p:%s] - [%p:%s]",
+ from_node_instance.get(), from_port_name.value().c_str(),
+ to_node_instance.get(), to_port_name.value().c_str());
+
+ m_port_instance_manager->link_port_instances(from_port_instance, to_port_instance);
+
+ return true;
+}
+
+void NodeInstanceManager::initialize() {
+}
+
+void NodeInstanceManager::deinitialize() {
+}
+
+void NodeInstanceManager::set_node_prototype_store(
+ std::shared_ptr<INodePrototypeStore> prototype_store) {
+ m_prototype_store = prototype_store;
+}
+
+void NodeInstanceManager::set_plugin_module_proxy_provider(
+ std::shared_ptr<IPluginModuleProxyProvider> plugin_module_proxy_provider) {
+ m_plugin_module_proxy_provider = plugin_module_proxy_provider;
+}
+
+void NodeInstanceManager::set_port_instance_manager(
+ std::shared_ptr<IPortInstanceManager> port_instance_manager) {
+ m_port_instance_manager = port_instance_manager;
+}
+
+void NodeInstanceManager::on_observer_event(
+ const PLUGIN_MODULE_EVENT_TYPE &event, std::any data) {
+ try {
+ if (event == PLUGIN_MODULE_EVENT_TYPE::OUTPUT_GENERATED) {
+ PluginModuleEventOutputGenerated *output_generated = std::any_cast<PluginModuleEventOutputGenerated*>(data);
+ if (output_generated) {
+ PortInstance *port_instance = reinterpret_cast<PortInstance*>(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);
+ }
+ }
+ }
+ } catch (const std::bad_any_cast &e) {
+ LOGE("Failed to cast message data: %s", e.what());
+ }
+}
+
+void NodeInstanceManager::on_observer_event(
+ const PROXY_FACTORY_EVENT_TYPE &event, std::any data) {
+ try {
+ if (event == PROXY_FACTORY_EVENT_TYPE::PROXY_CREATED) {
+ IPluginModuleProxy *proxy = std::any_cast<IPluginModuleProxy*>(data);
+ if (proxy) {
+ /* Add 'this' observer as a SimpleEventObserver<PLUGIN_MODULE_EVENT_TYPE> */
+ proxy->add_observer(this);
+ }
+ }
+ } catch (const std::bad_any_cast &e) {
+ LOGE("Failed to cast message data: %s", e.what());
+ }
+}
+
+} // namespace mmi
+
--- /dev/null
+/*
+* 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_NODE_INSTANCE_MANAGER_H__
+#define __MMI_NODE_INSTANCE_MANAGER_H__
+
+#include "mmi-plugin-module-event.h"
+#include "mmi-plugin-module-proxy.h"
+#include "mmi-node-instance.h"
+#include "mmi-node-prototype-manager.h"
+#include "mmi-port-instance-manager.h"
+
+#include <memory>
+#include <vector>
+
+namespace mmi {
+
+class INodeInstanceManager {
+public:
+ INodeInstanceManager() = default;
+ virtual ~INodeInstanceManager() = default;
+
+ virtual std::shared_ptr<NodeInstance> create_node_instance(
+ mmi_standard_node_type_e node_type,
+ mmi_standard_node_sub_type_e node_sub_type) = 0;
+ virtual bool destroy_node_instance(
+ std::shared_ptr<NodeInstance> node_instance) = 0;
+ virtual bool link_node_instances(
+ std::shared_ptr<NodeInstance> from_node_instance,
+ std::shared_ptr<NodeInstance> to_node_instance,
+ std::optional<std::string> from_port_name,
+ std::optional<std::string> to_port_name) = 0;
+};
+
+class NodeInstanceManager :
+ public INodeInstanceManager,
+ public SimpleEventObserver<PLUGIN_MODULE_EVENT_TYPE>,
+ public SimpleEventObserver<PROXY_FACTORY_EVENT_TYPE> {
+public:
+ NodeInstanceManager();
+ virtual ~NodeInstanceManager();
+
+ virtual std::shared_ptr<NodeInstance> create_node_instance(
+ mmi_standard_node_type_e node_type,
+ mmi_standard_node_sub_type_e node_sub_type) override;
+ virtual bool destroy_node_instance(
+ std::shared_ptr<NodeInstance> node_instance) override;
+ virtual bool link_node_instances(
+ std::shared_ptr<NodeInstance> from_node_instance,
+ std::shared_ptr<NodeInstance> to_node_instance,
+ std::optional<std::string> from_port_name,
+ std::optional<std::string> to_port_name) override;
+
+ void set_node_prototype_store(
+ std::shared_ptr<INodePrototypeStore> prototype_store);
+ void set_plugin_module_proxy_provider(
+ std::shared_ptr<IPluginModuleProxyProvider> plugin_module_proxy_provider);
+ void set_port_instance_manager(
+ std::shared_ptr<IPortInstanceManager> port_instance_manager);
+
+ void initialize();
+ void deinitialize();
+
+ void on_observer_event(
+ const PLUGIN_MODULE_EVENT_TYPE &event, std::any data) override;
+ void on_observer_event(
+ const PROXY_FACTORY_EVENT_TYPE &event, std::any data) override;
+
+protected:
+ std::shared_ptr<INodePrototypeStore> m_prototype_store;
+ std::shared_ptr<IPluginModuleProxyProvider> m_plugin_module_proxy_provider;
+ std::shared_ptr<IPortInstanceManager> m_port_instance_manager;
+
+ std::vector<std::shared_ptr<NodeInstance>> m_node_instances;
+};
+
+} // namespace mmi
+
+#endif //__MMI_NODE_INSTANCE_MANAGER_H__
+
+
--- /dev/null
+/*
+ * Copyright © 2021 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 "mmi-node-instance.h"
+
+#include "mmi-manager-log.h"
+
+namespace mmi {
+
+NodeInstance::NodeInstance(
+ mmi_standard_node_type_e node_type,
+ 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));
+}
+
+NodeInstance::~NodeInstance() {
+ _D("Node instance is destroyed : %d %d", m_node_type, to_int(m_node_sub_type));
+}
+
+static bool node_type_and_subtype_matches(
+ mmi_node_h node,
+ mmi_standard_node_type_e node_type,
+ mmi_standard_node_sub_type_e node_sub_type) {
+ mmi_standard_node_type_e type;
+ mmi_node_get_type(node, &type);
+
+ if (type != node_type) {
+ return false;
+ }
+
+ try {
+ if (node_type == MMI_STANDARD_NODE_TYPE_SOURCE) {
+ mmi_standard_node_source_type_e source_type;
+ mmi_standard_node_get_source_type(node, &source_type);
+ return source_type == std::get<mmi_standard_node_source_type_e>(node_sub_type);
+ } else if (node_type == MMI_STANDARD_NODE_TYPE_PROCESSOR) {
+ mmi_standard_node_processor_type_e processor_type;
+ mmi_standard_node_get_processor_type(node, &processor_type);
+ return processor_type == std::get<mmi_standard_node_processor_type_e>(node_sub_type);
+ } else if (node_type == MMI_STANDARD_NODE_TYPE_LOGIC) {
+ mmi_standard_node_logic_type_e logic_type;
+ mmi_standard_node_get_logic_type(node, &logic_type);
+ return logic_type == std::get<mmi_standard_node_logic_type_e>(node_sub_type);
+ } else if (node_type == MMI_STANDARD_NODE_TYPE_CONTROLLER) {
+ mmi_standard_node_controller_type_e controller_type;
+ mmi_standard_node_get_controller_type(node, &controller_type);
+ return controller_type == std::get<mmi_standard_node_controller_type_e>(node_sub_type);
+ }
+ } catch (const std::bad_variant_access &e) {
+ _E("Failed to get node sub type : %s", e.what());
+ }
+
+ return false;
+}
+
+
+
+bool NodeInstance::initialize() {
+ if (m_prototype_store == nullptr) {
+ _E("Node prototype store is not set");
+ return false;
+ }
+
+ m_prototype = m_prototype_store->get_node_prototype(m_node_type, m_node_sub_type);
+ if (m_prototype == nullptr) {
+ _E("Failed to get node prototype");
+ return false;
+ }
+
+ if (m_plugin_module_proxy_provider == nullptr) {
+ _E("Plugin module proxy provider is not set");
+ return false;
+ }
+
+ /* Owning this shared pointer guarantees that the callback functions are
+ * valid until the node instance is destroyed. */
+ m_plugin_module_proxy = m_plugin_module_proxy_provider->get_plugin_module_proxy(
+ m_prototype->get_plugin_module_info());
+
+ if (m_plugin_module_proxy == nullptr) {
+ _E("Failed to get plugin module proxy");
+ return false;
+ }
+
+ std::vector<mmi_port_h> ports;
+ size_t port_count = 0;
+
+ mmi_plugin_module_node_list_s node_list_s = m_plugin_module_proxy->load_node_prototypes();
+ for (int i = 0; i < node_list_s.node_count; i++) {
+ mmi_node_h node = node_list_s.nodes[i];
+ if (node_type_and_subtype_matches(node, m_node_type, m_node_sub_type)) {
+ mmi_node_get_callbacks(node, &m_callbacks);
+ mmi_node_get_port_count(node, &port_count);
+ for (size_t i = 0; i < port_count; i++) {
+ mmi_port_h port;
+ mmi_node_get_port(node, i, &port);
+ ports.push_back(port);
+ }
+ break;
+ }
+ }
+
+ _D("Node instance is initialized for %d %d",
+ m_node_type, to_int(m_node_sub_type));
+
+ if (m_port_instance_manager == nullptr) {
+ _E("Port instance manager is not set");
+ return false;
+ }
+
+ mmi_plugin_module_node_instance_info_s plugin_module_node_instance_info;
+ plugin_module_node_instance_info.node = static_cast<mmi_node_instance_h>(this);
+ plugin_module_node_instance_info.port_info_count = 0;
+
+ for (auto &port_info : m_prototype->get_port_infos()) {
+ std::shared_ptr<PortInstance> port_instance = m_port_instance_manager->create_port_instance();
+ if (port_instance == nullptr) {
+ _E("Failed to create port instance");
+ return false;
+ }
+ for (auto &port : ports) {
+ char *name = nullptr;
+ size_t name_length = 0;
+ mmi_port_get_name(port, &name, &name_length);
+
+ mmi_port_callbacks callbacks;
+ mmi_port_get_callbacks(port, &callbacks);
+
+ if (strncmp(name, port_info.name.c_str(), name_length) == 0) {
+ _D("Port instance is initialized for %s, %p %p", port_info.name.c_str(),
+ callbacks.output_format_requested_cb,
+ callbacks.input_data_received_cb);
+ port_instance->set_port_callbacks(callbacks);
+ break;
+ }
+ }
+
+ m_port_instances[port_info.name] = port_instance;
+
+ size_t index = plugin_module_node_instance_info.port_info_count;
+ plugin_module_node_instance_info.port_infos[index].port =
+ static_cast<mmi_port_instance_h>(port_instance.get());
+ strncpy(plugin_module_node_instance_info.port_infos[index].name,
+ port_info.name.c_str(), MMI_NAME_MAX_LENGTH - 1);
+ plugin_module_node_instance_info.port_infos[index].name[MMI_NAME_MAX_LENGTH - 1] = '\0';
+
+ plugin_module_node_instance_info.port_info_count++;
+ }
+
+ m_plugin_module_proxy->add_node_instance_info(&plugin_module_node_instance_info);
+
+ if (m_callbacks.initialized_cb != nullptr) {
+ m_callbacks.initialized_cb(static_cast<mmi_node_instance_h>(this));
+ }
+
+ return true;
+}
+
+bool NodeInstance::deinitialize() {
+ if (m_callbacks.deinitialized_cb != nullptr) {
+ m_callbacks.deinitialized_cb(static_cast<mmi_node_instance_h>(this));
+ }
+
+ m_plugin_module_proxy->remove_node_instance_info(static_cast<mmi_node_instance_h>(this));
+ return true;
+}
+
+void NodeInstance::set_node_prototype_store(
+ std::shared_ptr<INodePrototypeStore> prototype_store) {
+ m_prototype_store = prototype_store;
+}
+
+void NodeInstance::set_plugin_module_proxy_provider(
+ std::shared_ptr<IPluginModuleProxyProvider> plugin_module_proxy_provider) {
+ m_plugin_module_proxy_provider = plugin_module_proxy_provider;
+}
+
+void NodeInstance::set_port_instance_manager(
+ std::shared_ptr<IPortInstanceManager> port_instance_manager) {
+ m_port_instance_manager = port_instance_manager;
+}
+
+void NodeInstance::add_data_gateway(std::string port_name,
+ std::shared_ptr<DataGateway> gateway) {
+ try {
+ auto port = m_port_instances.at(port_name);
+ port->add_data_gateway(gateway);
+ } catch (const std::out_of_range &e) {
+ _E("Port instance is not found for %s, %s", port_name.c_str(), e.what());
+ }
+}
+
+mmi_standard_node_type_e NodeInstance::get_node_type() {
+ return m_node_type;
+}
+
+mmi_standard_node_sub_type_e NodeInstance::get_node_sub_type() {
+ return m_node_sub_type;
+}
+
+bool NodeInstance::activate() {
+ m_activated = true;
+ if (m_suspended) {
+ _D("Node instance is suspended, so the activated_cb is not called");
+ }
+ if (m_callbacks.activated_cb == nullptr) {
+ _E("Activate callback is not set");
+ return false;
+ }
+ m_callbacks.activated_cb(static_cast<mmi_node_instance_h>(this));
+ return true;
+}
+
+bool NodeInstance::deactivate() {
+ m_activated = false;
+ if (m_suspended) {
+ _D("Node instance is suspended, so the deactivated_cb is not called");
+ }
+ if (m_callbacks.deactivated_cb == nullptr) {
+ _E("Deactivate callback is not set");
+ return false;
+ }
+ m_callbacks.deactivated_cb(static_cast<mmi_node_instance_h>(this));
+ return true;
+}
+
+bool NodeInstance::suspend() {
+ m_suspended = true;
+ if (m_activated) {
+ if (m_callbacks.deactivated_cb != nullptr) {
+ m_callbacks.deactivated_cb(static_cast<mmi_node_instance_h>(this));
+ }
+ }
+ return true;
+}
+
+bool NodeInstance::resume() {
+ m_suspended = false;
+ if (m_activated) {
+ if (m_callbacks.activated_cb != nullptr) {
+ m_callbacks.activated_cb(static_cast<mmi_node_instance_h>(this));
+ }
+ }
+ return true;
+}
+
+std::shared_ptr<PortInstance> NodeInstance::get_port_instance(std::string name) {
+ auto it = m_port_instances.find(name);
+ if (it == m_port_instances.end()) {
+ _E("Port instance is not found : %s", name.c_str());
+ return nullptr;
+ }
+
+ return it->second;
+}
+
+std::shared_ptr<IPluginModuleProxy> NodeInstance::get_plugin_module_proxy() {
+ return m_plugin_module_proxy;
+}
+
+bool NodeInstance::set_attribute(mmi_attribute_h attribute)
+{
+ char *name = nullptr;
+ mmi_attribute_get_name(attribute, &name);
+ _D("Set attribute : %s [%p]", name, attribute);
+ free(name);
+
+ if (m_callbacks.attribute_set_cb == nullptr) {
+ _E("Set attribute callback is not set");
+ return false;
+ }
+ m_callbacks.attribute_set_cb(static_cast<mmi_node_instance_h>(this), attribute);
+ return true;
+}
+
+} // namespace mmi
+
+
--- /dev/null
+/*
+* 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_NODE_INSTANCE_H__
+#define __MMI_NODE_INSTANCE_H__
+
+#include "mmi-node.h"
+#include "mmi-node-prototype-manager.h"
+#include "mmi-plugin-module-proxy.h"
+#include "mmi-port-instance-manager.h"
+
+#include <map>
+#include <memory>
+
+namespace mmi {
+
+class NodeInstance {
+public:
+ NodeInstance(mmi_standard_node_type_e node_type,
+ mmi_standard_node_sub_type_e node_sub_type);
+ virtual ~NodeInstance();
+
+ bool initialize();
+ bool deinitialize();
+
+ void set_node_prototype_store(
+ std::shared_ptr<INodePrototypeStore> prototype_store);
+ void set_plugin_module_proxy_provider(
+ std::shared_ptr<IPluginModuleProxyProvider> plugin_module_proxy_provider);
+ void set_port_instance_manager(
+ std::shared_ptr<IPortInstanceManager> port_instance_manager);
+
+ void add_data_gateway(std::string port_name,
+ std::shared_ptr<DataGateway> gateway);
+
+ mmi_standard_node_type_e get_node_type();
+ mmi_standard_node_sub_type_e get_node_sub_type();
+
+ bool activate();
+ bool deactivate();
+
+ bool suspend();
+ bool resume();
+
+ std::shared_ptr<PortInstance> get_port_instance(std::string name);
+ std::shared_ptr<IPluginModuleProxy> get_plugin_module_proxy();
+
+ bool set_attribute(mmi_attribute_h attribute);
+protected:
+ std::shared_ptr<INodePrototypeStore> m_prototype_store;
+ std::shared_ptr<IPluginModuleProxyProvider> m_plugin_module_proxy_provider;
+ std::shared_ptr<IPortInstanceManager> m_port_instance_manager;
+
+ std::shared_ptr<NodePrototype> m_prototype;
+ std::shared_ptr<IPluginModuleProxy> m_plugin_module_proxy;
+ std::map<std::string, std::shared_ptr<PortInstance>> m_port_instances;
+
+ mmi_standard_node_type_e m_node_type;
+ mmi_standard_node_sub_type_e m_node_sub_type;
+
+ mmi_node_callbacks m_callbacks{nullptr,};
+
+ bool m_suspended{false};
+ bool m_activated{false};
+};
+
+} // namespace mmi
+
+#endif //__MMI_NODE_INSTANCE_H__
+
+
--- /dev/null
+/*
+ * Copyright © 2021 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 "mmi-node-prototype-manager.h"
+
+#include "mmi-manager-log.h"
+
+namespace mmi {
+
+NodePrototypeManager::NodePrototypeManager() {
+}
+
+NodePrototypeManager::~NodePrototypeManager() {
+}
+
+bool NodePrototypeManager::add_node_prototype(std::shared_ptr<NodePrototype> prototype) {
+ if (!prototype->is_valid()) {
+ _E("ERROR: invalid node prototype");
+ return false;
+ }
+
+ /* check if we already have a prototype with the same type and sub type */
+ for (auto& elem : m_prototypes) {
+ if (elem->get_type() == prototype->get_type() &&
+ elem->get_sub_type() == prototype->get_sub_type()) {
+ _E("ERROR: prototype with the same type / sub type already exists");
+ return false;
+ }
+ }
+
+ m_prototypes.push_back(prototype);
+
+ return true;
+}
+
+std::shared_ptr<NodePrototype> NodePrototypeManager::get_node_prototype(
+ mmi_standard_node_type_e type, mmi_standard_node_sub_type_e sub_type) {
+ std::shared_ptr<NodePrototype> ret;
+
+ for (auto& elem : m_prototypes) {
+ if (elem->get_type() == type && elem->get_sub_type() == sub_type) {
+ ret = elem;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void NodePrototypeManager::initialize() {
+}
+
+void NodePrototypeManager::deinitialize() {
+}
+
+} // namespace mmi
+
--- /dev/null
+/*
+* 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_NODE_PROTOTYPE_MANAGER_H__
+#define __MMI_NODE_PROTOTYPE_MANAGER_H__
+
+#include "mmi-node-prototype.h"
+
+#include <memory>
+#include <vector>
+
+namespace mmi {
+
+struct INodePrototypeStore {
+ virtual bool add_node_prototype(std::shared_ptr<NodePrototype> prototype) = 0;
+ virtual std::shared_ptr<NodePrototype> get_node_prototype(
+ mmi_standard_node_type_e type, mmi_standard_node_sub_type_e sub_type) = 0;
+};
+
+class NodePrototypeManager : public INodePrototypeStore {
+public:
+ NodePrototypeManager();
+ virtual ~NodePrototypeManager();
+
+ virtual bool add_node_prototype(std::shared_ptr<NodePrototype> prototype) override;
+ virtual std::shared_ptr<NodePrototype> get_node_prototype(
+ mmi_standard_node_type_e type, mmi_standard_node_sub_type_e sub_type) override;
+
+ void initialize();
+ void deinitialize();
+
+protected:
+ std::vector<std::shared_ptr<NodePrototype>> m_prototypes;
+};
+
+} // namespace mmi
+
+#endif //__MMI_NODE_PROTOTYPE_MANAGER_H__
+
+
--- /dev/null
+/*
+ * Copyright © 2021 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 "mmi-node-prototype.h"
+
+#include "mmi-manager-log.h"
+
+namespace mmi {
+
+NodePrototype::NodePrototype() {
+}
+
+NodePrototype::~NodePrototype() {
+}
+
+bool NodePrototype::is_valid() {
+ if (!m_type.has_value() || !m_sub_type.has_value()) {
+ _E("Failed to validate node prototype: type or sub type is empty");
+ return false;
+ }
+
+ bool valid = false;
+ /* Make sure that the m_sub_type is a valid match for m_type */
+ try {
+ switch (m_type.value()) {
+ case mmi_standard_node_type_e::MMI_STANDARD_NODE_TYPE_SOURCE: {
+ auto subclass =
+ std::get<mmi_standard_node_source_type_e>(m_sub_type.value());
+ valid = true;
+ }
+ break;
+ case mmi_standard_node_type_e::MMI_STANDARD_NODE_TYPE_PROCESSOR: {
+ auto subclass =
+ std::get<mmi_standard_node_processor_type_e>(m_sub_type.value());
+ valid = true;
+ }
+ break;
+ case mmi_standard_node_type_e::MMI_STANDARD_NODE_TYPE_LOGIC: {
+ auto subclass =
+ std::get<mmi_standard_node_logic_type_e>(m_sub_type.value());
+ valid = true;
+ }
+ break;
+ case mmi_standard_node_type_e::MMI_STANDARD_NODE_TYPE_CONTROLLER: {
+ auto subclass =
+ std::get<mmi_standard_node_controller_type_e>(m_sub_type.value());
+ valid = true;
+ }
+ }
+ } catch (const std::bad_variant_access& e) {
+ _E("[std::bad_variant_access] Failed to create node prototype: %s", e.what());
+ } catch (const std::bad_optional_access& e) {
+ _E("[std::bad_optional_access] Failed to create node prototype: %s", e.what());
+ }
+
+ if (get_plugin_module_info().plugin_module_identifier.empty()) {
+ _E("Failed to validate node prototype: plugin module info is empty");
+ valid = false;
+ }
+
+ return valid;
+}
+
+void NodePrototype::set_type(mmi_standard_node_type_e type) {
+ m_type = type;
+}
+
+void NodePrototype::set_sub_type(mmi_standard_node_sub_type_e sub_type) {
+ m_sub_type = sub_type;
+}
+
+bool NodePrototype::add_port_info(PortInfo &port_info) {
+ for (auto& port : m_port_infos) {
+ if (port.name == port_info.name) {
+ _E("Failed to add port info: port with the same name already exists");
+ return false;
+ }
+ }
+
+ m_port_infos.push_back(port_info);
+ return true;
+}
+
+bool NodePrototype::add_attribute_info(AttributeInfo &attribute_info) {
+ /* check if we already have an attribute with the same name */
+ for (auto& attribute : m_attribute_infos) {
+ if (attribute.name == attribute_info.name) {
+ _E("Failed to add attribute info: attribute with the same name already exists");
+ return false;
+ }
+ }
+
+ m_attribute_infos.push_back(attribute_info);
+ return true;
+}
+
+mmi_standard_node_type_e NodePrototype::get_type() {
+ mmi_standard_node_type_e ret = MMI_STANDARD_NODE_TYPE_NONE;
+ if (m_type.has_value()) {
+ ret = m_type.value();
+ }
+ return ret;
+}
+
+mmi_standard_node_sub_type_e NodePrototype::get_sub_type() {
+ mmi_standard_node_sub_type_e ret = std::monostate{};
+ if (m_sub_type.has_value()) {
+ ret = m_sub_type.value();
+ }
+ return ret;
+}
+
+std::vector<PortInfo> NodePrototype::get_port_infos() {
+ return m_port_infos;
+}
+
+std::vector<AttributeInfo> NodePrototype::get_attribute_infos() {
+ return m_attribute_infos;
+}
+
+bool NodePrototype::has_port_with_name(std::string name) {
+ for (auto& port : m_port_infos) {
+ if (port.name == name) {
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace mmi
+
--- /dev/null
+/*
+* 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_NODE_PROTOTYPE_H__
+#define __MMI_NODE_PROTOTYPE_H__
+
+#include "mmi-common.h"
+#include "mmi-node.h"
+#include "mmi-node-source.h"
+#include "mmi-node-processor.h"
+#include "mmi-node-logic.h"
+#include "mmi-node-controller.h"
+#include "mmi-plugin-module-proxy.h"
+
+#include <memory>
+#include <optional>
+#include <variant>
+#include <vector>
+
+namespace mmi {
+
+typedef std::variant<
+ std::monostate,
+ 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_sub_type_e;
+
+static int to_int(mmi_standard_node_sub_type_e sub_type) {
+ try {
+ return std::visit([](auto&& arg) -> int {
+ using T = std::decay_t<decltype(arg)>;
+ if constexpr (std::is_same_v<T, std::monostate>)
+ return -1;
+ else
+ return static_cast<int>(arg);
+ }, sub_type);
+ } catch (std::bad_variant_access&) {
+ return -1;
+ }
+}
+
+typedef struct {
+ std::string name;
+ mmi_port_type_e port_type;
+ mmi_data_type_e data_type;
+ std::string data_description;
+} PortInfo;
+
+typedef struct {
+ std::string name;
+ mmi_primitive_value_type_e value_type;
+} AttributeInfo;
+
+class NodePrototype {
+public:
+ NodePrototype();
+ virtual ~NodePrototype();
+
+ bool is_valid();
+
+ void set_plugin_module_info(PluginModuleInfo plugin_module_info) {
+ m_plugin_module_info = plugin_module_info;
+ }
+ PluginModuleInfo get_plugin_module_info() {
+ return m_plugin_module_info;
+ }
+
+ void set_type(mmi_standard_node_type_e type);
+ void set_sub_type(mmi_standard_node_sub_type_e sub_type);
+
+ bool add_port_info(PortInfo &port_info);
+ bool add_attribute_info(AttributeInfo &attribute_info);
+
+ mmi_standard_node_type_e get_type();
+ mmi_standard_node_sub_type_e get_sub_type();
+
+ std::vector<PortInfo> get_port_infos();
+ std::vector<AttributeInfo> get_attribute_infos();
+
+ bool has_port_with_name(std::string name);
+private:
+ PluginModuleInfo m_plugin_module_info;
+
+ std::optional<mmi_standard_node_type_e> m_type;
+ std::optional<mmi_standard_node_sub_type_e> m_sub_type;
+
+ std::vector<PortInfo> m_port_infos;
+ std::vector<AttributeInfo> m_attribute_infos;
+};
+
+} // namespace mmi
+
+#endif //__MMI_NODE_PROTOTYPE_H__
+
+
--- /dev/null
+/*
+ * 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 "mmi-plugin-module-proxy.h"
+#include "mmi-manager-log.h"
+
+#include <dlfcn.h>
+
+namespace mmi {
+
+static void port_instance_output_handler(mmi_port_instance_h port, mmi_data_h data, void *user_data) {
+ PluginModuleProxySharedLibrary* proxy = static_cast<PluginModuleProxySharedLibrary*>(user_data);
+ if (proxy == nullptr) {
+ _E("Invalid proxy");
+ return;
+ }
+
+ PluginModuleEventOutputGenerated event;
+ event.port_instance = port;
+ event.data = data;
+ proxy->notify_observers(PLUGIN_MODULE_EVENT_TYPE::OUTPUT_GENERATED, &event);
+}
+
+static void switch_node_event_handler(mmi_node_instance_h node, const char *controllee, bool state, void *user_data) {
+ PluginModuleProxySharedLibrary* proxy = static_cast<PluginModuleProxySharedLibrary*>(user_data);
+ if (proxy == nullptr) {
+ _E("Invalid proxy");
+ return;
+ }
+ if (controllee == nullptr) {
+ _E("Controllee is null");
+ return;
+ }
+
+ PluginModuleEventSwitchEventEmitted event;
+ event.node_instance = node;
+ event.controllee = controllee;
+ event.state = state;
+ proxy->notify_observers(PLUGIN_MODULE_EVENT_TYPE::SWITCH_EVENT_EMITTED, &event);
+}
+
+PluginModuleProxySharedLibrary::PluginModuleProxySharedLibrary(
+ const mmi_plugin_module_identifier plugin_module_identifier) :
+ m_plugin_module_identifier(plugin_module_identifier) {
+ mmi_plugin_module_event_handler_info_s module_event_handler_info{nullptr, };
+ module_event_handler_info.port_instance_output_handler = port_instance_output_handler;
+ module_event_handler_info.switch_node_event_handler = switch_node_event_handler;
+
+ /* FIXME : When there are more than one plugin module, the logic should be changed
+ * since the global event handler will be overwritten by the last plugin module.
+ * But the overwrite would not cause any problem for now, since the event handler
+ * will always have the pointer to the static function port_instance_output_handler(). */
+ mmi_plugin_storage_set_plugin_module_event_handler(module_event_handler_info, this);
+
+ m_shared_object_handle = dlopen(m_plugin_module_identifier.c_str(), RTLD_NOW);
+ if (!m_shared_object_handle) {
+ _E("Failed to load plugin module: %s", dlerror());
+ }
+}
+
+PluginModuleProxySharedLibrary::~PluginModuleProxySharedLibrary() {
+ if (m_shared_object_handle) dlclose(m_shared_object_handle);
+ m_shared_object_handle = nullptr;
+}
+
+function_pointer PluginModuleProxySharedLibrary::get_function(const std::string& function_name) {
+ return dlsym(m_shared_object_handle, function_name.c_str());
+}
+
+mmi_plugin_module_node_list_s PluginModuleProxySharedLibrary::load_node_prototypes() {
+ mmi_plugin_module_node_list_s node_list;
+ memset(&node_list, 0, sizeof(mmi_plugin_module_node_list_s));
+
+ mmi_plugin_storage_set_current_module_identifier(m_plugin_module_identifier.c_str());
+
+ function_pointer load_node_prototypes = get_function(MMI_PLUGIN_MODULE_GET_NODE_LIST_FUNC_NAME);
+ if (load_node_prototypes) {
+ auto func = (mmi_plugin_module_get_node_list_func)load_node_prototypes;
+ func();
+ } else {
+ _E("No prototype provider function exists for node prototypes : %s", m_plugin_module_identifier.c_str());
+ return node_list;
+ }
+
+ node_list = mmi_plugin_storage_get_node_list(m_plugin_module_identifier.c_str());
+
+ /* Dump node_list */
+ _D("node_list.count: %zu", node_list.node_count);
+ for (size_t i = 0;i < node_list.node_count;i++) {
+ mmi_node_h node = node_list.nodes[i];
+ mmi_standard_node_type_e type;
+ mmi_node_get_type(node, &type);
+ mmi_node_callbacks callbacks;
+ mmi_node_get_callbacks(node, &callbacks);
+ size_t port_count;
+ _D("node_info[%zu].type: %d", i, type);
+ _D("node_info[%zu].callbacks : %p %p %p %p %p %p", i,
+ callbacks.initialized_cb,
+ callbacks.deinitialized_cb,
+ callbacks.attribute_set_cb,
+ callbacks.activated_cb,
+ callbacks.deactivated_cb,
+ callbacks.signal_received_cb);
+ mmi_node_get_port_count(node, &port_count);
+ _D("node_info[%zu].port_list.count: %zu", i, port_count);
+ for (size_t j = 0;j < port_count;j++) {
+ mmi_port_h port;
+ mmi_node_get_port(node, j, &port);
+ char *name = nullptr;
+ size_t length = 0;
+ mmi_port_get_name(port, &name, &length);
+ mmi_port_type_e port_type;
+ mmi_port_get_type(port, &port_type);
+ mmi_data_type_e data_type;
+ mmi_port_get_data_type(port, &data_type);
+ mmi_port_callbacks port_callbacks;
+ mmi_port_get_callbacks(port, &port_callbacks);
+ _D("node_info[%zu].port_info[%zu].name: %s", i, j, name);
+ _D("node_info[%zu].port_info[%zu].type: %d", i, j, port_type);
+ _D("node_info[%zu].port_info[%zu].data_type: %d", i, j, data_type);
+ _D("node_info[%zu].port_info[%zu].callbacks: %p %p", i, j,
+ port_callbacks.output_format_requested_cb,
+ port_callbacks.input_data_received_cb);
+ }
+ }
+ return node_list;
+}
+
+mmi_plugin_module_workflow_list_s PluginModuleProxySharedLibrary::load_workflow_prototypes() {
+ mmi_plugin_module_workflow_list_s workflow_list;
+ memset(&workflow_list, 0, sizeof(mmi_plugin_module_workflow_list_s));
+
+ mmi_plugin_storage_set_current_module_identifier(m_plugin_module_identifier.c_str());
+
+ function_pointer load_workflow_prototypes = get_function(MMI_PLUGIN_MODULE_GET_WORKFLOW_LIST_FUNC_NAME);
+ if (load_workflow_prototypes) {
+ auto func = (mmi_plugin_module_get_workflow_list_func)load_workflow_prototypes;
+ func();
+ } else {
+ _E("No prototype provider function exists for workflow prototypes : %s", m_plugin_module_identifier.c_str());
+ return workflow_list;
+ }
+
+ workflow_list = mmi_plugin_storage_get_workflow_list(m_plugin_module_identifier.c_str());
+
+ /* Dump workflow_list */
+ _D("workflow_list.count: %zu", workflow_list.workflow_count);
+ for (size_t i = 0;i < workflow_list.workflow_count;i++) {
+ mmi_workflow_h workflow = workflow_list.workflows[i];
+ mmi_workflow_s *workflow_info = static_cast<mmi_workflow_s*>(workflow);
+ mmi_standard_workflow_type_e type;
+ mmi_workflow_get_type(workflow, &type);
+ _D("workflow_info[%zu].type: %d", i, type);
+
+ _D("workflow_info[%zu].node_info_count: %zu", i, workflow_info->node_info_count);
+ for (size_t j = 0;j < workflow_info->node_info_count;j++) {
+ mmi_workflow_node_info_s *node_info = &(workflow_info->node_infos[j]);
+ mmi_standard_node_type_e type;
+ mmi_node_get_type(workflow_info->node_infos[j].node, &type);
+ _D("workflow_info[%zu].node_info[%zu].name: %s", i, j, node_info->name);
+ _D("workflow_info[%zu].node_info[%zu].type: %d", i, j, type);
+ }
+
+ _D("workflow_info[%zu].link_info_count: %zu", i, workflow_info->link_info_count);
+ for (size_t j = 0;j < workflow_info->link_info_count;j++) {
+ mmi_workflow_link_info_s *link_info = &(workflow_info->link_infos[j]);
+ _D("workflow_info[%zu].link_info[%zu].from_node_name: %s", i, j, link_info->from_node_name);
+ _D("workflow_info[%zu].link_info[%zu].from_port_name: %s", i, j, link_info->from_port_name);
+ _D("workflow_info[%zu].link_info[%zu].to_node_name: %s", i, j, link_info->to_node_name);
+ _D("workflow_info[%zu].link_info[%zu].to_port_name: %s", i, j, link_info->to_port_name);
+ }
+
+ _D("workflow_info[%zu].output_assignment_info_count: %zu", i, workflow_info->output_assignment_info_count);
+ for (size_t j = 0;j < workflow_info->output_assignment_info_count;j++) {
+ mmi_workflow_output_assignment_info_s *output_assignment_info = &(workflow_info->output_assignment_infos[j]);
+ _D("workflow_info[%zu].output_assignment_info[%zu].output_name: %s", i, j, output_assignment_info->output_name);
+ _D("workflow_info[%zu].output_assignment_info[%zu].from_node_name: %s", i, j, output_assignment_info->from_node_name);
+ _D("workflow_info[%zu].output_assignment_info[%zu].from_port_name: %s", i, j, output_assignment_info->from_port_name);
+ }
+ }
+ return workflow_list;
+}
+
+void PluginModuleProxySharedLibrary::add_node_instance_info(mmi_plugin_module_node_instance_info_s *node_instance_info) {
+ mmi_plugin_storage_add_node_instance_info(node_instance_info);
+}
+
+void PluginModuleProxySharedLibrary::remove_node_instance_info(mmi_node_instance_h node_instance) {
+ mmi_plugin_storage_remove_node_instance_info(node_instance);
+}
+
+} // namespace mmi
+
--- /dev/null
+/*
+* 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_PLUGIN_MODULE_PROXY_H__
+#define __MMI_PLUGIN_MODULE_PROXY_H__
+
+#include <filesystem>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "mmi-common.h"
+#include "mmi-plugin-module.h"
+#include "mmi-plugin-module-event.h"
+#include "mmi-plugin-storage.h"
+
+#include "mmi.h"
+
+namespace mmi {
+
+typedef void* function_pointer;
+
+typedef std::string mmi_plugin_module_identifier;
+
+enum class mmi_plugin_module_type_e {
+ SELF_CONTAINED = 0,
+ SHARED_LIBRARY,
+};
+
+typedef struct {
+ mmi_plugin_module_type_e plugin_module_type;
+ mmi_plugin_module_identifier plugin_module_identifier;
+} PluginModuleInfo;
+
+struct IPluginModuleProxy : public SimpleEventObservable<PLUGIN_MODULE_EVENT_TYPE> {
+ IPluginModuleProxy() = default;
+ virtual ~IPluginModuleProxy() = default;
+ virtual function_pointer get_function(const std::string& function_name) = 0;
+
+ virtual mmi_plugin_module_node_list_s load_node_prototypes() = 0;
+ virtual mmi_plugin_module_workflow_list_s load_workflow_prototypes() = 0;
+
+ virtual void add_node_instance_info(mmi_plugin_module_node_instance_info_s *node_instance_info) = 0;
+ virtual void remove_node_instance_info(mmi_node_instance_h node_instance) = 0;
+};
+
+struct IPluginModuleProxyProvider {
+ virtual std::shared_ptr<IPluginModuleProxy> get_plugin_module_proxy(
+ const PluginModuleInfo plugin_module_info) = 0;
+};
+
+class PluginModuleProxySharedLibrary : public IPluginModuleProxy {
+public:
+ PluginModuleProxySharedLibrary(const mmi_plugin_module_identifier plugin_module_identifier);
+ virtual ~PluginModuleProxySharedLibrary();
+
+ virtual function_pointer get_function(const std::string& function_name) override;
+
+ virtual mmi_plugin_module_node_list_s load_node_prototypes() override;
+ virtual mmi_plugin_module_workflow_list_s load_workflow_prototypes() override;
+
+ virtual void add_node_instance_info(mmi_plugin_module_node_instance_info_s *node_instance_info) override;
+ virtual void remove_node_instance_info(mmi_node_instance_h node_instance) override;
+private:
+ const mmi_plugin_module_identifier m_plugin_module_identifier;
+
+ void* m_shared_object_handle{nullptr};
+};
+
+enum class PROXY_FACTORY_EVENT_TYPE {
+ PROXY_CREATED,
+};
+
+struct IPluginModuleProxyFactory : public SimpleEventObservable<PROXY_FACTORY_EVENT_TYPE> {
+ virtual std::vector<PluginModuleInfo> get_plugin_module_list() = 0;
+ virtual std::shared_ptr<IPluginModuleProxy> create(
+ PluginModuleInfo plugin_module_info) = 0;
+};
+
+class PluginModuleProxyFactoryDefault : public IPluginModuleProxyFactory {
+public:
+ virtual std::vector<PluginModuleInfo> get_plugin_module_list() override {
+ const std::string plugin_module_path{"/usr/share/mmi/plugins"};
+ std::vector<PluginModuleInfo> 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()};
+ plugin_module_list.push_back(info);
+ }
+ return plugin_module_list;
+ }
+ virtual std::shared_ptr<IPluginModuleProxy> create(
+ PluginModuleInfo plugin_module_info) override {
+ if (plugin_module_info.plugin_module_type == mmi_plugin_module_type_e::SHARED_LIBRARY) {
+ auto proxy = std::make_shared<PluginModuleProxySharedLibrary>(
+ plugin_module_info.plugin_module_identifier);
+ notify_observers(PROXY_FACTORY_EVENT_TYPE::PROXY_CREATED, static_cast<IPluginModuleProxy*>(proxy.get()));
+ return proxy;
+ }
+ return std::shared_ptr<IPluginModuleProxy>();
+ }
+};
+
+} // namespace mmi
+
+#endif //__MMI_PLUGIN_MODULE_PROXY_H__
+
+
--- /dev/null
+/*
+ * Copyright © 2021 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 "mmi-plugin-module-registry.h"
+#include "mmi-manager-log.h"
+
+namespace mmi {
+
+PluginModuleRegistry::PluginModuleRegistry() {
+ _D("PluginModuleRegistry is created");
+}
+
+PluginModuleRegistry::~PluginModuleRegistry() {
+ _D("PluginModuleRegistry is destroyed");
+}
+
+void PluginModuleRegistry::initialize() {
+ if (!m_factory) {
+ _E("Plugin module proxy factory is not set");
+ return;
+ }
+
+ load_node_prototypes();
+ load_workflow_prototypes();
+}
+
+void PluginModuleRegistry::deinitialize() {
+}
+
+void PluginModuleRegistry::set_plugin_module_proxy_factory(std::shared_ptr<IPluginModuleProxyFactory> factory) {
+ m_factory = factory;
+}
+
+void PluginModuleRegistry::set_node_prototype_store(std::shared_ptr<INodePrototypeStore> node_prototype_store) {
+ m_node_prototype_store = node_prototype_store;
+}
+
+void PluginModuleRegistry::set_workflow_prototype_store(std::shared_ptr<IWorkflowPrototypeStore> workflow_prototype_store) {
+ m_workflow_prototype_store = workflow_prototype_store;
+}
+
+/* FIXME : Check if this function needs to be moved to INodePrototypeStore */
+static std::shared_ptr<NodePrototype> create_node_prototype(mmi_node_h node) {
+ if (!node) {
+ _E("Invalid argument");
+ return nullptr;
+ }
+
+ auto prototype = std::make_shared<NodePrototype>();
+
+ if (prototype) {
+ mmi_standard_node_type_e type;
+ mmi_node_get_type(node, &type);
+
+ prototype->set_type(type);
+ switch (type) {
+ case MMI_STANDARD_NODE_TYPE_SOURCE: {
+ mmi_standard_node_source_type_e source_type;
+ mmi_standard_node_get_source_type(node, &source_type);
+ prototype->set_sub_type(source_type);
+ break;
+ }
+ case MMI_STANDARD_NODE_TYPE_PROCESSOR: {
+ mmi_standard_node_processor_type_e processor_type;
+ mmi_standard_node_get_processor_type(node, &processor_type);
+ prototype->set_sub_type(processor_type);
+ break;
+ }
+ case MMI_STANDARD_NODE_TYPE_LOGIC: {
+ mmi_standard_node_logic_type_e logic_type;
+ mmi_standard_node_get_logic_type(node, &logic_type);
+ prototype->set_sub_type(logic_type);
+ break;
+ }
+ case MMI_STANDARD_NODE_TYPE_CONTROLLER: {
+ mmi_standard_node_controller_type_e controller_type;
+ mmi_standard_node_get_controller_type(node, &controller_type);
+ prototype->set_sub_type(controller_type);
+ break;
+ }
+ }
+
+ size_t port_count;
+ mmi_node_get_port_count(node, &port_count);
+ for (size_t i = 0; i < port_count; i++) {
+ mmi_port_h port;
+ mmi_node_get_port(node, i, &port);
+
+ char *name = nullptr;
+ size_t name_length = 0;
+ mmi_port_get_name(port, &name, &name_length);
+
+ mmi_port_type_e type;
+ mmi_port_get_type(port, &type);
+
+ mmi_data_type_e data_type;
+ mmi_port_get_data_type(port, &data_type);
+
+ PortInfo port_info;
+ port_info.name = name;
+ port_info.port_type = type;
+ port_info.data_type = data_type;
+ prototype->add_port_info(port_info);
+ }
+ } else {
+ _E("Failed to create node prototype");
+ }
+
+ return prototype;
+}
+
+bool PluginModuleRegistry::load_node_prototypes() {
+ if (!m_node_prototype_store) {
+ _E("Node prototype store is not set");
+ return false;
+ }
+
+ std::vector<PluginModuleInfo> plugin_module_list = m_factory->get_plugin_module_list();
+ for (auto& plugin_module_info : plugin_module_list) {
+ std::shared_ptr<IPluginModuleProxy> ptr =
+ get_plugin_module_proxy(plugin_module_info);
+ if (ptr) {
+ mmi_plugin_module_node_list_s node_list = ptr->load_node_prototypes();
+ for (size_t i = 0; i < node_list.node_count; i++) {
+ auto prototype = create_node_prototype(node_list.nodes[i]);
+ 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());
+ }
+ }
+ } else {
+ _E("Failed to get plugin module: %s", plugin_module_info.plugin_module_identifier.c_str());
+ }
+ }
+
+ return true;
+}
+
+/* FIXME : Check if this function needs to be moved to IWorkflowPrototypeStore */
+static std::shared_ptr<WorkflowPrototype> create_workflow_prototype(mmi_workflow_h workflow) {
+ if (!workflow) {
+ _E("Invalid argument");
+ return nullptr;
+ }
+
+ auto prototype = std::make_shared<WorkflowPrototype>();
+
+ if (prototype) {
+ mmi_standard_workflow_type_e type;
+ mmi_workflow_get_type(workflow, &type);
+
+ prototype->set_type(type);
+
+ mmi_workflow_s *workflow_info = static_cast<mmi_workflow_s*>(workflow);
+ for (size_t i = 0; i < workflow_info->node_info_count; i++) {
+ NodeInfo node_info;
+ node_info.name = workflow_info->node_infos[i].name;
+ mmi_node_get_type(workflow_info->node_infos[i].node, &node_info.node_type);
+ switch (node_info.node_type) {
+ case MMI_STANDARD_NODE_TYPE_SOURCE: {
+ mmi_standard_node_source_type_e source_type;
+ mmi_standard_node_get_source_type(workflow_info->node_infos[i].node, &source_type);
+ node_info.node_sub_type = source_type;
+ }
+ break;
+ case MMI_STANDARD_NODE_TYPE_PROCESSOR: {
+ mmi_standard_node_processor_type_e processor_type;
+ mmi_standard_node_get_processor_type(workflow_info->node_infos[i].node, &processor_type);
+ node_info.node_sub_type = processor_type;
+ }
+ break;
+ case MMI_STANDARD_NODE_TYPE_LOGIC: {
+ mmi_standard_node_logic_type_e logic_type;
+ mmi_standard_node_get_logic_type(workflow_info->node_infos[i].node, &logic_type);
+ node_info.node_sub_type = logic_type;
+ }
+ break;
+ case MMI_STANDARD_NODE_TYPE_CONTROLLER: {
+ mmi_standard_node_controller_type_e controller_type;
+ mmi_standard_node_get_controller_type(workflow_info->node_infos[i].node, &controller_type);
+ node_info.node_sub_type = controller_type;
+ }
+ break;
+ default: {
+ _E("Invalid node type");
+ return nullptr;
+ }
+ }
+
+ prototype->add_node_info(node_info);
+ }
+
+ for (size_t i = 0; i < workflow_info->link_info_count; i++) {
+ LinkInfo link_info;
+ link_info.from_node_name = workflow_info->link_infos[i].from_node_name;
+ link_info.from_port_name = workflow_info->link_infos[i].from_port_name;
+ link_info.to_node_name = workflow_info->link_infos[i].to_node_name;
+ link_info.to_port_name = workflow_info->link_infos[i].to_port_name;
+
+ prototype->add_link_info(link_info);
+ }
+
+ for (size_t i = 0; i < workflow_info->attribute_assignment_info_count; i++) {
+ AttributeAssignmentInfo attribute_assignment_info;
+ attribute_assignment_info.attribute_name = workflow_info->attribute_assignment_infos[i].attribute_name;
+ attribute_assignment_info.target_node_name = workflow_info->attribute_assignment_infos[i].target_node_name;
+ attribute_assignment_info.target_attribute_name = workflow_info->attribute_assignment_infos[i].target_attribute_name;
+
+ prototype->add_attribute_assignment_info(attribute_assignment_info);
+ }
+
+ for (size_t i = 0; i < workflow_info->attribute_default_value_info_count; i++) {
+ AttributeDefaultValueInfo attribute_default_value_info;
+ mmi_attribute_h default_value = nullptr;
+ int ret = mmi_attribute_from_bytes(
+ workflow_info->attribute_default_value_infos[i].serialized_default_value,
+ workflow_info->attribute_default_value_infos[i].serialized_default_value_size,
+ &default_value);
+ if (MMI_ERROR_NONE != ret) {
+ _E("Failed to create attribute from bytes");
+ }
+ attribute_default_value_info.default_value = default_value;
+
+ prototype->add_attribute_default_value_info(attribute_default_value_info);
+ }
+
+ for (size_t i = 0; i < workflow_info->output_assignment_info_count; i++) {
+ OutputAssignmentInfo output_assignment_info;
+ output_assignment_info.output_name = workflow_info->output_assignment_infos[i].output_name;
+ output_assignment_info.from_node_name = workflow_info->output_assignment_infos[i].from_node_name;
+ output_assignment_info.from_port_name = workflow_info->output_assignment_infos[i].from_port_name;
+
+ prototype->add_output_assignment_info(output_assignment_info);
+ }
+ } else {
+ _E("Failed to create workflow prototype");
+ }
+
+ return prototype;
+}
+
+bool PluginModuleRegistry::load_workflow_prototypes() {
+ if (!m_workflow_prototype_store) {
+ _E("Workflow prototype store is not set");
+ return false;
+ }
+
+ std::vector<PluginModuleInfo> plugin_module_list = m_factory->get_plugin_module_list();
+ for (auto& plugin_module_info : plugin_module_list) {
+ std::shared_ptr<IPluginModuleProxy> ptr =
+ get_plugin_module_proxy(plugin_module_info);
+ if (ptr) {
+ mmi_plugin_module_workflow_list_s workflow_list = ptr->load_workflow_prototypes();
+ for (size_t i = 0; i < workflow_list.workflow_count; i++) {
+ auto prototype = create_workflow_prototype(workflow_list.workflows[i]);
+ if (prototype) {
+ prototype->set_plugin_module_info(plugin_module_info);
+ m_workflow_prototype_store->add_workflow_prototype(prototype);
+ }
+ }
+ } else {
+ _E("Failed to get plugin module: %s", plugin_module_info.plugin_module_identifier.c_str());
+ }
+ }
+
+ return true;
+}
+
+std::shared_ptr<IPluginModuleProxy> PluginModuleRegistry::get_plugin_module_proxy(
+ const PluginModuleInfo plugin_module_info) {
+ plugin_module_map_key key(
+ plugin_module_info.plugin_module_type, plugin_module_info.plugin_module_identifier);
+ auto it = m_plugin_modules.find(key);
+ if (it != m_plugin_modules.end()) {
+ auto plugin_module = it->second.lock();
+ if (plugin_module) {
+ return plugin_module;
+ } else {
+ _D("Plugin module proxy is expired: %d %s",
+ static_cast<int>(plugin_module_info.plugin_module_type),
+ plugin_module_info.plugin_module_identifier.c_str());
+ }
+ }
+
+ if (!m_factory) {
+ _E("Plugin module proxy factory is not set");
+ return nullptr;
+ }
+
+ _D("Create plugin module proxy: %d %s",
+ static_cast<int>(plugin_module_info.plugin_module_type),
+ plugin_module_info.plugin_module_identifier.c_str());
+
+ auto plugin_module = m_factory->create(plugin_module_info);
+ if (plugin_module) {
+ m_plugin_modules[key] = plugin_module;
+ }
+
+ return plugin_module;
+}
+
+} // namespace mmi
+
--- /dev/null
+/*
+* 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_PLUGIN_MODULE_REGISTRY_H__
+#define __MMI_PLUGIN_MODULE_REGISTRY_H__
+
+#include "mmi.h"
+#include "mmi-common.h"
+#include "mmi-plugin-module-proxy.h"
+#include "mmi-manager-log.h"
+#include "mmi-plugin-module.h"
+#include "mmi-node-prototype-manager.h"
+#include "mmi-workflow-prototype-manager.h"
+
+#include <map>
+#include <memory>
+#include <vector>
+
+namespace mmi {
+
+class PluginModuleRegistry : public IPluginModuleProxyProvider {
+public:
+ PluginModuleRegistry();
+ virtual ~PluginModuleRegistry();
+
+ void initialize();
+ void deinitialize();
+
+ void set_plugin_module_proxy_factory(std::shared_ptr<IPluginModuleProxyFactory> factory);
+ void set_node_prototype_store(std::shared_ptr<INodePrototypeStore> node_prototype_store);
+ void set_workflow_prototype_store(std::shared_ptr<IWorkflowPrototypeStore> workflow_prototype_store);
+
+ bool load_node_prototypes();
+ bool load_workflow_prototypes();
+
+ std::shared_ptr<IPluginModuleProxy> get_plugin_module_proxy(
+ const PluginModuleInfo plugin_module_info) override;
+protected:
+ std::shared_ptr<IPluginModuleProxyFactory> m_factory;
+
+ std::shared_ptr<INodePrototypeStore> m_node_prototype_store;
+ std::shared_ptr<IWorkflowPrototypeStore> m_workflow_prototype_store;
+
+ typedef std::pair<mmi_plugin_module_type_e, std::string> plugin_module_map_key;
+ std::map<plugin_module_map_key, std::weak_ptr<IPluginModuleProxy>> m_plugin_modules;
+};
+
+} // namespace mmi
+
+#endif //__MMI_PLUGIN_MODULE_REGISTRY_H__
+
+
--- /dev/null
+/*
+ * Copyright © 2021 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 "mmi-port-instance-manager.h"
+
+#include "mmi-manager-log.h"
+
+namespace mmi {
+
+PortInstanceManager::PortInstanceManager() {
+}
+
+PortInstanceManager::~PortInstanceManager() {
+}
+
+std::shared_ptr<PortInstance> PortInstanceManager::create_port_instance() {
+ std::shared_ptr<PortInstance> port_instance = std::make_shared<PortInstance>();
+ m_port_instances.push_back(port_instance);
+ return port_instance;
+}
+
+bool PortInstanceManager::destroy_port_instance(
+ std::shared_ptr<PortInstance> port_instance) {
+ for (auto it = m_port_instances.begin(); it != m_port_instances.end(); ++it) {
+ if (*it == port_instance) {
+ m_port_instances.erase(it);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool PortInstanceManager::link_port_instances(
+ std::shared_ptr<PortInstance> out_port,
+ std::shared_ptr<PortInstance> in_port) {
+ out_port->add_linked_port_instance(in_port);
+ in_port->add_linked_port_instance(out_port);
+ return true;
+}
+
+} // namespace mmi
+
--- /dev/null
+/*
+* 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_PORT_INSTANCE_MANAGER_H__
+#define __MMI_PORT_INSTANCE_MANAGER_H__
+
+#include "mmi-port-instance.h"
+
+#include <memory>
+#include <vector>
+
+namespace mmi {
+
+class IPortInstanceManager {
+public:
+ IPortInstanceManager() = default;
+ virtual ~IPortInstanceManager() = default;
+
+ virtual std::shared_ptr<PortInstance> create_port_instance() = 0;
+ virtual bool destroy_port_instance(
+ std::shared_ptr<PortInstance> port_instance) = 0;
+ virtual bool link_port_instances(
+ std::shared_ptr<PortInstance> out_port,
+ std::shared_ptr<PortInstance> in_port) = 0;
+};
+
+class PortInstanceManager : public IPortInstanceManager {
+public:
+ PortInstanceManager();
+ virtual ~PortInstanceManager();
+
+ virtual std::shared_ptr<PortInstance> create_port_instance() override;
+ virtual bool destroy_port_instance(
+ std::shared_ptr<PortInstance> port_instance) override;
+ virtual bool link_port_instances(
+ std::shared_ptr<PortInstance> out_port,
+ std::shared_ptr<PortInstance> in_port) override;
+
+ void initialize();
+ void deinitialize();
+
+protected:
+ std::vector<std::shared_ptr<PortInstance>> m_port_instances;
+};
+
+} // namespace mmi
+
+#endif //__MMI_PORT_INSTANCE_MANAGER_H__
+
+
--- /dev/null
+/*
+ * Copyright © 2021 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 "mmi-port-instance.h"
+
+#include "mmi-manager-log.h"
+
+namespace mmi {
+
+PortInstance::PortInstance() {
+ _D("PortInstance created : %p", this);
+}
+
+PortInstance::~PortInstance() {
+}
+
+void PortInstance::set_port_callbacks(mmi_port_callbacks callbacks) {
+ _D("PortInstance[%p] set_port_callbacks : %p %p", this,
+ callbacks.output_format_requested_cb, callbacks.input_data_received_cb);
+ m_callbacks = callbacks;
+}
+
+void PortInstance::add_data_gateway(std::shared_ptr<DataGateway> gateway) {
+ _D("PortInstance[%p] add_data_gateway : %p", this, gateway.get());
+ m_data_gateways.push_back(gateway);
+}
+
+void PortInstance::add_linked_port_instance(std::shared_ptr<PortInstance> port_instance) {
+ m_linked_port_instances.push_back(port_instance);
+}
+
+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);
+ }
+
+ for (auto it = m_linked_port_instances.begin(); it != m_linked_port_instances.end(); ++it) {
+ (*it)->on_output_data_received(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<mmi_port_instance_h>(this), data);
+ }
+}
+
+} // namespace mmi
+
--- /dev/null
+/*
+* 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_PORT_INSTANCE_H__
+#define __MMI_PORT_INSTANCE_H__
+
+#include "mmi.h"
+#include "mmi-port.h"
+#include "mmi-data-gateway.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace mmi {
+
+class PortInstance {
+public:
+ PortInstance();
+ virtual ~PortInstance();
+
+ void set_port_callbacks(mmi_port_callbacks callbacks);
+
+ void add_linked_port_instance(std::shared_ptr<PortInstance> port_instance);
+ void add_data_gateway(std::shared_ptr<DataGateway> gateway);
+
+ /* Output data was generated by a Node module */
+ void on_output_data_generated(mmi_data_h data);
+
+ /* An output data generated by a different Node module was received through a link */
+ void on_output_data_received(mmi_data_h data);
+private:
+ std::string m_name;
+ mmi_port_callbacks m_callbacks{nullptr,};
+
+ std::vector<std::shared_ptr<PortInstance>> m_linked_port_instances;
+ std::vector<std::shared_ptr<DataGateway>> m_data_gateways;
+};
+
+} // namespace mmi
+
+#endif //__MMI_PORT_INSTANCE_H__
+
+
--- /dev/null
+/*
+ * 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 "mmi-self-container.h"
+#include "mmi-port-instance-manager.h"
+
+#include <map>
+
+namespace mmi {
+
+std::map<mmi_port_instance_h, mmi_plugin_module_node_instance_info_s> g_node_instance_info_map;
+
+TestNodePluginModule::TestNodePluginModule() {
+ default_node_callbacks.initialized_cb = node_initialized_cb;
+ default_node_callbacks.deinitialized_cb = node_deinitialized_cb;
+ default_node_callbacks.attribute_set_cb = node_attribute_set_cb;
+ default_node_callbacks.activated_cb = node_activated_cb;
+ default_node_callbacks.deactivated_cb = node_deactivated_cb;
+ default_node_callbacks.signal_received_cb = node_signal_received_cb;
+
+ default_port_callbacks.output_format_requested_cb = port_output_format_requested_cb;
+ default_port_callbacks.input_data_received_cb = port_input_data_received_cb;
+}
+
+TestNodePluginModule::~TestNodePluginModule() {
+}
+
+int TestNodePluginModule::node_initialized_cb(mmi_node_instance_h instance) {
+ _D("Node initialize callback is called for %p", instance);
+ return MMI_ERROR_NONE;
+}
+
+int TestNodePluginModule::node_deinitialized_cb(mmi_node_instance_h instance) {
+ _D("Node deinitialize callback is called for %p", instance);
+ return MMI_ERROR_NONE;
+}
+
+int TestNodePluginModule::node_attribute_set_cb(mmi_node_instance_h instance, mmi_attribute_h attribute) {
+ _D("Node attribute set callback is called for %p", instance);
+ return MMI_ERROR_NONE;
+}
+
+int TestNodePluginModule::node_activated_cb(mmi_node_instance_h instance) {
+ _D("Node activate callback is called for %p", instance);
+ return MMI_ERROR_NONE;
+}
+
+int TestNodePluginModule::node_deactivated_cb(mmi_node_instance_h instance) {
+ _D("Node deactivate callback is called for %p", instance);
+ return MMI_ERROR_NONE;
+}
+
+int TestNodePluginModule::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;
+}
+
+int TestNodePluginModule::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;
+}
+int TestNodePluginModule::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;
+}
+
+TestNodePluginModuleMIC::TestNodePluginModuleMIC() {
+ m_node_callbacks = default_node_callbacks;
+ m_node_callbacks.activated_cb = node_activated_cb;
+ m_audio_port_callbacks = default_port_callbacks;
+}
+
+int TestNodePluginModuleMIC::node_activated_cb(mmi_node_instance_h instance) {
+ _D("[MIC] Node activate callback is called for %p", instance);
+
+ /* In shared object plugin module, the output data can be generated using the API
+ mmi_port_instance_output_generate() function, after finding the port using
+ the API mmi_node_instance_port_find. However, in this test plugin module, calling
+ mmi library API is not allowed. So, we have to find the output port using
+ the port instance map. */
+
+ std::string output_port_name{"AUDIO"};
+ mmi_port_instance_h output_port = nullptr;
+ for (const auto &elem : g_node_instance_info_map) {
+ const mmi_plugin_module_node_instance_info_s &node_instance_info = elem.second;
+ if (node_instance_info.node == instance) {
+ for (size_t i = 0; i < node_instance_info.port_info_count; ++i) {
+ if (output_port_name.compare(std::string(node_instance_info.port_infos[i].name)) == 0) {
+ _D("[MIC] Found output port %p", node_instance_info.port_infos[i].port);
+ output_port = node_instance_info.port_infos[i].port;
+ break;
+ }
+ }
+ }
+ }
+
+ auto plugin_module = reinterpret_cast<TestNodePluginModuleMIC*>(instance);
+
+ int value = 100;
+ mmi_data_h output_data = reinterpret_cast<mmi_data_h>(&value);
+
+ PortInstance *port_instance = reinterpret_cast<PortInstance*>(output_port);
+ if (port_instance) {
+ _D("[MIC] Generating an output %d to %p", value, port_instance);
+ port_instance->on_output_data_generated(output_data);
+ }
+
+ return MMI_ERROR_NONE;
+}
+
+TestNodePluginModuleASR::TestNodePluginModuleASR() {
+ m_node_callbacks = default_node_callbacks;
+ m_audio_port_callbacks = default_port_callbacks;
+ m_audio_port_callbacks.input_data_received_cb = audio_port_input_data_received_cb;
+}
+
+int TestNodePluginModuleASR::audio_port_input_data_received_cb(mmi_port_instance_h instance, mmi_data_h data) {
+ /* In shared object plugin module, the output port can be found using the API
+ mmi_node_instance_sibling_port_find() function. However, in this test
+ plugin module, calling mmi library API is not allowed. So, we have to find the
+ output port using the node instance info map. */
+ std::string output_port_name{"FINAL_RESULT"};
+ mmi_port_instance_h output_port = nullptr;
+ const mmi_plugin_module_node_instance_info_s &node_instance_info = g_node_instance_info_map[instance];
+ for (size_t i = 0; i < node_instance_info.port_info_count; ++i) {
+ if (output_port_name.compare(std::string(node_instance_info.port_infos[i].name)) == 0) {
+ output_port = node_instance_info.port_infos[i].port;
+ break;
+ }
+ }
+
+ int value = -1;
+ int *ptr = reinterpret_cast<int*>(data);
+ if (ptr) value = *ptr;
+
+ _D("[ASR] Audio input data callback is called: %p %d", instance, value);
+
+ value++;
+ ptr = &value;
+
+ mmi_data_h output_data = reinterpret_cast<mmi_data_h>(ptr);
+
+ /* In shared object plugin module, the output data can be generated using the API
+ mmi_port_instance_output_generate() function. However, in this test plugin module,
+ calling mmi library API is not allowed. So, we have to generate the output
+ using the port instance handle directly. */
+
+ PortInstance *port_instance = reinterpret_cast<PortInstance*>(output_port);
+ if (port_instance) {
+ _D("[ASR] Generating an output %d to %p", value, port_instance);
+ port_instance->on_output_data_generated(output_data);
+ }
+
+ return MMI_ERROR_NONE;
+}
+
+int TestNodePluginModuleMatch::text_port_input_data_received_cb(mmi_port_instance_h instance, mmi_data_h data) {
+ /* In shared object plugin module, the output port can be found using the API
+ mmi_node_instance_sibling_port_find() function. However, in this test
+ plugin module, calling mmi library API is not allowed. So, we have to find the
+ output port using the node instance info map. */
+
+ std::string output_port_name{"MATCHED_CANDIDATE"};
+ mmi_port_instance_h output_port = nullptr;
+ const mmi_plugin_module_node_instance_info_s &node_instance_info = g_node_instance_info_map[instance];
+ for (size_t i = 0; i < node_instance_info.port_info_count; ++i) {
+ if (output_port_name.compare(std::string(node_instance_info.port_infos[i].name)) == 0) {
+ output_port = node_instance_info.port_infos[i].port;
+ break;
+ }
+ }
+
+ int value = -1;
+ int *ptr = reinterpret_cast<int*>(data);
+ if (ptr) value = *ptr;
+
+ _D("[Match] Text input data callback is called: %p %d", instance, value);
+
+ value++;
+ ptr = &value;
+
+ mmi_data_h output_data = reinterpret_cast<mmi_data_h>(ptr);
+
+ /* In shared object plugin module, the output data can be generated using the API
+ mmi_port_instance_output_generate() function. However, in this test plugin module,
+ calling mmi library API is not allowed. So, we have to generate the output
+ using the port instance handle directly. */
+
+ PortInstance *port_instance = reinterpret_cast<PortInstance*>(output_port);
+ if (port_instance) {
+ _D("[Match] Generating an output %d to %p", value, port_instance);
+ port_instance->on_output_data_generated(output_data);
+ }
+
+ return MMI_ERROR_NONE;
+}
+
+TestNodePluginModuleMatch::TestNodePluginModuleMatch() {
+ m_node_callbacks = default_node_callbacks;
+ m_text_port_callbacks = default_port_callbacks;
+ m_text_port_callbacks.input_data_received_cb = text_port_input_data_received_cb;
+}
+
+PluginModuleProxySelfContainerTest::PluginModuleProxySelfContainerTest() {
+}
+
+PluginModuleProxySelfContainerTest::~PluginModuleProxySelfContainerTest() {
+}
+
+function_pointer PluginModuleProxySelfContainerTest::get_function(const std::string& function_name) {
+ return nullptr;
+}
+
+mmi_plugin_module_node_list_s PluginModuleProxySelfContainerTest::load_node_prototypes() {
+ _D("Loading node prototypes from self-contained test plugin module");
+
+ /* Self-contained port information */
+
+ 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, m_node_mic.m_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, m_node_mic.m_node_callbacks);
+ mmi_node_register(mic_node);
+
+ mmi_node_destroy(mic_node);
+
+ mmi_port_h asr_audio_port = nullptr;
+ mmi_port_create(&asr_audio_port);
+ mmi_port_set_name(asr_audio_port, "AUDIO");
+ mmi_port_set_type(asr_audio_port, MMI_PORT_TYPE_IN);
+ mmi_port_set_data_type(asr_audio_port, MMI_DATA_TYPE_AUDIO);
+ mmi_port_set_callbacks(asr_audio_port, m_node_asr.m_audio_port_callbacks);
+
+ mmi_port_h asr_partial_result_port = nullptr;
+ mmi_port_create(&asr_partial_result_port);
+ mmi_port_set_name(asr_partial_result_port, "PARTIAL_RESULT");
+ mmi_port_set_type(asr_partial_result_port, MMI_PORT_TYPE_OUT);
+ mmi_port_set_data_type(asr_partial_result_port, MMI_DATA_TYPE_TEXT);
+ mmi_port_set_callbacks(asr_partial_result_port, m_node_asr.m_audio_port_callbacks);
+
+ mmi_port_h asr_final_result_port = nullptr;
+ mmi_port_create(&asr_final_result_port);
+ mmi_port_set_name(asr_final_result_port, "FINAL_RESULT");
+ mmi_port_set_type(asr_final_result_port, MMI_PORT_TYPE_OUT);
+ mmi_port_set_data_type(asr_final_result_port, MMI_DATA_TYPE_TEXT);
+ mmi_port_set_callbacks(asr_final_result_port, m_node_asr.m_audio_port_callbacks);
+
+ mmi_node_h asr_node = nullptr;
+ mmi_standard_node_create_processor(MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR, &asr_node);
+ mmi_node_add_port(asr_node, asr_audio_port);
+ mmi_node_add_port(asr_node, asr_partial_result_port);
+ mmi_node_add_port(asr_node, asr_final_result_port);
+ mmi_node_set_callbacks(asr_node, m_node_asr.m_node_callbacks);
+ mmi_node_register(asr_node);
+
+ mmi_node_destroy(asr_node);
+
+ mmi_port_h match_text_port = nullptr;
+ mmi_port_create(&match_text_port);
+ mmi_port_set_name(match_text_port, "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, m_node_match.m_text_port_callbacks);
+
+ mmi_port_h match_candidate_port = nullptr;
+ mmi_port_create(&match_candidate_port);
+ mmi_port_set_name(match_candidate_port, "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_set_callbacks(match_candidate_port, m_node_match.m_text_port_callbacks);
+
+ 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_set_callbacks(match_node, m_node_match.m_node_callbacks);
+ mmi_node_register(match_node);
+
+ mmi_node_destroy(match_node);
+
+ const char *identifier = mmi_plugin_storage_get_current_module_identifier();
+ mmi_plugin_module_node_list_s list = mmi_plugin_storage_get_node_list(identifier);
+
+ return list;
+}
+
+mmi_plugin_module_workflow_list_s PluginModuleProxySelfContainerTest::load_workflow_prototypes() {
+ _D("Loading workflow prototypes from self-contained test plugin module");
+
+ mmi_workflow_h workflow = nullptr;
+ mmi_workflow_create(&workflow);
+
+ mmi_workflow_set_type(workflow, MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND);
+
+ mmi_node_h node_mic = nullptr;
+ mmi_standard_node_create_source(MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT, &node_mic);
+ mmi_workflow_node_add(workflow, "MIC", node_mic);
+
+ mmi_node_h node_asr = nullptr;
+ mmi_standard_node_create_processor(MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR, &node_asr);
+ mmi_workflow_node_add(workflow, "ASR", node_asr);
+
+ mmi_node_h node_match = nullptr;
+ mmi_standard_node_create_logic(MMI_STANDARD_NODE_LOGIC_TYPE_FIXED_STRING_MATCH, &node_match);
+ mmi_workflow_node_add(workflow, "MATCH", node_match);
+
+ mmi_workflow_link_nodes_by_names(workflow, "MIC", "AUDIO", "ASR", "AUDIO");
+ mmi_workflow_link_nodes_by_names(workflow, "ASR", "FINAL_RESULT", "MATCH", "TEXT");
+
+ mmi_workflow_output_assign(workflow, "OUTPUT", "MATCH", "MATCHED_CANDIDATE");
+
+ mmi_standard_workflow_register(workflow);
+
+ mmi_node_destroy(node_match);
+ mmi_node_destroy(node_asr);
+ mmi_node_destroy(node_mic);
+
+ mmi_workflow_destroy(workflow);
+
+ const char *identifier = mmi_plugin_storage_get_current_module_identifier();
+ mmi_plugin_module_workflow_list_s list = mmi_plugin_storage_get_workflow_list(identifier);
+
+ return list;
+}
+
+void PluginModuleProxySelfContainerTest::add_node_instance_info(mmi_plugin_module_node_instance_info_s *node_instance_info) {
+ for (size_t i = 0; i < node_instance_info->port_info_count; i++) {
+ g_node_instance_info_map[node_instance_info->port_infos[i].port] = *node_instance_info;
+ }
+}
+
+void PluginModuleProxySelfContainerTest::remove_node_instance_info(mmi_node_instance_h node_instance) {
+ for (auto it = g_node_instance_info_map.begin(); it != g_node_instance_info_map.end();) {
+ if (it->second.node == node_instance) {
+ it = g_node_instance_info_map.erase(it);
+ } else {
+ it++;
+ }
+ }
+}
+
+} // namespace mmi
+
--- /dev/null
+/*
+* 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_SELF_CONTAINER__
+#define __MMI_SELF_CONTAINER__
+
+#include "mmi-plugin-module-proxy.h"
+#include "mmi-manager-log.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+/* This file is for testing purpose only */
+
+namespace mmi {
+
+class PluginModuleProxySelfContainerTest;
+
+struct TestWorkflowPluginModule {
+};
+
+class TestNodePluginModule {
+public:
+ TestNodePluginModule();
+ virtual ~TestNodePluginModule();
+
+ static int node_initialized_cb(mmi_node_instance_h instance);
+ static int node_deinitialized_cb(mmi_node_instance_h instance);
+ static int node_attribute_set_cb(mmi_node_instance_h instance, mmi_attribute_h attribute);
+ static int node_activated_cb(mmi_node_instance_h instance);
+ static int node_deactivated_cb(mmi_node_instance_h instance);
+ static int node_signal_received_cb(mmi_node_instance_h instance, mmi_signal_h signal);
+ static int port_output_format_requested_cb(mmi_port_instance_h instance, const char *format);
+ static int port_input_data_received_cb(mmi_port_instance_h instance, mmi_data_h data);
+
+ mmi_node_callbacks default_node_callbacks;
+ mmi_port_callbacks default_port_callbacks;
+};
+
+class TestWorkflowPluginModuleWakeuplessCommand : TestWorkflowPluginModule {
+
+};
+
+class TestNodePluginModuleMIC : public TestNodePluginModule {
+public:
+ TestNodePluginModuleMIC();
+ static int node_activated_cb(mmi_node_instance_h instance);
+
+ mmi_node_callbacks m_node_callbacks;
+ mmi_port_callbacks m_audio_port_callbacks;
+};
+
+class TestNodePluginModuleASR : public TestNodePluginModule {
+public:
+ TestNodePluginModuleASR();
+
+ static int audio_port_input_data_received_cb(mmi_port_instance_h instance, mmi_data_h data);
+
+ mmi_node_callbacks m_node_callbacks;
+ mmi_port_callbacks m_audio_port_callbacks;
+};
+
+class TestNodePluginModuleMatch : public TestNodePluginModule {
+public:
+ TestNodePluginModuleMatch();
+
+ static int text_port_input_data_received_cb(mmi_port_instance_h instance, mmi_data_h data);
+
+ mmi_node_callbacks m_node_callbacks;
+ mmi_port_callbacks m_text_port_callbacks;
+};
+
+class PluginModuleProxySelfContainerTest : public IPluginModuleProxy {
+public:
+ PluginModuleProxySelfContainerTest();
+ virtual ~PluginModuleProxySelfContainerTest();
+
+ virtual function_pointer get_function(const std::string& function_name) override;
+
+ virtual mmi_plugin_module_node_list_s load_node_prototypes() override;
+ virtual mmi_plugin_module_workflow_list_s load_workflow_prototypes() override;
+
+ virtual void add_node_instance_info(mmi_plugin_module_node_instance_info_s *node_instance_info) override;
+ virtual void remove_node_instance_info(mmi_node_instance_h node_instance) override;
+
+private:
+ TestWorkflowPluginModuleWakeuplessCommand m_workflow_wakeupless_command;
+ TestNodePluginModuleMIC m_node_mic;
+ TestNodePluginModuleASR m_node_asr;
+ TestNodePluginModuleMatch m_node_match;
+};
+
+class PluginModuleProxyFactorySelfContainerTest : public IPluginModuleProxyFactory {
+public:
+ virtual std::vector<PluginModuleInfo> get_plugin_module_list() override {
+ std::vector<PluginModuleInfo> plugin_module_list;
+ PluginModuleInfo item{mmi_plugin_module_type_e::SELF_CONTAINED, "self-container-test"};
+ plugin_module_list.push_back(item);
+ return plugin_module_list;
+ }
+ virtual std::shared_ptr<IPluginModuleProxy> create(
+ PluginModuleInfo plugin_module_info) override {
+ return std::make_shared<PluginModuleProxySelfContainerTest>();
+ }
+};
+
+} // namespace mmi
+
+#endif //__MMI_SELF_CONTAINER__
+
+
--- /dev/null
+/*
+ * Copyright © 2021 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 "mmi-workflow-instance-manager.h"
+
+#include "mmi-manager-log.h"
+
+namespace mmi {
+
+WorkflowInstanceManager::WorkflowInstanceManager() {
+}
+
+WorkflowInstanceManager::~WorkflowInstanceManager() {
+ deinitialize();
+}
+
+void WorkflowInstanceManager::initialize() {
+}
+
+void WorkflowInstanceManager::deinitialize() {
+ m_workflow_instances.clear();
+
+ m_node_instance_manager.reset();
+ m_prototype_store.reset();
+}
+
+void WorkflowInstanceManager::set_workflow_prototype_store(
+ std::shared_ptr<IWorkflowPrototypeStore> prototype_store) {
+ m_prototype_store = prototype_store;
+}
+
+void WorkflowInstanceManager::set_plugin_module_proxy_provider(
+ std::shared_ptr<IPluginModuleProxyProvider> plugin_module_proxy_provider) {
+ m_plugin_module_proxy_provider = plugin_module_proxy_provider;
+}
+
+void WorkflowInstanceManager::set_node_instance_manager(
+ std::shared_ptr<INodeInstanceManager> node_instance_manager) {
+ m_node_instance_manager = node_instance_manager;
+}
+
+std::shared_ptr<WorkflowInstance> WorkflowInstanceManager::get_workflow_instance(
+ std::string client_id, int local_workflow_instance_id) {
+ for (auto &instance : m_workflow_instances) {
+ if (instance->get_client_id() == client_id &&
+ instance->get_local_workflow_instance_id() == local_workflow_instance_id) {
+ return instance;
+ }
+ }
+
+ return nullptr;
+}
+
+void WorkflowInstanceManager::on_observer_event(
+ const COMMUNICATION_CHANNEL_EVENT_TYPE &event, std::any data) {
+ try {
+ if (event == COMMUNICATION_CHANNEL_EVENT_TYPE::CONNECTED) {
+ std::string client_id = std::any_cast<std::string>(data);
+ handle_client_connected(client_id);
+ } else if (event == COMMUNICATION_CHANNEL_EVENT_TYPE::DISCONNECTED) {
+ std::string client_id = std::any_cast<std::string>(data);
+ handle_client_disconnected(client_id);
+ } else if (event == COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED) {
+ Message *message = std::any_cast<Message*>(data);
+ if (message->message_group == MESSAGE_GROUP::CLIENT) {
+ handle_client_message(static_cast<ClientMessage*>(message));
+ }
+ }
+ } catch (const std::bad_any_cast &e) {
+ LOGE("Failed to cast message data: %s", e.what());
+ }
+}
+
+void WorkflowInstanceManager::handle_client_message(ClientMessage *message) {
+ if (nullptr == message) {
+ LOGE("Message is null");
+ return;
+ }
+
+ switch(message->message_type) {
+ case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_CREATE: {
+ auto *msg = static_cast<ClientMessageWorkflowInstanceCreate*>(message);
+ handle_create(msg);
+ }
+ break;
+ case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_DESTROY: {
+ auto *msg = static_cast<ClientMessageWorkflowInstanceDestroy*>(message);
+ handle_destroy(msg);
+ }
+ break;
+ case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_SET_ATTRIBUTE: {
+ auto *msg = static_cast<ClientMessageWorkflowInstanceSetAttribute*>(message);
+ handle_set_attribute(msg);
+ }
+ break;
+ case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_ACTIVATE: {
+ auto *msg = static_cast<ClientMessageWorkflowInstanceActivate*>(message);
+ handle_activate(msg);
+ }
+ break;
+ case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_DEACTIVATE: {
+ auto *msg = static_cast<ClientMessageWorkflowInstanceDeactivate*>(message);
+ handle_deactivate(msg);
+ }
+ break;
+ }
+}
+
+void WorkflowInstanceManager::handle_client_connected(std::string client_id) {
+ LOGD("%s connected", client_id.c_str());
+}
+
+void WorkflowInstanceManager::handle_client_disconnected(std::string client_id) {
+ LOGD("%s disconnected", client_id.c_str());
+
+ auto it = m_workflow_instances.begin();
+ while (it != m_workflow_instances.end()) {
+ if ((*it)->get_client_id() == client_id) {
+ (*it)->deinitialize();
+ it = m_workflow_instances.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+
+void WorkflowInstanceManager::handle_create(
+ ClientMessageWorkflowInstanceCreate *message) {
+ if (nullptr == message) {
+ LOGE("Message is null");
+ return;
+ }
+
+ std::shared_ptr<WorkflowInstance> instance =
+ get_workflow_instance(message->sender, message->local_workflow_instance_id);
+ if (instance) {
+ LOGE("Workflow instance already exists");
+ return;
+ }
+
+ if (nullptr == m_prototype_store) {
+ LOGE("Workflow prototype store is not set");
+ return;
+ }
+
+ if (nullptr == m_node_instance_manager) {
+ LOGE("Node instance manager is not set");
+ return;
+ }
+
+ instance = std::make_shared<WorkflowInstance>();
+ if (instance) {
+ instance->set_client_id(message->sender);
+ instance->set_local_workflow_instance_id(message->local_workflow_instance_id);
+ instance->set_type(message->workflow_type);
+
+ instance->set_workflow_prototype_store(m_prototype_store);
+ instance->set_plugin_module_proxy_provider(m_plugin_module_proxy_provider);
+ instance->set_node_instance_manager(m_node_instance_manager);
+
+ instance->initialize();
+
+ m_workflow_instances.push_back(instance);
+
+ WorkflowEventWorkflowCreated event;
+ event.workflow_instance = instance;
+ notify_observers(WORKFLOW_EVENT_TYPE::WORKFLOW_CREATED, &event);
+ } else {
+ LOGE("Failed to create workflow instance");
+ }
+}
+
+void WorkflowInstanceManager::handle_destroy(
+ ClientMessageWorkflowInstanceDestroy *message) {
+ if (nullptr == message) {
+ LOGE("Message is null");
+ return;
+ }
+
+ std::shared_ptr<WorkflowInstance> instance =
+ get_workflow_instance(message->sender, message->local_workflow_instance_id);
+ if (instance) {
+ instance->deinitialize();
+ }
+
+ auto it = m_workflow_instances.begin();
+ while (it != m_workflow_instances.end()) {
+ if ((*it)->get_client_id() == message->sender &&
+ (*it)->get_local_workflow_instance_id() == message->local_workflow_instance_id) {
+ it = m_workflow_instances.erase(it);
+ } else {
+ ++it;
+ }
+ }
+}
+
+void WorkflowInstanceManager::handle_set_attribute(
+ ClientMessageWorkflowInstanceSetAttribute *message) {
+ if (nullptr == message) {
+ LOGE("Message is null");
+ return;
+ }
+
+ std::shared_ptr<WorkflowInstance> instance =
+ get_workflow_instance(message->sender, message->local_workflow_instance_id);
+ if (instance) {
+ instance->set_attribute(message->attribute);
+ }
+}
+
+void WorkflowInstanceManager::handle_activate(
+ ClientMessageWorkflowInstanceActivate *message) {
+ if (nullptr == message) {
+ LOGE("Message is null");
+ return;
+ }
+
+ std::shared_ptr<WorkflowInstance> instance =
+ get_workflow_instance(message->sender, message->local_workflow_instance_id);
+ if (instance) {
+ instance->activate();
+ }
+}
+
+void WorkflowInstanceManager::handle_deactivate(
+ ClientMessageWorkflowInstanceDeactivate *message) {
+ if (nullptr == message) {
+ LOGE("Message is null");
+ return;
+ }
+
+ std::shared_ptr<WorkflowInstance> instance =
+ get_workflow_instance(message->sender, message->local_workflow_instance_id);
+ if (instance) {
+ instance->deactivate();
+ }
+}
+
+} // namespace mmi
+
--- /dev/null
+/*
+* 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_WORKFLOW_INSTANCE_MANAGER_H__
+#define __MMI_WORKFLOW_INSTANCE_MANAGER_H__
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "mmi-communication-channel.h"
+#include "mmi-event-observer.h"
+#include "mmi-node-instance-manager.h"
+#include "mmi-plugin-module-proxy.h"
+#include "mmi-workflow-instance.h"
+#include "mmi-workflow-prototype-manager.h"
+#include "mmi-workflow-event.h"
+
+namespace mmi {
+
+using namespace communication;
+
+class WorkflowInstanceManager :
+ public SimpleEventObserver<COMMUNICATION_CHANNEL_EVENT_TYPE>,
+ public SimpleEventObservable<WORKFLOW_EVENT_TYPE> {
+public:
+ WorkflowInstanceManager();
+ virtual ~WorkflowInstanceManager();
+
+ void initialize();
+ void deinitialize();
+
+ void set_workflow_prototype_store(
+ std::shared_ptr<IWorkflowPrototypeStore> prototype_store);
+ void set_plugin_module_proxy_provider(
+ std::shared_ptr<IPluginModuleProxyProvider> plugin_module_proxy_provider);
+ void set_node_instance_manager(
+ std::shared_ptr<INodeInstanceManager> node_instance_manager);
+
+ std::shared_ptr<WorkflowInstance> get_workflow_instance(
+ std::string client_id, int local_workflow_instance_id);
+
+ void on_observer_event(
+ const COMMUNICATION_CHANNEL_EVENT_TYPE &event, std::any data) override;
+
+private:
+ void handle_client_message(ClientMessage *message);
+
+ void handle_client_connected(std::string client_id);
+ void handle_client_disconnected(std::string client_id);
+
+ void handle_create(ClientMessageWorkflowInstanceCreate *message);
+ void handle_destroy(ClientMessageWorkflowInstanceDestroy *message);
+ void handle_set_attribute(ClientMessageWorkflowInstanceSetAttribute *message);
+ void handle_activate(ClientMessageWorkflowInstanceActivate *message);
+ void handle_deactivate(ClientMessageWorkflowInstanceDeactivate *message);
+protected:
+ std::shared_ptr<IWorkflowPrototypeStore> m_prototype_store;
+ std::shared_ptr<IPluginModuleProxyProvider> m_plugin_module_proxy_provider;
+ std::shared_ptr<INodeInstanceManager> m_node_instance_manager;
+
+ std::vector<std::shared_ptr<WorkflowInstance>> m_workflow_instances;
+};
+
+} // namespace mmi
+
+#endif //__MMI_WORKFLOW_INSTANCE_MANAGER_H__
+
--- /dev/null
+/*
+ * 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 "mmi-workflow-instance.h"
+#include "mmi-manager-log.h"
+#include "mmi-workflow-output-event.h"
+
+#include <bundle.h>
+namespace mmi {
+
+WorkflowInstance::WorkflowInstance() {
+}
+
+WorkflowInstance::~WorkflowInstance() {
+}
+
+void WorkflowInstance::set_client_id(std::string client_id) {
+ m_client_id = client_id;
+}
+
+std::string WorkflowInstance::get_client_id() {
+ return m_client_id;
+}
+
+void WorkflowInstance::set_local_workflow_instance_id(int local_workflow_instance_id) {
+ m_local_workflow_instance_id = local_workflow_instance_id;
+}
+
+int WorkflowInstance::get_local_workflow_instance_id() {
+ return m_local_workflow_instance_id;
+}
+
+void WorkflowInstance::set_type(mmi_standard_workflow_type_e type) {
+ m_type = type;
+}
+
+mmi_standard_workflow_type_e WorkflowInstance::get_type() {
+ return m_type;
+}
+
+void WorkflowInstance::set_workflow_prototype_store(
+ std::shared_ptr<IWorkflowPrototypeStore> prototype_store) {
+ m_prototype_store = prototype_store;
+}
+
+void WorkflowInstance::set_plugin_module_proxy_provider(
+ std::shared_ptr<IPluginModuleProxyProvider> plugin_module_proxy_provider) {
+ m_plugin_module_proxy_provider = plugin_module_proxy_provider;
+}
+
+void WorkflowInstance::set_node_instance_manager(
+ std::shared_ptr<INodeInstanceManager> node_instance_manager) {
+ m_node_instance_manager = node_instance_manager;
+}
+
+
+void WorkflowInstance::initialize() {
+ if (WORKFLOW_INSTANCE_STATE::NONE != m_state) {
+ _E("Workflow instance state is not NONE");
+ return;
+ }
+
+ if (nullptr == m_prototype_store) {
+ _E("Workflow prototype store is not set");
+ return;
+ }
+
+ if (nullptr == m_node_instance_manager) {
+ _E("Node instance manager is not set");
+ return;
+ }
+
+ if (nullptr == m_plugin_module_proxy_provider) {
+ _E("Plugin module proxy provider is not set");
+ return;
+ }
+
+ std::shared_ptr<WorkflowPrototype> prototype = m_prototype_store->get_workflow_prototype(m_type);
+ if (nullptr == prototype) {
+ _E("Could not find prototype information from store");
+ return;
+ }
+
+ /* Owning this shared pointer guarantees that the callback functions are
+ * valid until the node instance is destroyed. */
+ m_plugin_module_proxy = m_plugin_module_proxy_provider->get_plugin_module_proxy(
+ prototype->get_plugin_module_info());
+
+ /* Create node instances based on prototype information */
+ std::vector<NodeInfo> node_infos = prototype->get_node_infos();
+ for (auto &node_info : node_infos) {
+ std::shared_ptr<NodeInstance> node_instance =
+ m_node_instance_manager->create_node_instance(
+ node_info.node_type, node_info.node_sub_type);
+ if (nullptr == node_instance) {
+ _E("Failed to create node instance : %s", node_info.name.c_str());
+ } else {
+ m_node_instances[node_info.name] = node_instance;
+ _D("Created node instance : %s(%p)",
+ node_info.name.c_str(), node_instance.get());
+ /* Listen to plugin module events */
+ std::shared_ptr<IPluginModuleProxy> proxy = node_instance->get_plugin_module_proxy();
+ if (proxy) {
+ proxy->add_observer(this);
+ }
+ }
+ }
+
+ std::vector<LinkInfo> link_infos = prototype->get_link_infos();
+ for (auto &link_info : link_infos) {
+ try {
+ std::shared_ptr<NodeInstance> from_node_instance =
+ m_node_instances.at(link_info.from_node_name);
+ std::shared_ptr<NodeInstance> to_node_instance =
+ m_node_instances.at(link_info.to_node_name);
+
+ _D("Linking two nodes : %s(%p) -> %s(%p)",
+ link_info.from_node_name.c_str(), from_node_instance.get(),
+ link_info.to_node_name.c_str(), to_node_instance.get());
+ m_node_instance_manager->link_node_instances(
+ from_node_instance, to_node_instance,
+ link_info.from_port_name, link_info.to_port_name);
+ } catch (std::out_of_range& e) {
+ _E("Failed to find node instance : %s -> %s",
+ link_info.from_node_name.c_str(), link_info.to_node_name.c_str());
+ }
+ }
+
+ std::vector<OutputAssignmentInfo> output_assignment_infos =
+ prototype->get_output_assignment_infos();
+
+ for (auto &output_assignment_info : output_assignment_infos) {
+ try {
+ std::shared_ptr<NodeInstance> from_node_instance =
+ m_node_instances.at(output_assignment_info.from_node_name);
+
+ std::shared_ptr<DataGateway> output_data_gateway =
+ std::make_shared<DataGateway>(output_assignment_info.output_name);
+
+
+ _D("Adding Gateway : node(%s), port(%s) -> output name(%s)",
+ output_assignment_info.from_node_name.c_str(),
+ output_assignment_info.from_port_name.c_str(),
+ output_assignment_info.output_name.c_str());
+
+ 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);
+
+ WorkflowOutputEventOutputGenerated event;
+ event.source_name = name;
+ event.data = encoded;
+ event.client_id = get_client_id();
+ event.local_workflow_instance_id = get_local_workflow_instance_id();
+ this->notify_observers(WORKFLOW_OUTPUT_EVENT_TYPE::OUTPUT_GENERATED, &event);
+ };
+ output_data_gateway->set_callback(callback);
+
+ m_data_gateways.push_back(output_data_gateway);
+
+ from_node_instance->add_data_gateway(
+ output_assignment_info.from_port_name,
+ output_data_gateway);
+ } catch (std::out_of_range& e) {
+ _E("Failed to find node instance : %s",
+ output_assignment_info.from_node_name.c_str());
+ }
+ }
+
+ for (auto &node_instance : m_node_instances) {
+ _D("Node instance in m_node_instances : %s(%p)",
+ node_instance.first.c_str(), node_instance.second.get());
+ }
+
+ set_attribute_default_values();
+
+ m_state = WORKFLOW_INSTANCE_STATE::INITIALIZED;
+}
+
+void WorkflowInstance::deinitialize() {
+ /* If the workflow instance is running, stop it first */
+ if (WORKFLOW_INSTANCE_STATE::ACTIVATED == m_state) {
+ deactivate();
+ }
+ if (WORKFLOW_INSTANCE_STATE::INITIALIZED != m_state) {
+ _E("Workflow instance state is not INITIALIZED");
+ return;
+ }
+
+ for (auto &node_instance : m_node_instances) {
+ std::shared_ptr<IPluginModuleProxy> proxy = (node_instance.second)->get_plugin_module_proxy();
+ if (proxy) {
+ proxy->remove_observer(this);
+ }
+ m_node_instance_manager->destroy_node_instance(node_instance.second);
+ }
+ m_node_instances.clear();
+}
+
+void WorkflowInstance::activate() {
+ if (WORKFLOW_INSTANCE_STATE::INITIALIZED != m_state) {
+ _E("Workflow instance state is not INITIALIZED");
+ return;
+ }
+
+ _D("Activating workflow instance");
+
+ for (auto &node_instance : m_node_instances) {
+ _D("Activating node instance : %s(%p)",
+ node_instance.first.c_str(), node_instance.second.get());
+ (node_instance.second)->activate();
+ }
+
+ m_state = WORKFLOW_INSTANCE_STATE::ACTIVATED;
+}
+
+void WorkflowInstance::deactivate() {
+ if (WORKFLOW_INSTANCE_STATE::ACTIVATED != m_state) {
+ _E("Workflow instance state is not ACTIVATED");
+ return;
+ }
+
+ _D("Deactivating workflow instance");
+
+ for (auto &node_instance : m_node_instances) {
+ (node_instance.second)->deactivate();
+ }
+
+ m_state = WORKFLOW_INSTANCE_STATE::INITIALIZED;
+}
+
+bool WorkflowInstance::set_attribute(mmi_attribute_h attribute) {
+ _D("Setting attribute : %p", attribute);
+
+ std::shared_ptr<WorkflowPrototype> 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_attribute_get_name(attribute, &name)) {
+ std::vector<AttributeAssignmentInfo> attribute_assignment_infos =
+ prototype->get_attribute_assignment_infos();
+
+ if (!name) {
+ _E("Attribute name is null");
+ return false;
+ }
+ auto it = std::find_if(attribute_assignment_infos.begin(), attribute_assignment_infos.end(),
+ [name](const AttributeAssignmentInfo& info) {
+ return (info.attribute_name.compare(name) == 0);
+ });
+ if (it != attribute_assignment_infos.end()) {
+ _D("Found attribute assignment info : %s", name);
+ try {
+ std::shared_ptr<NodeInstance> 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);
+ } 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 attribute assignment info : %s", name);
+ }
+ free(name);
+ name = nullptr;
+ }
+
+ return true;
+}
+
+void WorkflowInstance::on_observer_event(
+ const PLUGIN_MODULE_EVENT_TYPE &event, std::any data) {
+ try {
+ if (event == PLUGIN_MODULE_EVENT_TYPE::SWITCH_EVENT_EMITTED) {
+ PluginModuleEventSwitchEventEmitted *switch_event = std::any_cast<PluginModuleEventSwitchEventEmitted*>(data);
+ if (switch_event != nullptr) {
+ bool found = false;
+ for (auto &node_instance : m_node_instances) {
+ if (switch_event->node_instance == node_instance.second.get()) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ /* This event is not for this workflow instance */
+ return;
+ }
+ _D("Switch Event emitted for %s %d", switch_event->controllee.c_str(), switch_event->state);
+ std::shared_ptr<NodeInstance> node_instance = m_node_instances.at(switch_event->controllee);
+ if (node_instance) {
+ if (switch_event->state) {
+ node_instance->resume();
+ } else {
+ node_instance->suspend();
+ }
+ } else {
+ _E("Could not find node instance : %s", switch_event->controllee.c_str());
+ }
+ }
+ }
+ } catch (const std::bad_any_cast &e) {
+ LOGE("Failed to cast message data: %s", e.what());
+ }
+}
+
+bool WorkflowInstance::set_attribute_default_values() {
+ _D("Setting attribute default value");
+
+ std::shared_ptr<WorkflowPrototype> prototype = m_prototype_store->get_workflow_prototype(m_type);
+ if (nullptr == prototype) {
+ _E("Could not find prototype information from store");
+ return false;
+ }
+
+ std::vector<AttributeDefaultValueInfo> attribute_default_value_infos =
+ prototype->get_attribute_default_value_infos();
+
+ for (auto &default_value_info : attribute_default_value_infos) {
+ set_attribute(default_value_info.default_value);
+ }
+
+ return true;
+}
+
+} // namespace mmi
+
--- /dev/null
+/*
+* 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_WORKFLOW_INSTANCE_H__
+#define __MMI_WORKFLOW_INSTANCE_H__
+
+#include <memory>
+#include <map>
+#include <string>
+
+#include "mmi-plugin-module-event.h"
+#include "mmi-plugin-module-proxy.h"
+#include "mmi-manager-log.h"
+#include "mmi-node-instance-manager.h"
+#include "mmi-workflow-prototype-manager.h"
+#include "mmi-workflow-output-event.h"
+namespace mmi {
+
+enum class WORKFLOW_INSTANCE_STATE {
+ NONE,
+ INITIALIZED,
+ ACTIVATED,
+};
+
+class WorkflowInstance :
+ public SimpleEventObserver<PLUGIN_MODULE_EVENT_TYPE>,
+ public SimpleEventObservable<WORKFLOW_OUTPUT_EVENT_TYPE> {
+public:
+ WorkflowInstance();
+ virtual ~WorkflowInstance();
+
+ void set_client_id(std::string client_id);
+ std::string get_client_id();
+
+ void set_local_workflow_instance_id(int local_workflow_instance_id);
+ int get_local_workflow_instance_id();
+
+ void set_type(mmi_standard_workflow_type_e type);
+ mmi_standard_workflow_type_e get_type();
+
+ void set_workflow_prototype_store(
+ std::shared_ptr<IWorkflowPrototypeStore> prototype_store);
+ void set_plugin_module_proxy_provider(
+ std::shared_ptr<IPluginModuleProxyProvider> plugin_module_proxy_provider);
+ void set_node_instance_manager(
+ std::shared_ptr<INodeInstanceManager> node_instance_manager);
+
+ void initialize();
+ void deinitialize();
+
+ void activate();
+ void deactivate();
+
+ bool set_attribute(mmi_attribute_h attribute);
+ bool set_attribute_default_values();
+
+ void on_observer_event(
+ const PLUGIN_MODULE_EVENT_TYPE &event, std::any data) override;
+private:
+ std::shared_ptr<IWorkflowPrototypeStore> m_prototype_store;
+ std::shared_ptr<IPluginModuleProxyProvider> m_plugin_module_proxy_provider;
+ std::shared_ptr<INodeInstanceManager> m_node_instance_manager;
+
+ std::shared_ptr<IPluginModuleProxy> m_plugin_module_proxy;
+
+ std::string m_client_id;
+ int m_local_workflow_instance_id{0};
+
+ mmi_standard_workflow_type_e m_type{MMI_STANDARD_WORKFLOW_NONE};
+ WORKFLOW_INSTANCE_STATE m_state{WORKFLOW_INSTANCE_STATE::NONE};
+
+ std::map<std::string, std::shared_ptr<NodeInstance>> m_node_instances;
+
+ std::vector<std::shared_ptr<DataGateway>> m_data_gateways;
+};
+
+} // namespace mmi
+
+#endif //__MMI_WORKFLOW_INSTANCE_H__
+
--- /dev/null
+/*
+ * Copyright © 2021 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 "mmi-workflow-prototype-manager.h"
+
+#include "mmi-manager-log.h"
+
+namespace mmi {
+
+WorkflowPrototypeManager::WorkflowPrototypeManager() {
+}
+
+WorkflowPrototypeManager::~WorkflowPrototypeManager() {
+}
+
+bool WorkflowPrototypeManager::add_workflow_prototype(std::shared_ptr<WorkflowPrototype> prototype) {
+ if (!prototype->is_valid()) {
+ _E("ERROR: invalid workflow prototype");
+ return false;
+ }
+
+ /* check if we already have a prototype with the same type */
+ for (auto& elem : m_prototypes) {
+ if (elem->get_type() == prototype->get_type()) {
+ _E("ERROR: prototype with the same type already exists : %d", prototype->get_type());
+ return false;
+ }
+ }
+
+ m_prototypes.push_back(prototype);
+
+ return true;
+}
+
+std::shared_ptr<WorkflowPrototype> WorkflowPrototypeManager::get_workflow_prototype(
+ mmi_standard_workflow_type_e type) {
+ std::shared_ptr<WorkflowPrototype> ret;
+
+ for (auto& elem : m_prototypes) {
+ if (elem->get_type() == type) {
+ ret = elem;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void WorkflowPrototypeManager::initialize() {
+}
+
+void WorkflowPrototypeManager::deinitialize() {
+}
+
+} // namespace mmi
+
--- /dev/null
+/*
+* 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_WORKFLOW_PROTOTYPE_MANAGER_H__
+#define __MMI_WORKFLOW_PROTOTYPE_MANAGER_H__
+
+#include "mmi-workflow.h"
+#include "mmi-workflow-prototype.h"
+
+#include <memory>
+
+namespace mmi {
+
+struct IWorkflowPrototypeStore {
+ virtual bool add_workflow_prototype(std::shared_ptr<WorkflowPrototype> prototype) = 0;
+ virtual std::shared_ptr<WorkflowPrototype> get_workflow_prototype(mmi_standard_workflow_type_e type) = 0;
+};
+
+class WorkflowPrototypeManager : public IWorkflowPrototypeStore {
+public:
+ WorkflowPrototypeManager();
+ virtual ~WorkflowPrototypeManager();
+
+ virtual bool add_workflow_prototype(std::shared_ptr<WorkflowPrototype> prototype) override;
+ virtual std::shared_ptr<WorkflowPrototype> get_workflow_prototype(mmi_standard_workflow_type_e type) override;
+
+ void initialize();
+ void deinitialize();
+
+protected:
+ std::vector<std::shared_ptr<WorkflowPrototype>> m_prototypes;
+};
+
+} // namespace mmi
+
+#endif //__MMI_WORKFLOW_PROTOTYPE_MANAGER_H__
+
+
--- /dev/null
+/*
+ * Copyright © 2021 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 "mmi-workflow-prototype.h"
+
+#include "mmi-manager-log.h"
+
+namespace mmi {
+
+WorkflowPrototype::WorkflowPrototype() {
+}
+
+WorkflowPrototype::~WorkflowPrototype() {
+ for (auto& attribute_default_value_info : m_attribute_default_value_infos) {
+ mmi_attribute_destroy(attribute_default_value_info.default_value);
+ }
+}
+
+bool WorkflowPrototype::is_valid() {
+ if (!m_type.has_value()) {
+ _E("ERROR: type is not set");
+ return false;
+ }
+
+ if (m_plugin_module_info.plugin_module_identifier.empty()) {
+ _E("ERROR: plugin module identifier is not set");
+ return false;
+ }
+
+ return true;
+}
+
+void WorkflowPrototype::set_type(mmi_standard_workflow_type_e type) {
+ m_type = type;
+}
+
+bool WorkflowPrototype::add_node_info(NodeInfo node_info) {
+ m_node_infos.push_back(node_info);
+ return true;
+}
+
+bool WorkflowPrototype::add_link_info(LinkInfo link_info) {
+ m_link_infos.push_back(link_info);
+ return true;
+}
+
+bool WorkflowPrototype::add_attribute_assignment_info(AttributeAssignmentInfo attribute_assignment_info) {
+ m_attribute_assignment_infos.push_back(attribute_assignment_info);
+ return true;
+}
+
+bool WorkflowPrototype::add_attribute_default_value_info(AttributeDefaultValueInfo attribute_default_value_info) {
+ m_attribute_default_value_infos.push_back(attribute_default_value_info);
+ return true;
+}
+
+bool WorkflowPrototype::add_output_assignment_info(OutputAssignmentInfo output_assignment_info) {
+ m_output_assignment_infos.push_back(output_assignment_info);
+ return true;
+}
+
+mmi_standard_workflow_type_e WorkflowPrototype::get_type() {
+ return m_type.value();
+}
+
+std::vector<NodeInfo> WorkflowPrototype::get_node_infos() {
+ return m_node_infos;
+}
+
+std::vector<LinkInfo> WorkflowPrototype::get_link_infos() {
+ return m_link_infos;
+}
+
+std::vector<AttributeAssignmentInfo> WorkflowPrototype::get_attribute_assignment_infos() {
+ return m_attribute_assignment_infos;
+}
+
+std::vector<AttributeDefaultValueInfo> WorkflowPrototype::get_attribute_default_value_infos() {
+ return m_attribute_default_value_infos;
+}
+
+std::vector<OutputAssignmentInfo> WorkflowPrototype::get_output_assignment_infos() {
+ return m_output_assignment_infos;
+}
+
+} // namespace mmi
+
--- /dev/null
+/*
+* 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_WORKFLOW_PROTOTYPE_H__
+#define __MMI_WORKFLOW_PROTOTYPE_H__
+
+#include "mmi-workflow.h"
+#include "mmi-node-prototype.h"
+
+#include <memory>
+
+namespace mmi {
+
+typedef struct {
+ std::string name;
+ mmi_standard_node_type_e node_type;
+ mmi_standard_node_sub_type_e node_sub_type;
+} NodeInfo;
+
+typedef struct {
+ std::string from_node_name;
+ std::string from_port_name;
+ std::string to_node_name;
+ std::string to_port_name;
+} LinkInfo;
+
+typedef struct {
+ std::string attribute_name;
+ std::string target_node_name;
+ std::string target_attribute_name;
+} AttributeAssignmentInfo;
+
+typedef struct {
+ mmi_attribute_h default_value;
+} AttributeDefaultValueInfo;
+
+typedef struct {
+ std::string output_name;
+ std::string from_node_name;
+ std::string from_port_name;
+} OutputAssignmentInfo;
+
+class WorkflowPrototype {
+public:
+ WorkflowPrototype();
+ virtual ~WorkflowPrototype();
+
+ bool is_valid();
+
+ void set_plugin_module_info(PluginModuleInfo plugin_module_info) {
+ m_plugin_module_info = plugin_module_info;
+ }
+ PluginModuleInfo get_plugin_module_info() {
+ return m_plugin_module_info;
+ }
+
+ void set_type(mmi_standard_workflow_type_e type);
+
+ bool add_node_info(NodeInfo node_info);
+ 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_output_assignment_info(OutputAssignmentInfo output_assignment_info);
+
+ mmi_standard_workflow_type_e get_type();
+
+ std::vector<NodeInfo> get_node_infos();
+ std::vector<LinkInfo> get_link_infos();
+ std::vector<AttributeAssignmentInfo> get_attribute_assignment_infos();
+ std::vector<AttributeDefaultValueInfo> get_attribute_default_value_infos();
+ std::vector<OutputAssignmentInfo> get_output_assignment_infos();
+private:
+ PluginModuleInfo m_plugin_module_info;
+
+ std::optional<mmi_standard_workflow_type_e> m_type;
+
+ std::vector<NodeInfo> m_node_infos;
+ std::vector<LinkInfo> m_link_infos;
+ std::vector<AttributeAssignmentInfo> m_attribute_assignment_infos;
+ std::vector<AttributeDefaultValueInfo> m_attribute_default_value_infos;
+ std::vector<OutputAssignmentInfo> m_output_assignment_infos;
+};
+
+} // namespace mmi
+
+#endif //__MMI_WORKFLOW_PROTOTYPE_H__
+
+
+++ /dev/null
-/*
- * 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 "mmi.h"
-#include "mmi-client.h"
-#include "mmi-dbg.h"
-#include "mmi-ipc.h"
-
-MMI_API int mmi_initialize(void)
-{
- int ret = mmi_client_create();
- if(ret != MMI_ERROR_NONE) {
- LOGE("Fail to create mmi client(%d)", ret);
- return MMI_ERROR_NOT_SUPPORTED;
- }
-
- return MMI_ERROR_NONE;
-}
-
-MMI_API int mmi_deinitialize(void)
-{
- int ret = mmi_client_destroy();
- if(ret != MMI_ERROR_NONE) {
- LOGE("Fail to destroy mmi client(%d)", ret);
- return MMI_ERROR_NOT_SUPPORTED;
- }
-
- return MMI_ERROR_NONE;
-}
-
-MMI_API int mmi_set_result_cb(int input_event_type, mmi_result_cb callback, void* user_data)
-{
- LOGI("Set result cb about input event type(%d)", input_event_type);
-
- int ret = mmi_client_set_result_cb(input_event_type, callback, user_data);
- if(ret != MMI_ERROR_NONE) {
- LOGE("Fail to set result cb(%d)", ret);
- return ret;
- }
-
- return MMI_ERROR_NONE;
-}
-
-MMI_API int mmi_activate_input_event(int input_event_type)
-{
- LOGI("Activate input event(%d)", input_event_type);
-
- int ret;
- GList* iter = NULL;
- mmi_result_cb_s *data = NULL;
- mmi_handle client = mmi_client_get();
-
- if (g_list_length(client->result_cb_list) > 0) {
- LOGD("Check length of callback lists = %d", g_list_length(client->result_cb_list));
-
- iter = g_list_first(client->result_cb_list);
-
- while (iter != NULL) {
- data = iter->data;
-
- if (data != NULL) {
- int type = data->input_event_type;
-
- if (type == input_event_type) {
- ret = mmi_ipc_activate_input_event(input_event_type);
- if(ret != MMI_ERROR_NONE) {
- LOGE("Fail to activate input event(%d)", ret);
- return ret;
- }
-
- LOGD("Activate input event(%d)", type);
- return MMI_ERROR_NONE;
- }
- }
-
- iter = g_list_next(iter);
- }
- }
-
- LOGE("No match callback about input event type(%d)", input_event_type);
- return MMI_ERROR_INVALID_PARAMETER;
-}
-
-MMI_API int mmi_deactivate_input_event(int input_event_type)
-{
- LOGI("Deactivate input event(%d)", input_event_type);
-
- int ret;
- GList* iter = NULL;
- mmi_result_cb_s *data = NULL;
- mmi_handle client = mmi_client_get();
-
- if (g_list_length(client->result_cb_list) > 0) {
- LOGD("Check length of callback lists = %d", g_list_length(client->result_cb_list));
-
- iter = g_list_first(client->result_cb_list);
-
- while (NULL != iter) {
- data = iter->data;
-
- if (NULL != data) {
- int type = data->input_event_type;
-
- if (type == input_event_type) {
- ret = mmi_ipc_deactivate_input_event(input_event_type);
- if(ret != MMI_ERROR_NONE) {
- LOGE("Fail to deactivate input event(%d)", ret);
- return ret;
- }
-
- return MMI_ERROR_NONE;
- }
- }
-
- iter = g_list_next(iter);
- }
- }
-
- LOGE("Fail to deactivate input event type(%d)", input_event_type);
- return MMI_ERROR_INVALID_PARAMETER;
-}
+++ /dev/null
-/*
- * 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.
- *
- */
-
-#ifndef __MMI_H__
-#define __MMI_H__
-
-#include <tizen.h>
-
-#define MMI_API __attribute__ ((visibility("default")))
-
-typedef enum {
- MMI_RESULT_NONE,
- MMI_RESULT_FAIL,
- MMI_RESULT_SUCCESS
-} mmi_result_e;
-
-#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_e;
-
-typedef void (*mmi_result_cb)(int input_event_type, const char *result_out, void *user_data);
-
-typedef enum {
- MMI_INPUT_EVENT_TYPE_NONE,
- MMI_INPUT_EVENT_TYPE_VOICE_TOUCH,
- MMI_INPUT_EVENT_TYPE_VOICE_RECOGNITION,
-} mmi_input_event_type_e;
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-MMI_API int mmi_initialize(void);
-MMI_API int mmi_deinitialize(void);
-MMI_API int mmi_set_result_cb(int input_event_type, mmi_result_cb callback, void* user_data);
-MMI_API int mmi_activate_input_event(int input_event_type);
-MMI_API int mmi_deactivate_input_event(int input_event_type);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif //__MMI_H__
--- /dev/null
+mmi_srcs = [
+ 'mmi.cpp',
+ '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',
+ 'mmi-node.cpp',
+ 'mmi-node-source.cpp',
+ 'mmi-node-processor.cpp',
+ 'mmi-node-logic.cpp',
+ 'mmi-node-controller.cpp',
+ 'mmi-port.cpp',
+ 'mmi-signal.cpp',
+ 'mmi-plugin-storage.cpp',
+ ]
+
+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')
+
+mmi_deps = [
+ ecore_dep,
+ glib_dep,
+ gio_dep,
+ bundle_dep,
+ dlog_dep,
+ rpc_port_dep,
+ libtzplatform_config_dep]
+
+mmi_include_dirs = include_directories(
+ '.',
+ '../common',
+ '../../capi'
+ )
+
+mmi_lib = shared_library(
+ 'mmi',
+ mmi_srcs,
+ dependencies : [mmi_deps],
+ include_directories : [mmi_include_dirs],
+ version : meson.project_version(),
+ install : true
+ )
+
+pkgconfig = import('pkgconfig')
+pkgconfig.generate(
+ filebase : 'mmi',
+ name : 'mmi',
+ description : 'Multi-modal Interaction Framework Library',
+ version : meson.project_version(),
+ libraries : mmi_lib
+ )
+
+mmi_declared_dep = declare_dependency(
+ link_with : mmi_lib,
+ dependencies : [mmi_deps],
+ include_directories : [mmi_include_dirs]
+ )
--- /dev/null
+/*
+ * 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-error.h>
+#include <mmi-primitive-value.h>
+#include <mmi-attribute.h>
+
+#include "mmi-log.h"
+
+#include <cstdio>
+
+constexpr size_t MAX_ATTRIBUTE_NAME_SIZE = 256;
+
+struct mmi_attribute_s {
+ char name[MAX_ATTRIBUTE_NAME_SIZE];
+ mmi_primitive_value_h value;
+};
+
+
+static constexpr size_t g_unit_size = sizeof(mmi_primitive_value_h);
+
+
+int mmi_attribute_create(mmi_primitive_value_h value, const char *name, mmi_attribute_h *attribute) {
+ if (nullptr == value || nullptr == name || nullptr == attribute) {
+ _E("[ERROR] Some parameters are null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ const size_t length = strlen(name);
+ if (0 == length || MAX_ATTRIBUTE_NAME_SIZE <= length) {
+ _E("[ERROR] Length of name is invalid. length(%zu)", length);
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_attribute_h new_attribute = reinterpret_cast<mmi_attribute_s *>(calloc(1, sizeof(mmi_attribute_s)));
+ if (nullptr == new_attribute) {
+ _E("[ERROR] Fail to allocate memory for attribute");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ snprintf(new_attribute->name, MAX_ATTRIBUTE_NAME_SIZE, "%s", name);
+ int ret = mmi_primitive_value_clone(value, &(new_attribute->value));
+ if (MMI_ERROR_NONE != ret) {
+ free(new_attribute);
+ _E("[ERROR] Fail to clone primitve value");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ *attribute = new_attribute;
+
+ _D("[DEBUG] Success to create attribute");
+ return MMI_ERROR_NONE;
+}
+
+int mmi_attribute_set_name(mmi_attribute_h attribute, const char *name) {
+ if (nullptr == attribute || nullptr == name) {
+ _E("[ERROR] Some parameters are null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto attribute_ptr = static_cast<mmi_attribute_s *>(attribute);
+ snprintf(attribute_ptr->name, MAX_ATTRIBUTE_NAME_SIZE, "%s", name);
+
+ _D("[DEBUG] Success to set name (%s)", attribute_ptr->name);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_attribute_get_name(mmi_attribute_h attribute, char **name) {
+ if (nullptr == attribute || nullptr == name) {
+ _E("[ERROR] Some parameters are null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *name = strdup(attribute->name);
+ if (nullptr == *name) {
+ _E("[ERROR] Fail to allocate memory for name string");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ _D("[DEBUG] Success to get name (%s)", *name);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_attribute_get_value(mmi_attribute_h attribute, mmi_primitive_value_h *value) {
+ if (nullptr == attribute || nullptr == value) {
+ _E("[ERROR] Some parameters are null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ int ret = mmi_primitive_value_clone(attribute->value, value);
+ if (MMI_ERROR_NONE != ret) {
+ _E("[ERROR] Fail to clone primitve value");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ _D("[DEBUG] Success to get primitive value");
+ return MMI_ERROR_NONE;
+}
+
+int mmi_attribute_clone(mmi_attribute_h attribute, mmi_attribute_h *cloned) {
+ if (nullptr == attribute || nullptr == cloned) {
+ _E("[ERROR] Some parameters are null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_attribute_h new_attribute = reinterpret_cast<mmi_attribute_s *>(calloc(1, sizeof(mmi_attribute_s)));
+ if (nullptr == new_attribute) {
+ _E("[ERROR] Fail to allocate memory for attribute");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ snprintf(new_attribute->name, MAX_ATTRIBUTE_NAME_SIZE, "%s", attribute->name);
+ int ret = mmi_primitive_value_clone(attribute->value, &(new_attribute->value));
+ if (MMI_ERROR_NONE != ret) {
+ free(new_attribute);
+ _E("[ERROR] Fail to clone primitve value");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ *cloned = new_attribute;
+
+ _D("[DEBUG] Success to clone attribute");
+ return MMI_ERROR_NONE;
+}
+
+int mmi_attribute_destroy(mmi_attribute_h attribute) {
+ if (nullptr == attribute) {
+ _E("[ERROR] Parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ int ret = mmi_primitive_value_destroy(attribute->value);
+ if (MMI_ERROR_NONE != ret) {
+ _W("[WARN] Fail to destroy primitive value");
+ }
+
+ free(attribute);
+
+ _D("[DEBUG] Success to destroy attribute");
+ return MMI_ERROR_NONE;
+}
+
+int mmi_attribute_to_bytes(mmi_attribute_h attribute, unsigned char **bytes, size_t *length) {
+ if (nullptr == attribute || nullptr == bytes || nullptr == length) {
+ _E("[ERROR] Some parameters are null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ size_t name_length = strlen(attribute->name);
+ size_t value_length = 0;
+ unsigned char *value_bytes = nullptr;
+ int ret = mmi_primitive_value_to_bytes(attribute->value, &value_bytes, &value_length);
+ if (MMI_ERROR_NONE != ret) {
+ _E("[ERROR] Fail to convert primitive value to bytes");
+ free(value_bytes);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ *length = sizeof(name_length) + name_length + sizeof(value_length) + value_length;
+ *bytes = reinterpret_cast<unsigned char *>(calloc(1, *length));
+ if (nullptr == *bytes) {
+ _E("[ERROR] Fail to allocate memory for bytes");
+ free(value_bytes);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ unsigned char *pos = *bytes;
+ memcpy(pos, &name_length, sizeof(name_length));
+ pos += sizeof(name_length);
+ memcpy(pos, attribute->name, name_length);
+ pos += name_length;
+ memcpy(pos, &value_length, sizeof(value_length));
+ pos += sizeof(value_length);
+ memcpy(pos, value_bytes, value_length);
+
+ free(value_bytes);
+
+ _D("[DEBUG] Success to convert attribute to bytes");
+ return MMI_ERROR_NONE;
+}
+
+int mmi_attribute_from_bytes(const unsigned char *bytes, size_t length, mmi_attribute_h *attribute) {
+ if (nullptr == bytes || 0 == length || nullptr == attribute) {
+ _E("[ERROR] Some parameters are null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ size_t name_length = 0;
+ char *name = nullptr;
+ unsigned char *pos = const_cast<unsigned char *>(bytes);
+ memcpy(&name_length, pos, sizeof(name_length));
+ pos += sizeof(name_length);
+ name = reinterpret_cast<char *>(calloc(1, name_length + 1));
+ if (nullptr == name) {
+ _E("[ERROR] Fail to allocate memory for name string");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+ memcpy(name, pos, name_length);
+ pos += name_length;
+
+ size_t value_length = 0;
+ unsigned char *value_bytes = nullptr;
+ memcpy(&value_length, pos, sizeof(value_length));
+ pos += sizeof(value_length);
+ value_bytes = reinterpret_cast<unsigned char *>(calloc(1, value_length));
+ if (nullptr == value_bytes) {
+ _E("[ERROR] Fail to allocate memory for value bytes");
+ free(name);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+ memcpy(value_bytes, pos, value_length);
+ pos += value_length;
+
+ mmi_primitive_value_h value = nullptr;
+ int ret = mmi_primitive_value_from_bytes(value_bytes, value_length, &value);
+ if (MMI_ERROR_NONE != ret) {
+ _E("[ERROR] Fail to convert bytes to primitive value");
+ free(name);
+ free(value_bytes);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ free(value_bytes);
+
+ ret = mmi_attribute_create(value, name, attribute);
+ if (MMI_ERROR_NONE != ret) {
+ _E("[ERROR] Fail to create attribute");
+ free(name);
+ mmi_primitive_value_destroy(value);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ mmi_primitive_value_destroy(value);
+
+ free(name);
+
+ _D("[DEBUG] Success to convert bytes to attribute");
+ return MMI_ERROR_NONE;
+}
+
+int mmi_attribute_create_string_array(const char *name, const char *strings[], size_t count, mmi_attribute_h *attribute) {
+ if (nullptr == attribute || nullptr == name || nullptr == strings || 0 == count) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_primitive_value_h array = nullptr;
+ int ret = mmi_primitive_value_create_array(&array);
+ if (MMI_ERROR_NONE != ret) {
+ _E("[ERROR] Fail to allocate memory for array primitive");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ for (size_t i = 0; i < count; i++) {
+ mmi_primitive_value_h element = nullptr;
+ int ret = mmi_primitive_value_create_string(strings[i], &element);
+ if (MMI_ERROR_NONE != ret) {
+ _E("[ERROR] Fail to allocate memory for array attribute");
+ mmi_primitive_value_destroy(array);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ret = mmi_primitive_value_add_array_element(array, element);
+ if (MMI_ERROR_NONE != ret) {
+ _E("[ERROR] Fail to allocate memory for array attribute");
+ mmi_primitive_value_destroy(array);
+ mmi_primitive_value_destroy(element);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+ }
+
+ ret = mmi_attribute_create(array, name, attribute);
+ if (MMI_ERROR_NONE != ret) {
+ mmi_primitive_value_destroy(array);
+ _E("[ERROR] Fail to allocate memory for array attribute");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ ret = mmi_primitive_value_destroy(array);
+ if (MMI_ERROR_NONE != ret) {
+ _W("[WARN] Fail to destroy temporary primitive value");
+ }
+
+ _D("[DEBUG] Success to create attribute");
+ return MMI_ERROR_NONE;
+}
--- /dev/null
+/*
+ * 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 "mmi.h"
+
+#include "mmi-event-observer.h"
+#include "mmi-communication-channel.h"
+#include "mmi-workflow-instance-manager.h"
+
+using namespace mmi;
+using namespace mmi::communication;
+
+struct ICommunicationChannelFactory {
+ virtual CommunicationChannel* create_channel() = 0;
+ virtual void destroy_channel(CommunicationChannel* channel) = 0;
+};
+
+class ClientManager : public SimpleEventObserver<COMMUNICATION_CHANNEL_EVENT_TYPE> {
+public:
+ ClientManager(
+ ICommunicationChannelFactory *factory,
+ SimpleEventObserver<COMMUNICATION_CHANNEL_EVENT_TYPE> *observer)
+ : m_communication_channel_factory(factory),
+ m_communication_channel_observer(observer) {
+ }
+ virtual ~ClientManager() {
+ }
+
+ bool initialize() {
+ if (m_reference_count == 0) {
+ m_communication_channel =
+ m_communication_channel_factory->create_channel();
+ if (nullptr == m_communication_channel) {
+ return false;
+ } else {
+ m_communication_channel->add_observer(m_communication_channel_observer);
+ m_communication_channel->add_observer(this);
+ m_communication_channel->connect();
+ }
+
+ m_workflow_instance_manager.initialize();
+ }
+ m_reference_count++;
+ return true;
+ }
+ bool deinitialize() {
+ if (m_reference_count == 0) {
+ return false;
+ }
+ m_reference_count--;
+ 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 = nullptr;
+
+ m_workflow_instance_manager.deinitialize();
+ }
+ return true;
+ }
+
+ CommunicationChannel* get_communication_channel() {
+ return m_communication_channel;
+ }
+ WorkflowInstanceManager* get_workflow_instance_manager() {
+ return &m_workflow_instance_manager;
+ }
+
+ void on_observer_event(
+ const COMMUNICATION_CHANNEL_EVENT_TYPE &event, std::any data) override {
+ }
+
+private:
+ ICommunicationChannelFactory* m_communication_channel_factory{nullptr};
+ CommunicationChannel *m_communication_channel{nullptr};
+ SimpleEventObserver<COMMUNICATION_CHANNEL_EVENT_TYPE>
+ *m_communication_channel_observer;
+ WorkflowInstanceManager m_workflow_instance_manager;
+
+ int m_reference_count{0};
+};
+
--- /dev/null
+/*
+ * 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 <new>
+#include <string>
+#include <vector>
+
+#include "mmi-log.h"
+
+#include <mmi-error.h>
+#include <mmi-data.h>
+
+
+struct mmi_data_timestamp_s {
+ bool valid;
+ void *data;
+};
+
+struct mmi_data_s {
+ mmi_data_type_e type;
+ void *data;
+ size_t datalen;
+};
+
+
+static constexpr size_t g_unit_size = sizeof(mmi_data_h);
+
+
+static constexpr size_t get_count_of_elements(mmi_data_h array) {
+ return array->datalen / g_unit_size;
+}
+
+static constexpr size_t get_count_of_struct_elements(mmi_data_h struct_handle) {
+ return get_count_of_elements(struct_handle) / 2;
+}
+
+static inline mmi_data_h *get_element_pointer_in_array(mmi_data_h array, size_t index) {
+ return reinterpret_cast<mmi_data_h *>(array->data) + index;
+}
+
+static inline mmi_data_h *get_element_name_pointer_in_struct(mmi_data_h struct_handle, size_t index) {
+ return get_element_pointer_in_array(struct_handle, index * 2);
+}
+
+static inline mmi_data_h *get_element_value_pointer_in_struct(mmi_data_h struct_handle, size_t index) {
+ return get_element_pointer_in_array(struct_handle, index * 2 + 1);
+}
+
+
+int mmi_data_create_bool(bool value, mmi_data_h *data) {
+ if (nullptr == data) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto new_data = reinterpret_cast<mmi_data_s *>(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_BOOLEAN;
+ new_data->data = malloc(sizeof(bool));
+ 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<bool *>(new_data->data)) = value;
+ new_data->datalen = sizeof(bool);
+
+ *data = new_data;
+
+ _D("[DEBUG] Success to create for bool(%d)", value);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_create_int(int value, mmi_data_h *data) {
+ if (nullptr == data) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto new_data = reinterpret_cast<mmi_data_s *>(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_INTEGER;
+ new_data->data = malloc(sizeof(int));
+ 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<int *>(new_data->data)) = value;
+ new_data->datalen = sizeof(int);
+
+ *data = new_data;
+
+ _D("[DEBUG] Success to create for int(%d)", value);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_create_float(float value, mmi_data_h *data) {
+ if (nullptr == data) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto new_data = reinterpret_cast<mmi_data_s *>(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_FLOAT;
+ new_data->data = malloc(sizeof(float));
+ 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<float *>(new_data->data)) = value;
+ new_data->datalen = sizeof(float);
+
+ *data = new_data;
+
+ _D("[DEBUG] Success to create for float(%f)", value);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_create_text(const char *value, mmi_data_h *data) {
+ if (nullptr == data || nullptr == value) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto new_data = reinterpret_cast<mmi_data_s *>(malloc(sizeof(mmi_data_s)));
+ if (nullptr == new_data) {
+ _E("[ERROR] Fail to allocate memory for primitive value");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ new_data->type = MMI_DATA_TYPE_TEXT;
+ new_data->data = reinterpret_cast<void *>(strdup(value));
+ if (nullptr == new_data->data) {
+ _E("[ERROR] Fail to allocate memory for raw data");
+ free(new_data);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ new_data->datalen = strlen(value);
+
+ *data = new_data;
+
+ _D("[DEBUG] Success to create for string(%s)", value);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_create_audio(const void *ptr, size_t len, mmi_data_h *data) {
+ if (nullptr == data || nullptr == ptr || 0 == len) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto new_data = reinterpret_cast<mmi_data_s *>(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_AUDIO;
+ new_data->data = malloc(len);
+ if (nullptr == new_data->data) {
+ _E("[ERROR] Fail to allocate memory for raw data");
+ free(new_data);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ memcpy(new_data->data, ptr, len);
+ new_data->datalen = len;
+
+ *data = new_data;
+
+ _D("[DEBUG] Success to create for audio data. len(%zu)", len);
+ return MMI_ERROR_NONE;
+}
+
+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");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto new_data = reinterpret_cast<mmi_data_s *>(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_VIDEO;
+ new_data->data = malloc(len);
+ if (nullptr == new_data->data) {
+ _E("[ERROR] Fail to allocate memory for raw data");
+ free(new_data);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ memcpy(new_data->data, ptr, len);
+ new_data->datalen = len;
+
+ *data = new_data;
+
+ _D("[DEBUG] Success to create for video data. len(%zu)", len);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_create_user_identification(const void *ptr, size_t len, mmi_data_h *data) {
+ if (nullptr == data || nullptr == ptr || 0 == len) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto new_data = reinterpret_cast<mmi_data_s *>(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_USER_IDENTIFICATION;
+ new_data->data = malloc(len);
+ if (nullptr == new_data->data) {
+ _E("[ERROR] Fail to allocate memory for raw data");
+ free(new_data);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ memcpy(new_data->data, ptr, len);
+ new_data->datalen = len;
+
+ *data = new_data;
+
+ _D("[DEBUG] Success to create for user identification data. len(%zu)", len);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_create_array(mmi_data_h *data) {
+ if (nullptr == data) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto new_data = reinterpret_cast<mmi_data_s *>(malloc(sizeof(mmi_data_s)));
+ if (nullptr == new_data) {
+ _E("[ERROR] Fail to allocate memory for primitive value");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ new_data->type = MMI_DATA_TYPE_ARRAY;
+ new_data->data = nullptr;
+ new_data->datalen = 0;
+
+ *data = new_data;
+
+ _D("[DEBUG] Success to create empty array");
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_add_array_element(mmi_data_h array, mmi_data_h element) {
+ if (nullptr == array || nullptr == element) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (array->type != MMI_DATA_TYPE_ARRAY) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ size_t count = get_count_of_elements(array);
+ if (count > 0) {
+ mmi_data_h first = *(get_element_pointer_in_array(array, 0));
+ if (first->type != element->type) {
+ _E("[ERROR] Element type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ auto array_data = reinterpret_cast<mmi_data_h *>(array->data);
+ array_data = reinterpret_cast<mmi_data_h *>(realloc(array_data, g_unit_size * (count + 1)));
+ if (array_data) {
+ array_data[count] = element;
+
+ array->data = array_data;
+ array->datalen = array->datalen + g_unit_size;
+ } else {
+ _E("[ERROR] Fail to allocate memory for array data");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ _D("[DEBUG] Success to add element(%zu)", get_count_of_elements(array));
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_create_struct(mmi_data_h *struct_handle) {
+ if (nullptr == struct_handle) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto new_data = reinterpret_cast<mmi_data_s *>(malloc(sizeof(mmi_data_s)));
+ if (nullptr == new_data) {
+ _E("[ERROR] Fail to allocate memory for primitive value");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ new_data->type = MMI_DATA_TYPE_STRUCT;
+ new_data->data = nullptr;
+ new_data->datalen = 0;
+
+ *struct_handle = new_data;
+
+ _D("[DEBUG] Success to create empty array");
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_set_struct_element(mmi_data_h struct_handle, const char *name, mmi_data_h element) {
+ if (nullptr == struct_handle || nullptr == name || nullptr == element) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (struct_handle->type != MMI_DATA_TYPE_STRUCT) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_data_h name_element = nullptr;
+ int ret = mmi_data_create_text(name, &name_element);
+ if (MMI_ERROR_NONE != ret) {
+ _E("[ERROR] Fail to allocate memory for name element");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ size_t count = get_count_of_elements(struct_handle);
+ auto struct_data = reinterpret_cast<mmi_data_h *>(struct_handle->data);
+ struct_data = reinterpret_cast<mmi_data_h *>(realloc(struct_data, g_unit_size * (count + 2)));
+ if (struct_data) {
+ struct_data[count] = name_element;
+ struct_data[count + 1] = element;
+
+ struct_handle->data = struct_data;
+ struct_handle->datalen = struct_handle->datalen + g_unit_size * 2;
+ } else {
+ mmi_data_destroy(name_element);
+ _E("[ERROR] Fail to allocate memory for struct data");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ _D("[DEBUG] Success to add element with name(%s)", name);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_get_type(mmi_data_h data, mmi_data_type_e *type) {
+ if (nullptr == data || nullptr == type) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *type = data->type;
+
+ _D("[DEBUG] Success to get type(%d)", *type);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_get_bool(mmi_data_h data, bool *value) {
+ if (nullptr == data || nullptr == value) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (data->type != MMI_DATA_TYPE_BOOLEAN) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *value = *(reinterpret_cast<bool *>(data->data));
+
+ _D("[DEBUG] Success to get value: bool(%d)", *value);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_get_int(mmi_data_h data, int *value) {
+ if (nullptr == data || nullptr == value) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (data->type != MMI_DATA_TYPE_INTEGER) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *value = *(reinterpret_cast<int *>(data->data));
+
+ _D("[DEBUG] Success to get value: int(%d)", *value);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_get_float(mmi_data_h data, float *value) {
+ if (nullptr == data || nullptr == value) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (data->type != MMI_DATA_TYPE_FLOAT) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *value = *(reinterpret_cast<float *>(data->data));
+
+ _D("[DEBUG] Success to get value: float(%f)", *value);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_get_text(mmi_data_h data, const char **string) {
+ if (nullptr == data || nullptr == string) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (data->type != MMI_DATA_TYPE_TEXT) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *string = reinterpret_cast<char *>(data->data);
+
+ _D("[DEBUG] Success to get value: string(%s)", *string);
+ return MMI_ERROR_NONE;
+}
+
+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");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (data->type != MMI_DATA_TYPE_AUDIO) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *len = data->datalen;
+ *ptr = data->data;
+
+ _D("[DEBUG] Success to get value: audio(%zu)", *len);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_get_video(mmi_data_h data, const void **ptr, size_t *len) {
+ if (nullptr == data || nullptr == ptr || nullptr == len) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (data->type != MMI_DATA_TYPE_VIDEO) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *len = data->datalen;
+ *ptr = data->data;
+
+ _D("[DEBUG] Success to get value: video(%zu)", *len);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_get_user_identification(mmi_data_h data, const void **ptr, size_t *len) {
+ if (nullptr == data || nullptr == ptr || nullptr == len) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (data->type != MMI_DATA_TYPE_USER_IDENTIFICATION) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *len = data->datalen;
+ *ptr = data->data;
+
+ _D("[DEBUG] Success to get value: user_identification(%zu)", *len);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_get_array_count(mmi_data_h array, size_t *count) {
+ if (nullptr == array || nullptr == count) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (array->type != MMI_DATA_TYPE_ARRAY) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *count = get_count_of_elements(array);
+
+ _D("[DEBUG] Success to get array count(%zu)", *count);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_get_array_element(mmi_data_h array, size_t index, mmi_data_h *element) {
+ if (nullptr == array || nullptr == element) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (array->type != MMI_DATA_TYPE_ARRAY) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ size_t count = get_count_of_elements(array);
+ if (index >= count) {
+ _E("[ERROR] index(%zu) is out of range. count(%zu)", index, count);
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *element = *(get_element_pointer_in_array(array, index));
+
+ _D("[DEBUG] Success to get array element on index(%zu)", index);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_get_struct_element(mmi_data_h struct_handle, const char *name, mmi_data_h *element) {
+ if (nullptr == struct_handle || nullptr == name || nullptr == element) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (struct_handle->type != MMI_DATA_TYPE_STRUCT) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ size_t count = get_count_of_elements(struct_handle);
+ if (count % 2 != 0) {
+ _E("[ERROR] Element size is invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_data_h target_element = nullptr;
+ auto struct_data = reinterpret_cast<mmi_data_h *>(struct_handle->data);
+ for (size_t i = 0; i < count; i += 2) {
+ const char *element_name = nullptr;
+ mmi_data_get_text(struct_data[i], &element_name);
+ if (0 == strcmp(name, element_name)) {
+ target_element = struct_data[i + 1];
+ break;
+ }
+ }
+
+ if (nullptr == target_element) {
+ _E("[ERROR] No matched element with name (%s)", name);
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *element = target_element;
+
+ _D("[DEBUG] Success to get element on name(%s)", name);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_get_struct_count(mmi_data_h struct_handle, size_t *count) {
+ if (nullptr == struct_handle || nullptr == count) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (struct_handle->type != MMI_DATA_TYPE_STRUCT) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *count = get_count_of_struct_elements(struct_handle);
+
+ _D("[DEBUG] Success to get struct count(%zu)", *count);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_get_struct_element_name(mmi_data_h struct_handle, size_t index, const char **string) {
+ if (nullptr == struct_handle || nullptr == string) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (struct_handle->type != MMI_DATA_TYPE_STRUCT) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ size_t count = get_count_of_struct_elements(struct_handle);
+ if (index >= count) {
+ _E("[ERROR] index(%zu) is out of range. count(%zu)", index, count);
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ 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;
+}
+
+
+int mmi_data_get_struct_element_value(mmi_data_h struct_handle, size_t index, mmi_data_h *element) {
+ if (nullptr == struct_handle || nullptr == element) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (struct_handle->type != MMI_DATA_TYPE_STRUCT) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ size_t count = get_count_of_struct_elements(struct_handle);
+ if (index >= count) {
+ _E("[ERROR] index(%zu) is out of range. count(%zu)", index, count);
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *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;
+}
+
+int mmi_data_destroy(mmi_data_h data) {
+ if (nullptr == data) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (data->type == MMI_DATA_TYPE_ARRAY || data->type == MMI_DATA_TYPE_STRUCT) {
+ size_t count = get_count_of_elements(data);
+ for (size_t i = 0; i < count; i++) {
+ auto element = get_element_pointer_in_array(data, i);
+ mmi_data_destroy(*element);
+ }
+ }
+
+ free(data->data);
+ data->data = nullptr;
+ data->datalen = 0;
+ data->type = MMI_DATA_TYPE_ANY;
+ free(data);
+
+ _D("[DEBUG] Success to destroy");
+ return MMI_ERROR_NONE;
+}
+
+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;
+ }
+
+ *timestamp = (mmi_data_timestamp_s*)(data->data);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_get_source_timestamp(mmi_data_h data, mmi_data_timestamp_h *timestamp) {
+ if (nullptr == data || nullptr == timestamp) {
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *timestamp = (mmi_data_timestamp_s*)(data->data);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_set_source_timestamp(mmi_data_h data, mmi_data_timestamp_h timestamp) {
+ if (nullptr == data || nullptr == timestamp) {
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ data->data = timestamp;
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_to_bytes(mmi_data_h data, unsigned char **bytes, size_t *length) {
+ if (nullptr == data || nullptr == bytes || nullptr == length) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_data_type_e type;
+ mmi_data_get_type(data, &type);
+ // TODO:: add data type, separate to function
+
+ if (type == MMI_DATA_TYPE_ARRAY || type == MMI_DATA_TYPE_STRUCT) {
+ size_t current_size = sizeof(mmi_data_type_e) + sizeof(size_t);
+ unsigned char *buffer = reinterpret_cast<unsigned char *>(malloc(current_size));
+
+ size_t count = get_count_of_elements(data);
+ unsigned char *current = buffer;
+ memcpy(current, &(data->type), sizeof(mmi_data_type_e));
+ current += sizeof(mmi_data_type_e);
+ /* This size will be updated after getting element bytes */
+ memcpy(current, &count, sizeof(size_t));
+ current += sizeof(size_t);
+ for (size_t i = 0; i < count; i++) {
+ auto element = get_element_pointer_in_array(data, i);
+ unsigned char *element_bytes = nullptr;
+ size_t element_size = 0;
+ mmi_data_to_bytes(*element, &element_bytes, &element_size);
+ buffer = reinterpret_cast<unsigned char *>(realloc(buffer, current_size + element_size + sizeof(size_t)));
+ if (nullptr == buffer) {
+ _E("[ERROR] Failed to allocate memory");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+ current = buffer + current_size;
+ memcpy(current, &element_size, sizeof(size_t));
+ current += sizeof(size_t);
+ current_size += sizeof(size_t);
+ memcpy(current, element_bytes, element_size);
+ current_size += element_size;
+ free(element_bytes);
+ }
+ size_t total_element_size = current_size - sizeof(mmi_data_type_e) - sizeof(size_t);
+ memcpy(buffer + sizeof(mmi_data_type_e), &total_element_size, sizeof(size_t));
+
+ *bytes = buffer;
+ *length = current_size;
+ } else {
+ size_t total_size = sizeof(mmi_data_type_e) + sizeof(size_t) + data->datalen;
+ unsigned char *buffer = reinterpret_cast<unsigned char *>(malloc(total_size));
+ if (nullptr == buffer) {
+ _E("[ERROR] Failed to allocate memory");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+ unsigned char *current = buffer;
+ memcpy(current, &(data->type), sizeof(mmi_data_type_e));
+ current += sizeof(mmi_data_type_e);
+ memcpy(current, &(data->datalen), sizeof(size_t));
+ current += sizeof(size_t);
+ memcpy(current, data->data, data->datalen);
+
+ *bytes = buffer;
+ *length = total_size;
+ }
+
+ _D("[DEBUG] Success to convert data to bytes");
+
+ return MMI_ERROR_NONE;
+}
+
+int mmi_data_from_bytes(unsigned char *bytes, size_t length, mmi_data_h *data) {
+ if (nullptr == data || nullptr == bytes || 0 == length) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ unsigned char *current = bytes;
+ mmi_data_type_e type = MMI_DATA_TYPE_ANY;
+ memcpy(&type, current, sizeof(mmi_data_type_e));
+ current += sizeof(mmi_data_type_e);
+ if (type == MMI_DATA_TYPE_ARRAY || type == MMI_DATA_TYPE_STRUCT) {
+ size_t datalen = 0;
+ memcpy(&datalen, current, sizeof(size_t));
+ current += sizeof(size_t);
+ void *buf = nullptr;
+ auto value = reinterpret_cast<mmi_data_h>(malloc(sizeof(mmi_data_s)));
+ value->type = type;
+ value->datalen = 0;
+ value->data = nullptr;
+
+ size_t num_elements = 0;
+ while (current < bytes + length) {
+ size_t element_size;
+ memcpy(&element_size, current, sizeof(size_t));
+ current += sizeof(size_t);
+ unsigned char *element_bytes = reinterpret_cast<unsigned char *>(malloc(element_size));
+ if (nullptr == element_bytes) {
+ _E("[ERROR] Failed to allocate memory");
+ mmi_data_destroy(value);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ memcpy(element_bytes, current, element_size);
+ current += element_size;
+ mmi_data_h element = nullptr;
+ mmi_data_from_bytes(element_bytes, element_size, &element);
+ free(element_bytes);
+ if (nullptr == element) {
+ _E("[ERROR] Failed to convert bytes to data");
+ mmi_data_destroy(value);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ auto array_data = reinterpret_cast<mmi_data_h *>(value->data);
+ array_data = reinterpret_cast<mmi_data_h *>(realloc(array_data, g_unit_size * (num_elements + 1)));
+ if (array_data) {
+ array_data[num_elements] = element;
+
+ value->data = array_data;
+ value->datalen += g_unit_size;
+ } else {
+ _E("[ERROR] Fail to allocate memory for array data");
+ mmi_data_destroy(element);
+ mmi_data_destroy(value);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ num_elements++;
+ }
+
+ *data = value;
+ } else {
+ size_t datalen;
+ memcpy(&datalen, current, sizeof(size_t));
+ current += sizeof(size_t);
+ void *buf = calloc(1, datalen);
+ if (nullptr == buf) {
+ _E("[ERROR] Failed to allocate memory");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+ memcpy(buf, current, datalen);
+
+ auto value = reinterpret_cast<mmi_data_h>(malloc(sizeof(mmi_data_s)));
+ value->type = type;
+ value->datalen = datalen;
+ value->data = buf;
+
+ *data = value;
+ }
+
+ _D("[DEBUG] Success to convert from bytes. type(%d), size(%zu)", type, length);
+
+ return MMI_ERROR_NONE;
+}
--- /dev/null
+/*
+ * 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 "mmi-ipc-tidl.h"
+#include "mmi-log.h"
+#include "mmi-workflow-instance-manager.h"
+
+#include <tzplatform_config.h>
+#include <unistd.h>
+#include <rpc-port.h>
+#include <rpc-port-internal.h>
+
+namespace mmi {
+
+namespace communication {
+
+CommunicationChannelTIDL::CommunicationChannelTIDL() {
+}
+
+CommunicationChannelTIDL::~CommunicationChannelTIDL() {
+}
+
+static void result_cb(void *user_data, const char *source_name, bundle *data) {
+ mmi_data_h restored_data = nullptr;
+
+ if (nullptr == user_data) {
+ LOGE("[ERROR] user_data is null");
+ return;
+ }
+
+ WorkflowInstance *workflow_instance = static_cast<WorkflowInstance *>(user_data);
+ unsigned char *bytes = nullptr;
+ size_t returned_size = 0;
+
+ if (BUNDLE_ERROR_NONE != bundle_get_byte(data, "data", (void**)&bytes, &returned_size)) {
+ LOGE("[ERROR] Failed to get bytes from bundle");
+ return;
+ }
+
+ if (nullptr == bytes || 0 == returned_size) {
+ LOGE("[ERROR] bytes is null or returned_size is 0");
+ return;
+ }
+
+ if (MMI_ERROR_NONE != mmi_data_from_bytes(bytes, returned_size, &restored_data)) {
+ LOGE("[ERROR] Failed to restore data from bytes");
+ return;
+ }
+
+ workflow_instance->call_output_callback(source_name, restored_data);
+}
+
+void CommunicationChannelTIDL::on_connected(rpc_port_proxy_mmi_h h, void *user_data) {
+ LOGI("[ENTER]");
+ CommunicationChannelTIDL *channel = static_cast<CommunicationChannelTIDL*>(user_data);
+ if (channel) {
+ channel->m_connected = true;
+ channel->notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::CONNECTED);
+ }
+}
+
+void CommunicationChannelTIDL::on_disconnected(rpc_port_proxy_mmi_h h, void *user_data) {
+ LOGI("[ENTER]");
+ CommunicationChannelTIDL *channel = static_cast<CommunicationChannelTIDL*>(user_data);
+ if (channel) {
+ channel->m_connected = false;
+ channel->notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::DISCONNECTED);
+ }
+}
+
+void CommunicationChannelTIDL::on_rejected(rpc_port_proxy_mmi_h h, void *user_data) {
+ LOGI("[ENTER]");
+ CommunicationChannelTIDL *channel = static_cast<CommunicationChannelTIDL*>(user_data);
+ if (channel) {
+ channel->m_connected = false;
+ channel->notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::DISCONNECTED);
+ }
+}
+
+int CommunicationChannelTIDL::connect() {
+ LOGI("[ENTER]");
+
+ if (m_rpc_h) {
+ LOGI("RPC Handle already exists");
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ rpc_port_proxy_mmi_callback_s callback;
+ callback.connected = on_connected;
+ callback.disconnected = on_disconnected;
+ callback.rejected = on_rejected;
+
+ int ret = rpc_port_proxy_mmi_create(m_stub_appid.c_str(), &callback, this, &m_rpc_h);
+ if (ret != RPC_PORT_ERROR_NONE) {
+ LOGE("Failed to create mmi proxy handle ! (error:%d)\n", ret);
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ ret = rpc_port_proxy_mmi_connect_sync(m_rpc_h);
+ if (ret != RPC_PORT_ERROR_NONE) {
+ LOGE("Try to connect again");
+ //Retry
+ ret = retry_connection(m_rpc_h);
+ if (ret != RPC_PORT_ERROR_NONE) {
+ LOGE("Fail to retry connection(%d)", ret);
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+ }
+
+ LOGI("Connected to mmi manager");
+
+ return MMI_ERROR_NONE;
+}
+
+int CommunicationChannelTIDL::disconnect(void) {
+ if (!m_rpc_h) {
+ LOGE("RPC Handle does not exist");
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ rpc_port_proxy_mmi_destroy(m_rpc_h);
+ rpc_port_deregister_proc_info();
+ m_rpc_h = nullptr;
+
+ m_connected = false;
+
+ LOGI("disconnected from mmi manager");
+
+ return MMI_ERROR_NONE;
+}
+
+int CommunicationChannelTIDL::send(Message *message) {
+ auto clientMessage = static_cast<ClientMessage*>(message);
+ CLIENT_MESSAGE_TYPE type = clientMessage->message_type;
+
+ switch(type) {
+ case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_CREATE: {
+ auto subclass = static_cast<ClientMessageWorkflowInstanceCreate*>(message);
+ workflow_instance_create(subclass->local_workflow_instance_id, subclass->workflow_type, subclass->user_data);
+ }
+ break;
+ case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_DESTROY: {
+ auto subclass = static_cast<ClientMessageWorkflowInstanceDestroy*>(message);
+ workflow_instance_destroy(subclass->local_workflow_instance_id);
+ }
+ break;
+ case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_SET_ATTRIBUTE: {
+ auto subclass = static_cast<ClientMessageWorkflowInstanceSetAttribute*>(message);
+ workflow_instance_set_attribute(subclass->local_workflow_instance_id, subclass->attribute);
+ }
+ break;
+ case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_ACTIVATE: {
+ auto subclass = static_cast<ClientMessageWorkflowInstanceActivate*>(message);
+ workflow_instance_activate(subclass->local_workflow_instance_id);
+ }
+ break;
+ case CLIENT_MESSAGE_TYPE::WORKFLOW_INSTANCE_DEACTIVATE: {
+ auto subclass = static_cast<ClientMessageWorkflowInstanceDeactivate*>(message);
+ workflow_instance_deactivate(subclass->local_workflow_instance_id);
+ }
+ break;
+ };
+
+ return MMI_ERROR_NONE;
+}
+
+bool CommunicationChannelTIDL::is_connected(void) {
+ return m_connected ? true : false;
+}
+
+int CommunicationChannelTIDL::retry_connection(rpc_port_proxy_mmi_h h) {
+ LOGI("Retry connection");
+
+ int ret = rpc_port_proxy_mmi_connect_sync(h);
+ if (ret != RPC_PORT_ERROR_NONE) {
+ LOGE("Fail to retry connection(%d)", ret);
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ return MMI_ERROR_NONE;
+}
+
+int CommunicationChannelTIDL::workflow_instance_create(int local_workflow_instance_id, mmi_standard_workflow_type_e workflow_type, void *user_data) {
+ LOGI("Creating workflow instance of type (%d) for id (%d)",
+ workflow_type, local_workflow_instance_id);
+
+ rpc_port_proxy_mmi_h rpc_h = static_cast<rpc_port_proxy_mmi_h>(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;
+ }
+ }
+
+ int ret = rpc_port_proxy_mmi_invoke_workflow_instance_create(
+ rpc_h, local_workflow_instance_id, workflow_type);
+ if (RPC_PORT_ERROR_NONE != ret) {
+ LOGE("Failed to create workflow instance(%d)\n", ret);
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ ret = workflow_instance_register_result_callback(local_workflow_instance_id, user_data);
+ if (MMI_ERROR_NONE != ret) {
+ LOGE("Failed to register result callback(%d)\n", ret);
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ return MMI_ERROR_NONE;
+}
+
+int CommunicationChannelTIDL::workflow_instance_destroy(int local_workflow_instance_id) {
+ LOGI("Destroying workflow instance of id (%d)", local_workflow_instance_id);
+
+ rpc_port_proxy_mmi_h rpc_h = static_cast<rpc_port_proxy_mmi_h>(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;
+ }
+ }
+
+ int ret = rpc_port_proxy_mmi_invoke_workflow_instance_destroy(
+ rpc_h, local_workflow_instance_id);
+ if (RPC_PORT_ERROR_NONE != ret) {
+ LOGE("Failed to destroy workflow instance(%d)\n", ret);
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ return MMI_ERROR_NONE;
+}
+
+int CommunicationChannelTIDL::workflow_instance_set_attribute(int local_workflow_instance_id, mmi_attribute_h attribute) {
+ LOGI("Setting attribute for workflow instance (%d)", local_workflow_instance_id);
+ int ret = MMI_ERROR_NONE;
+
+ if (NULL == attribute) {
+ LOGE("Parameter is NULL or empty");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ rpc_port_proxy_mmi_h rpc_h = static_cast<rpc_port_proxy_mmi_h>(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;
+ }
+ }
+
+ unsigned char *attribute_bytes = nullptr;
+ size_t attribute_byte_size = 0;
+ mmi_attribute_to_bytes(attribute, &attribute_bytes, &attribute_byte_size);
+
+ bundle *encoded = bundle_create();
+ bundle_add_byte(encoded, "data", attribute_bytes, attribute_byte_size);
+
+ if (encoded) {
+ int ret = rpc_port_proxy_mmi_invoke_workflow_instance_set_attribute(rpc_h, local_workflow_instance_id, encoded);
+ bundle_free(encoded);
+
+ if (RPC_PORT_ERROR_NONE != ret) {
+ LOGE("Failed to set workflow attribute(%d)\n", ret);
+ ret = MMI_ERROR_OPERATION_FAILED;
+ }
+ }
+
+ return ret;
+}
+
+int CommunicationChannelTIDL::workflow_instance_activate(int local_workflow_instance_id) {
+ LOGI("Activating workflow instance of id (%d)", local_workflow_instance_id);
+
+ rpc_port_proxy_mmi_h rpc_h = static_cast<rpc_port_proxy_mmi_h>(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;
+ }
+ }
+
+ int ret = rpc_port_proxy_mmi_invoke_workflow_instance_activate(
+ rpc_h, local_workflow_instance_id);
+ if (RPC_PORT_ERROR_NONE != ret) {
+ LOGE("Failed to activate workflow instance(%d)\n", ret);
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ return MMI_ERROR_NONE;
+}
+
+int CommunicationChannelTIDL::workflow_instance_deactivate(int local_workflow_instance_id) {
+ LOGI("Deactivating workflow instance of id (%d)", local_workflow_instance_id);
+
+ rpc_port_proxy_mmi_h rpc_h = static_cast<rpc_port_proxy_mmi_h>(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;
+ }
+ }
+
+ int ret = rpc_port_proxy_mmi_invoke_workflow_instance_deactivate(
+ rpc_h, local_workflow_instance_id);
+ if (RPC_PORT_ERROR_NONE != ret) {
+ LOGE("Failed to deactivate workflow instance(%d)\n", ret);
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ return MMI_ERROR_NONE;
+}
+
+int CommunicationChannelTIDL::workflow_instance_register_result_callback(int local_workflow_instance_id, void *user_data) {
+ LOGI("Registering result callback for workflow instance of id (%d)", local_workflow_instance_id);
+
+ if (nullptr == user_data) {
+ LOGE("Parameter is NULL or empty");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ rpc_port_proxy_mmi_h rpc_h = static_cast<rpc_port_proxy_mmi_h>(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;
+ }
+ }
+
+ rpc_port_proxy_mmi_result_cb_h result_cb_h = make_callback_handle(result_cb, user_data);
+
+ int ret = rpc_port_proxy_mmi_invoke_workflow_instance_register_result_callback(
+ rpc_h, local_workflow_instance_id, result_cb_h);
+ if (RPC_PORT_ERROR_NONE != ret) {
+ LOGE("Failed to register result callback(%d)\n", ret);
+ rpc_port_proxy_mmi_result_cb_destroy(result_cb_h);
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ LOGI("register result callback done");
+ return MMI_ERROR_NONE;
+}
+
+rpc_port_proxy_mmi_result_cb_h CommunicationChannelTIDL::make_callback_handle(rpc_port_proxy_mmi_result_cb_cb callback, void *user_data) {
+ rpc_port_proxy_mmi_result_cb_h result_cb_h;
+ int ret = rpc_port_proxy_mmi_result_cb_create(&result_cb_h);
+ if (RPC_PORT_ERROR_NONE != ret) {
+ LOGE("Failed to create result callback handle (error:%d)\n", ret);
+ return nullptr;
+ }
+ rpc_port_proxy_mmi_result_cb_set_callback(result_cb_h, callback, user_data);
+ rpc_port_proxy_mmi_result_cb_set_once(result_cb_h, false);
+ if (NULL == result_cb_h) {
+ LOGE("Failed to set result callback handle\n");
+ return nullptr;
+ }
+ return result_cb_h;
+}
+
+}; // namespace communication
+
+}; // namespace mmi
--- /dev/null
+/*
+ * 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.
+ *
+ */
+
+#ifndef __MMI_IPC_TIDL_H__
+#define __MMI_IPC_TIDL_H__
+
+#include "mmi.h"
+
+#include "mmi-communication-channel.h"
+
+#include "mmi_proxy.h"
+
+namespace mmi {
+
+namespace communication {
+
+class CommunicationChannelTIDL : public CommunicationChannelClient {
+public:
+ CommunicationChannelTIDL();
+ ~CommunicationChannelTIDL();
+
+ int connect() override;
+ int disconnect(void) override;
+ int send(communication::Message *message) override;
+
+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_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);
+
+ bool is_connected(void);
+ int retry_connection(rpc_port_proxy_mmi_h h);
+
+ static void on_connected(rpc_port_proxy_mmi_h h, void *user_data);
+ static void on_disconnected(rpc_port_proxy_mmi_h h, void *user_data);
+ static void on_rejected(rpc_port_proxy_mmi_h h, void *user_data);
+
+ static rpc_port_proxy_mmi_result_cb_h make_callback_handle(rpc_port_proxy_mmi_result_cb_cb callback, void *user_data);
+
+private:
+ rpc_port_proxy_mmi_h m_rpc_h{nullptr};
+ const std::string m_stub_appid{"mmi-manager"};
+ bool m_connected{false};
+};
+
+}; // namespace communication
+
+}; // namespace mmi
+
+#endif //__MMI_IPC_TIDL_H__
*
*/
-#ifndef __MMI_DBG_H__
-#define __MMI_DBG_H__
+#ifndef __MMI_LOG_H__
+#define __MMI_LOG_H__
#include <dlog.h>
#define _W LOGW
#endif
-#endif // __MMI_DBG_H__
+#endif // __MMI_LOG_H__
--- /dev/null
+/*
+ * 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-logic.h"
+
+#include "mmi-log.h"
+
+int mmi_standard_node_create_logic(mmi_standard_node_logic_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_LOGIC;
+ (*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_logic_type(mmi_node_h node, mmi_standard_node_logic_type_e *type) {
+ if (nullptr == node) {
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ *type = (mmi_standard_node_logic_type_e)node->sub_type;
+ return MMI_ERROR_NONE;
+}
+
+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;
+}
+
--- /dev/null
+/*
+ * 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-processor.h"
+
+#include "mmi-log.h"
+
+int mmi_standard_node_create_processor(mmi_standard_node_processor_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_PROCESSOR;
+ (*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_processor_type(mmi_node_h node, mmi_standard_node_processor_type_e *type) {
+ if (nullptr == node || nullptr == type) {
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ *type = (mmi_standard_node_processor_type_e)node->sub_type;
+ return MMI_ERROR_NONE;
+}
+
+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;
+}
+
--- /dev/null
+/*
+ * 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-source.h"
+
+#include "mmi-log.h"
+
+int mmi_standard_node_create_source(mmi_standard_node_source_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_SOURCE;
+ (*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_source_type(mmi_node_h node, mmi_standard_node_source_type_e *type) {
+ if (nullptr == type || nullptr == node) {
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ *type = (mmi_standard_node_source_type_e)node->sub_type;
+ return MMI_ERROR_NONE;
+}
+
--- /dev/null
+/*
+ * 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.h"
+#include "mmi-plugin-storage.h"
+
+#include "mmi-log.h"
+
+#include <new>
+
+int mmi_node_add_port(mmi_node_h node, mmi_port_h port) {
+ if (nullptr == node || nullptr == port) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_node_s *node_ptr = static_cast<mmi_node_s*>(node);
+
+ mmi_port_h *ports = node_ptr->ports;
+ size_t port_count = node_ptr->port_count;
+
+ node_ptr->ports = new(std::nothrow) mmi_port_h[port_count + 1];
+ if (nullptr == node_ptr->ports) {
+ node_ptr->ports = ports;
+ LOGE("[ERROR] failed to allocate memory");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+ if (port_count > 0) {
+ memcpy(node_ptr->ports, ports, sizeof(mmi_port_h) * port_count);
+ delete [] ports;
+ }
+
+ node_ptr->ports[port_count] = port;
+ node_ptr->port_count = port_count + 1;
+
+ return MMI_ERROR_NONE;
+}
+
+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");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_link(mmi_node_h from_node, mmi_node_h to_node) {
+ if (nullptr == from_node || nullptr == to_node) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_link_by_name(mmi_node_h from_node, const char *from_port_name, mmi_node_h to_node, const char *to_port_name) {
+ if (nullptr == from_node || nullptr == from_port_name || nullptr == to_node || nullptr == to_port_name) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_get_type(mmi_node_h node, mmi_standard_node_type_e *type) {
+ if (nullptr == node || nullptr == type) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ *type = (mmi_standard_node_type_e)node->type;
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_get_port_count(mmi_node_h node, size_t *port_count) {
+ if (nullptr == node || nullptr == port_count) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ *port_count = node->port_count;
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_get_port(mmi_node_h node, size_t index, mmi_port_h *port) {
+ if (nullptr == node || nullptr == port) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ if (index >= node->port_count) {
+ LOGE("[ERROR] index is out of range");
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+ *port = node->ports[index];
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_get_callbacks(mmi_node_h node, mmi_node_callbacks *callbacks) {
+ if (nullptr == node || nullptr == callbacks) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ *callbacks = node->callbacks;
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_set_callbacks(mmi_node_h node, mmi_node_callbacks callbacks) {
+ if (nullptr == node) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ node->callbacks = callbacks;
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_register(mmi_node_h node) {
+ if (nullptr == node) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_standard_node_type_e node_type;
+ mmi_node_get_type(node, &node_type);
+
+ const char *identifier = mmi_plugin_storage_get_current_module_identifier();
+ if (nullptr == identifier) {
+ LOGE("[ERROR] identifier is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_plugin_module_node_list_s list = mmi_plugin_storage_get_node_list(identifier);
+
+ mmi_node_h *nodes = list.nodes;
+ size_t node_count = list.node_count;
+
+ bool duplicated = false;
+ for (size_t i = 0; i < node_count; i++) {
+ mmi_standard_node_type_e type;
+ mmi_node_get_type(nodes[i], &type);
+
+ if (type == node_type) {
+ switch (type) {
+ case MMI_STANDARD_NODE_TYPE_SOURCE: {
+ mmi_standard_node_source_type_e node_source_type;
+ mmi_standard_node_get_source_type(node, &node_source_type);
+ mmi_standard_node_source_type_e source_type;
+ mmi_standard_node_get_source_type(nodes[i], &source_type);
+ if (node_source_type == source_type) {
+ duplicated = true;
+ }
+ break;
+ }
+ case MMI_STANDARD_NODE_TYPE_PROCESSOR: {
+ mmi_standard_node_processor_type_e node_processor_type;
+ mmi_standard_node_get_processor_type(node, &node_processor_type);
+ mmi_standard_node_processor_type_e processor_type;
+ mmi_standard_node_get_processor_type(nodes[i], &processor_type);
+ if (node_processor_type == processor_type) {
+ duplicated = true;
+ }
+ break;
+ }
+ case MMI_STANDARD_NODE_TYPE_LOGIC: {
+ mmi_standard_node_logic_type_e node_logic_type;
+ mmi_standard_node_get_logic_type(node, &node_logic_type);
+ mmi_standard_node_logic_type_e logic_type;
+ mmi_standard_node_get_logic_type(nodes[i], &logic_type);
+ if (node_logic_type == logic_type) {
+ duplicated = true;
+ }
+ break;
+ }
+ 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);
+ mmi_standard_node_controller_type_e controller_type;
+ mmi_standard_node_get_controller_type(nodes[i], &controller_type);
+ if (node_controller_type == controller_type) {
+ duplicated = true;
+ }
+ break;
+ }
+ }
+ }
+ if (duplicated) {
+ mmi_node_h cloned;
+ mmi_node_clone(node, &cloned);
+ mmi_node_destroy(nodes[i]);
+ nodes[i] = cloned;
+ break;
+ }
+ }
+
+ if (!duplicated) {
+ list.nodes = new(std::nothrow) mmi_node_h[node_count + 1];
+ if (nullptr == list.nodes) {
+ LOGE("[ERROR] failed to allocate memory");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+ if (node_count > 0) {
+ memcpy(list.nodes, nodes, sizeof(mmi_node_h) * node_count);
+ delete [] nodes;
+ }
+ mmi_node_h cloned;
+ mmi_node_clone(node, &cloned);
+ list.nodes[node_count] = cloned;
+ list.node_count = node_count + 1;
+ }
+
+ mmi_plugin_storage_set_node_list(list);
+
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_clone(mmi_node_h node, mmi_node_h *cloned) {
+ if (nullptr == node || nullptr == cloned) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_node_s *node_ptr = static_cast<mmi_node_s*>(node);
+
+ mmi_node_s *cloned_ptr = new(std::nothrow) mmi_node_s;
+ if (nullptr == cloned_ptr) {
+ LOGE("[ERROR] failed to allocate memory");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ cloned_ptr->type = node_ptr->type;
+ cloned_ptr->sub_type = node_ptr->sub_type;
+ cloned_ptr->port_count = node_ptr->port_count;
+ cloned_ptr->callbacks = node_ptr->callbacks;
+
+ cloned_ptr->ports = new(std::nothrow) mmi_port_h[node_ptr->port_count];
+ if (nullptr == cloned_ptr->ports) {
+ LOGE("[ERROR] failed to allocate memory");
+ delete cloned_ptr;
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ for (int i = 0; i < node_ptr->port_count; i++) {
+ mmi_port_clone(node_ptr->ports[i], &cloned_ptr->ports[i]);
+ }
+
+ *cloned = cloned_ptr;
+
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_destroy(mmi_node_h node) {
+ if (nullptr == node) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ for (int i = 0; i < node->port_count; i++) {
+ mmi_port_destroy(node->ports[i]);
+ }
+ delete [] node->ports;
+ delete node;
+
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_instance_set_attribute(mmi_node_instance_h instance, mmi_attribute_h attribute) {
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_instance_find_port(mmi_node_instance_h instance, mmi_port_type_e port_type, const char *port_name, mmi_port_instance_h *port) {
+ if (instance == NULL || port_name == NULL || port == NULL) {
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ *port = mmi_plugin_storage_find_port_instance(instance, port_name);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_instance_find_sibling_port(mmi_port_instance_h instance, const char *port_name, mmi_port_instance_h *sibling) {
+ if (instance == NULL || port_name == NULL || sibling == NULL) {
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ mmi_node_instance_h node_instance = mmi_plugin_storage_find_node_instance_by_port_instance(instance);
+ if (node_instance == NULL) {
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ *sibling = mmi_plugin_storage_find_port_instance(node_instance, port_name);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_instance_emit_signal(mmi_node_instance_h instance, mmi_signal_h signal) {
+ return MMI_ERROR_NONE;
+}
+
+int mmi_node_instance_update_pending_activation_result(mmi_error_e result) {
+ return MMI_ERROR_NONE;
+}
--- /dev/null
+/*
+ * 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_PLUGIN_STORAGE_IMPL_H__
+#define __MMI_PLUGIN_STORAGE_IMPL_H__
+
+#include <string>
+#include <vector>
+#include <map>
+
+#include "mmi-log.h"
+
+class PluginStorageImpl {
+public:
+ PluginStorageImpl() {
+ }
+
+ ~PluginStorageImpl() {
+ for (auto &it : m_node_lists) {
+ for (int loop = 0; loop < it.second.node_count; loop++) {
+ mmi_node_destroy(it.second.nodes[loop]);
+ }
+ delete [] it.second.nodes;
+ }
+ for (auto &it : m_workflow_lists) {
+ for (int loop = 0; loop < it.second.workflow_count; loop++) {
+ mmi_workflow_destroy(it.second.workflows[loop]);
+ }
+ delete [] it.second.workflows;
+ }
+ }
+
+ void set_current_identifier(const char *identifier) {
+ if (identifier == nullptr) {
+ LOGE("Identifier is null");
+ return;
+ }
+ m_current_identifier = identifier;
+ }
+
+ const char* get_current_identifier() {
+ return m_current_identifier.c_str();
+ }
+
+ void set_node_list(mmi_plugin_module_node_list_s node_list) {
+ m_node_lists[m_current_identifier] = node_list;
+ }
+
+ void set_workflow_list(mmi_plugin_module_workflow_list_s workflow_list) {
+ m_workflow_lists[m_current_identifier] = workflow_list;
+ }
+
+ mmi_plugin_module_node_list_s get_node_list(const char *identifier) {
+ return m_node_lists[identifier];
+ }
+
+ mmi_plugin_module_workflow_list_s get_workflow_list(const char *identifier) {
+ return m_workflow_lists[identifier];
+ }
+
+ void add_node_instance_info(mmi_plugin_module_node_instance_info_s *info) {
+ m_node_instance_infos.push_back(*info);
+ }
+
+ void remove_node_instance_info(mmi_node_instance_h node_instance) {
+ for (auto it = m_node_instance_infos.begin(); it != m_node_instance_infos.end(); ++it) {
+ if (it->node == node_instance) {
+ m_node_instance_infos.erase(it);
+ break;
+ }
+ }
+ }
+
+ mmi_port_instance_h find_port_instance(mmi_node_instance_h node_instance, const char *port_name) {
+ for (auto &info : m_node_instance_infos) {
+ if (info.node == node_instance) {
+ for (int loop = 0; loop < info.port_info_count; loop++) {
+ if (strncmp(info.port_infos[loop].name, port_name, MMI_NAME_MAX_LENGTH) == 0) {
+ return info.port_infos[loop].port;
+ }
+ }
+ }
+ }
+ return nullptr;
+ }
+
+ mmi_node_instance_h find_node_instance_by_port_instance(mmi_port_instance_h port_instance) {
+ for (auto &info : m_node_instance_infos) {
+ for (int loop = 0; loop < info.port_info_count; loop++) {
+ if (info.port_infos[loop].port == port_instance) {
+ return info.node;
+ }
+ }
+ }
+ return nullptr;
+ }
+private:
+ std::string m_current_identifier;
+
+ std::map<std::string, mmi_plugin_module_node_list_s> m_node_lists;
+ std::map<std::string, mmi_plugin_module_workflow_list_s> m_workflow_lists;
+
+ /* Better to use std::map since find_port_instance() would be called frequently */
+ std::vector<mmi_plugin_module_node_instance_info_s> m_node_instance_infos;
+};
+
+
+#endif /* __MMI_PLUGIN_STORAGE_IMPL_H__ */
--- /dev/null
+/*
+ * 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-plugin-storage.h"
+#include "mmi-plugin-storage-impl.h"
+
+PluginStorageImpl g_plugin_storage_impl;
+
+void mmi_plugin_storage_set_current_module_identifier(const char *identifier) {
+ g_plugin_storage_impl.set_current_identifier(identifier);
+}
+
+const char* mmi_plugin_storage_get_current_module_identifier() {
+ return g_plugin_storage_impl.get_current_identifier();
+}
+
+void mmi_plugin_storage_set_node_list(mmi_plugin_module_node_list_s node_list) {
+ g_plugin_storage_impl.set_node_list(node_list);
+}
+
+void mmi_plugin_storage_set_workflow_list(mmi_plugin_module_workflow_list_s workflow_list) {
+ g_plugin_storage_impl.set_workflow_list(workflow_list);
+}
+
+mmi_plugin_module_node_list_s mmi_plugin_storage_get_node_list(const char *identifier) {
+ return g_plugin_storage_impl.get_node_list(identifier);
+}
+
+mmi_plugin_module_workflow_list_s mmi_plugin_storage_get_workflow_list(const char *identifier) {
+ return g_plugin_storage_impl.get_workflow_list(identifier);
+}
+
+void mmi_plugin_storage_add_node_instance_info(mmi_plugin_module_node_instance_info_s *info) {
+ g_plugin_storage_impl.add_node_instance_info(info);
+}
+
+void mmi_plugin_storage_remove_node_instance_info(mmi_node_instance_h node_instance) {
+ g_plugin_storage_impl.remove_node_instance_info(node_instance);
+}
+
+mmi_port_instance_h mmi_plugin_storage_find_port_instance(
+ mmi_node_instance_h node_instance, const char *port_name) {
+ return g_plugin_storage_impl.find_port_instance(node_instance, port_name);
+}
+
+mmi_node_instance_h mmi_plugin_storage_find_node_instance_by_port_instance(mmi_port_instance_h port_instance) {
+ return g_plugin_storage_impl.find_node_instance_by_port_instance(port_instance);
+}
+
+static mmi_plugin_module_event_handler_info_s g_event_handler_info{nullptr, };
+static void* g_event_handler_user_data = nullptr;
+
+void mmi_plugin_storage_set_plugin_module_event_handler(
+ mmi_plugin_module_event_handler_info_s handler_info, void *user_data) {
+ g_event_handler_info = handler_info;
+ g_event_handler_user_data = user_data;
+}
+
+void mmi_plugin_storage_unset_plugin_module_event_handler() {
+ memset(&g_event_handler_info, 0x00, sizeof(g_event_handler_info));
+ g_event_handler_user_data = nullptr;
+}
+
+mmi_plugin_module_event_handler_info_s mmi_plugin_storage_get_plugin_module_event_handler() {
+ return g_event_handler_info;
+}
+
+void* mmi_plugin_storage_get_plugin_module_event_handler_user_data() {
+ return g_event_handler_user_data;
+}
--- /dev/null
+/*
+ * 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-log.h"
+#include "mmi-port.h"
+#include "mmi-plugin-storage.h"
+
+#include <new>
+#include <cstdio>
+
+MMI_API int mmi_port_create(mmi_port_h *port) {
+ if (nullptr == port) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_port_s *port_s = new (std::nothrow) mmi_port_s;
+ if (nullptr == port_s) {
+ LOGE("[ERROR] failed to create port");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+ memset(port_s, 0, sizeof(mmi_port_s));
+
+ *port = port_s;
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_port_get_name(mmi_port_h port, char **name, size_t *length) {
+ if (nullptr == port || nullptr == name || nullptr == length) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_port_s *port_s = static_cast<mmi_port_s*>(port);
+
+ *name = port_s->name;
+ *length = strlen(*name);
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_port_get_type(mmi_port_h port, mmi_port_type_e *type) {
+ if (nullptr == port || nullptr == type) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_port_s *port_s = static_cast<mmi_port_s*>(port);
+
+ *type = port_s->type;
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_port_get_data_type(mmi_port_h port, mmi_data_type_e *data_type) {
+ if (nullptr == port || nullptr == data_type) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_port_s *port_s = static_cast<mmi_port_s*>(port);
+
+ *data_type = port_s->data_type;
+
+ return MMI_ERROR_NONE;
+}
+
+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");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_port_s *port_s = static_cast<mmi_port_s*>(port);
+
+ *callbacks = port_s->callbacks;
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_port_set_name(mmi_port_h port, const char *name) {
+ if (nullptr == port || nullptr == name) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_port_s *port_s = static_cast<mmi_port_s*>(port);
+
+ std::snprintf(port_s->name, MMI_NAME_MAX_LENGTH, "%s", name);
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_port_set_type(mmi_port_h port, mmi_port_type_e type) {
+ if (nullptr == port) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_port_s *port_s = static_cast<mmi_port_s*>(port);
+
+ port_s->type = type;
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_port_set_data_type(mmi_port_h port, mmi_data_type_e data_type) {
+ if (nullptr == port) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_port_s *port_s = static_cast<mmi_port_s*>(port);
+
+ port_s->data_type = data_type;
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_port_set_callbacks(mmi_port_h port, mmi_port_callbacks callbacks) {
+ if (nullptr == port) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_port_s *port_s = static_cast<mmi_port_s*>(port);
+
+ port_s->callbacks = callbacks;
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_port_clone(mmi_port_h port, mmi_port_h *cloned) {
+ if (nullptr == port || nullptr == cloned) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_port_s *port_s = static_cast<mmi_port_s*>(port);
+
+ *cloned = new (std::nothrow) mmi_port_s;
+ if (nullptr == *cloned) {
+ LOGE("[ERROR] failed to clone port");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ strncpy((*cloned)->name, port_s->name, MMI_NAME_MAX_LENGTH);
+ (*cloned)->type = port_s->type;
+ (*cloned)->data_type = port_s->data_type;
+ (*cloned)->callbacks = port_s->callbacks;
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_port_destroy(mmi_port_h port) {
+ if (nullptr == port) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ delete port;
+
+ return MMI_ERROR_NONE;
+}
+
+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();
+
+ mmi_plugin_module_port_instance_output_handler_func output_handler = event_handler_info.port_instance_output_handler;
+ if (output_handler) {
+ output_handler(instance, data, user_data);
+ }
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_port_instance_request_auto_transform(mmi_port_instance_h instance, const char *from_format, const char *to_format) {
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_port_instance_request_input_data_format(mmi_port_instance_h instance, const char *format) {
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_port_instance_announce_output_data_format(mmi_port_instance_h instance, const char *format) {
+ return MMI_ERROR_NONE;
+}
--- /dev/null
+/*
+ * 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-error.h>
+#include <mmi-primitive-value.h>
+
+#include "mmi-log.h"
+
+
+struct mmi_primitive_value_s {
+ mmi_primitive_value_type_e type;
+ void *data;
+ size_t datalen;
+};
+
+static const size_t g_unit_size = sizeof(mmi_primitive_value_h);
+
+
+static inline size_t get_array_count(mmi_primitive_value_h array) {
+ if (nullptr != array) {
+ return array->datalen / g_unit_size;
+ }
+
+ return 0;
+}
+
+static inline mmi_primitive_value_h *get_element_pointer_in_array(mmi_primitive_value_h array, size_t index) {
+ return reinterpret_cast<mmi_primitive_value_h *>(array->data) + index;
+}
+
+int mmi_primitive_value_create_int(int data, mmi_primitive_value_h *handle) {
+ if (nullptr == handle) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto primitive_value = reinterpret_cast<mmi_primitive_value_s *>(malloc(sizeof(mmi_primitive_value_s)));
+ if (nullptr == primitive_value) {
+ _E("[ERROR] Fail to allocate memory for primitive value");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ primitive_value->type = MMI_PRIMITIVE_VALUE_TYPE_INT;
+ primitive_value->data = reinterpret_cast<void *>(malloc(sizeof(int)));
+ if (nullptr == primitive_value->data) {
+ _E("[ERROR] Fail to allocate memory for raw data");
+ free(primitive_value);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ *(reinterpret_cast<int *>(primitive_value->data)) = data;
+ primitive_value->datalen = sizeof(int);
+
+ *handle = primitive_value;
+
+ _D("[DEBUG] Success to create for int(%d)", data);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_create_float(float data, mmi_primitive_value_h *handle) {
+ if (nullptr == handle) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto primitive_value = reinterpret_cast<mmi_primitive_value_s *>(malloc(sizeof(mmi_primitive_value_s)));
+ if (nullptr == primitive_value) {
+ _E("[ERROR] Fail to allocate memory for primitive value");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ primitive_value->type = MMI_PRIMITIVE_VALUE_TYPE_FLOAT;
+ primitive_value->data = reinterpret_cast<void *>(malloc(sizeof(float)));
+ if (nullptr == primitive_value->data) {
+ _E("[ERROR] Fail to allocate memory for raw data");
+ free(primitive_value);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ *(reinterpret_cast<float *>(primitive_value->data)) = data;
+ primitive_value->datalen = sizeof(float);
+
+ *handle = primitive_value;
+
+ _D("[DEBUG] Success to create for float(%f)", data);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_create_string(const char *data, mmi_primitive_value_h *handle) {
+ if (nullptr == handle || nullptr == data) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto primitive_value = reinterpret_cast<mmi_primitive_value_s *>(malloc(sizeof(mmi_primitive_value_s)));
+ if (nullptr == primitive_value) {
+ _E("[ERROR] Fail to allocate memory for primitive value");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ primitive_value->type = MMI_PRIMITIVE_VALUE_TYPE_STRING;
+ primitive_value->data = reinterpret_cast<void *>(strdup(data));
+ primitive_value->datalen = strlen(data) + 1; /* including null character */
+
+ *handle = primitive_value;
+
+ _D("[DEBUG] Success to create for string(%s)", data);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_create_bool(bool data, mmi_primitive_value_h *handle) {
+ if (nullptr == handle) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto primitive_value = reinterpret_cast<mmi_primitive_value_s *>(malloc(sizeof(mmi_primitive_value_s)));
+ if (nullptr == primitive_value) {
+ _E("[ERROR] Fail to allocate memory for primitive value");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ primitive_value->type = MMI_PRIMITIVE_VALUE_TYPE_BOOL;
+ primitive_value->data = reinterpret_cast<void *>(malloc(sizeof(int)));
+ if (nullptr == primitive_value->data) {
+ _E("[ERROR] Fail to allocate memory for raw data");
+ free(primitive_value);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ *(reinterpret_cast<int *>(primitive_value->data)) = static_cast<int>(data);
+ primitive_value->datalen = sizeof(int);
+
+ *handle = primitive_value;
+
+ _D("[DEBUG] Success to create for boolean(%s)", data ? "true" : "false");
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_create_array(mmi_primitive_value_h *handle) {
+ if (nullptr == handle) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto primitive_value = reinterpret_cast<mmi_primitive_value_s *>(malloc(sizeof(mmi_primitive_value_s)));
+ if (nullptr == primitive_value) {
+ _E("[ERROR] Fail to allocate memory for primitive value");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ primitive_value->type = MMI_PRIMITIVE_VALUE_TYPE_ARRAY;
+ primitive_value->data = nullptr;
+ primitive_value->datalen = 0;
+
+ *handle = primitive_value;
+
+ _D("[DEBUG] Success to create empty array");
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_add_array_element(mmi_primitive_value_h array, mmi_primitive_value_h element) {
+ if (nullptr == array || nullptr == element) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (array->type != MMI_PRIMITIVE_VALUE_TYPE_ARRAY) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ size_t count = get_array_count(array);
+ if (count > 0) {
+ mmi_primitive_value_h first = nullptr;
+ mmi_primitive_value_get_array_element(array, 0, &first);
+
+ if (first->type != element->type) {
+ _E("[ERROR] Element type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ }
+
+ auto array_data = reinterpret_cast<mmi_primitive_value_h *>(array->data);
+ array_data = reinterpret_cast<mmi_primitive_value_h *>(realloc(array_data, g_unit_size * (count + 1)));
+ if (array_data) {
+ array_data[count] = element;
+
+ array->data = array_data;
+ array->datalen = array->datalen + g_unit_size;
+ } else {
+ _E("[ERROR] Fail to allocate memory for array element");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ _D("[DEBUG] Success to add element(%zu)", get_array_count(array));
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_get_type(mmi_primitive_value_h handle, mmi_primitive_value_type_e *type) {
+ if (nullptr == handle || nullptr == type) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *type = handle->type;
+
+ _D("[DEBUG] Success to get type(%d)", *type);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_get_int(mmi_primitive_value_h handle, int *value) {
+ if (nullptr == handle || nullptr == value) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (handle->type != MMI_PRIMITIVE_VALUE_TYPE_INT) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *value = *(reinterpret_cast<int *>(handle->data));
+
+ _D("[DEBUG] Success to get value: int(%d)", *value);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_get_float(mmi_primitive_value_h handle, float *value) {
+ if (nullptr == handle || nullptr == value) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (handle->type != MMI_PRIMITIVE_VALUE_TYPE_FLOAT) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *value = *(reinterpret_cast<float *>(handle->data));
+
+ _D("[DEBUG] Success to get value: float(%f)", *value);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_get_string(mmi_primitive_value_h handle, const char **string) {
+ if (nullptr == handle || nullptr == string) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (handle->type != MMI_PRIMITIVE_VALUE_TYPE_STRING) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *string = reinterpret_cast<char *>(handle->data);
+
+ _D("[DEBUG] Success to get value: string(%s)", *string);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_get_bool(mmi_primitive_value_h handle, bool *value) {
+ if (nullptr == handle || nullptr == value) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (handle->type != MMI_PRIMITIVE_VALUE_TYPE_BOOL) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ int data = *(reinterpret_cast<int *>(handle->data));
+ *value = (data != 0);
+
+ _D("[DEBUG] Success to get value: boolean(%s)", *value ? "true" : "false");
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_get_array_count(mmi_primitive_value_h array, size_t *count) {
+ if (nullptr == array || nullptr == count) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (array->type != MMI_PRIMITIVE_VALUE_TYPE_ARRAY) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *count = get_array_count(array);
+
+ _D("[DEBUG] Success to get array count(%zu)", *count);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_get_array_element(mmi_primitive_value_h array, size_t index, mmi_primitive_value_h *element) {
+ if (nullptr == array || nullptr == element) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (array->type != MMI_PRIMITIVE_VALUE_TYPE_ARRAY) {
+ _E("[ERROR] Data type is not matched");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ size_t count = get_array_count(array);
+ if (index >= count) {
+ _E("[ERROR] index(%zu) is out of range. count(%zu)", index, count);
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ *element = *(get_element_pointer_in_array(array, index));
+
+ _D("[DEBUG] Success to get array element on index(%zu)", index);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_clone(mmi_primitive_value_h handle, mmi_primitive_value_h *cloned) {
+ if (nullptr == handle || nullptr == cloned) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ auto cloned_value = reinterpret_cast<mmi_primitive_value_s *>(malloc(sizeof(mmi_primitive_value_s)));
+ cloned_value->type = handle->type;
+ cloned_value->datalen = handle->datalen;
+ cloned_value->data = calloc(1, handle->datalen);
+ if (nullptr == cloned_value->data) {
+ _E("[ERROR] Fail to allocate memory for data");
+ free(cloned_value);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (handle->type == MMI_PRIMITIVE_VALUE_TYPE_ARRAY) {
+ const size_t count = get_array_count(handle);
+ for (size_t i = 0; i < count; i++) {
+ auto element = get_element_pointer_in_array(handle, i);
+ if (nullptr == element) {
+ _E("[ERROR] Fail to get element");
+ mmi_primitive_value_destroy(cloned_value);
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ mmi_primitive_value_clone(*element, get_element_pointer_in_array(cloned_value, i));
+ }
+ } else {
+ memcpy(cloned_value->data, handle->data, handle->datalen);
+ }
+
+ *cloned = cloned_value;
+
+ _D("[DEBUG] Success to clone data. type(%d)", cloned_value->type);
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_destroy(mmi_primitive_value_h handle) {
+ if (nullptr == handle) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (handle->type == MMI_PRIMITIVE_VALUE_TYPE_ARRAY) {
+ size_t count = get_array_count(handle);
+ for (size_t i = 0; i < count; i++) {
+ auto element = get_element_pointer_in_array(handle, i);
+ mmi_primitive_value_destroy(*element);
+ }
+ }
+
+ if (handle->data != NULL) {
+ free(handle->data);
+ }
+
+ free(handle);
+
+ _D("[DEBUG] Success to destroy");
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_to_bytes(mmi_primitive_value_h handle, unsigned char **bytes, size_t *size)
+{
+ if (nullptr == handle || nullptr == bytes || nullptr == size) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_primitive_value_type_e type;
+ mmi_primitive_value_get_type(handle, &type);
+ if (type == MMI_PRIMITIVE_VALUE_TYPE_ARRAY) {
+ size_t current_size = sizeof(mmi_primitive_value_type_e) + sizeof(size_t);
+ unsigned char *buffer = reinterpret_cast<unsigned char *>(malloc(current_size));
+ size_t count = get_array_count(handle);
+ unsigned char *current = buffer;
+ memcpy(current, &type, sizeof(mmi_primitive_value_type_e));
+ current += sizeof(mmi_primitive_value_type_e);
+ /* This size will be updated after getting element bytes */
+ memcpy(current, &count, sizeof(size_t));
+ current += sizeof(size_t);
+ for (size_t i = 0; i < count; i++) {
+ auto element = get_element_pointer_in_array(handle, i);
+ unsigned char *element_bytes = nullptr;
+ size_t element_size = 0;
+ mmi_primitive_value_to_bytes(*element, &element_bytes, &element_size);
+ buffer = reinterpret_cast<unsigned char *>(realloc(buffer, current_size + element_size + sizeof(size_t)));
+ if (nullptr == buffer) {
+ _E("[ERROR] Fail to allocate memory for buffer");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+ current = buffer + current_size;
+ memcpy(current, &element_size, sizeof(size_t));
+ current += sizeof(size_t);
+ current_size += sizeof(size_t);
+ memcpy(current, element_bytes, element_size);
+ current_size += element_size;
+ free(element_bytes);
+ }
+ size_t total_element_size = current_size - sizeof(mmi_primitive_value_type_e) - sizeof(size_t);
+ memcpy(buffer + sizeof(mmi_primitive_value_type_e), &total_element_size, sizeof(size_t));
+
+ *bytes = buffer;
+ *size = current_size;
+ } else {
+ size_t total_size = sizeof(mmi_primitive_value_type_e) + sizeof(size_t) + handle->datalen;
+ unsigned char *buffer = reinterpret_cast<unsigned char *>(malloc(total_size));
+ if (nullptr == buffer) {
+ _E("[ERROR] Fail to allocate memory for buffer");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+ unsigned char *current = buffer;
+ memcpy(current, &(handle->type), sizeof(mmi_primitive_value_type_e));
+ current += sizeof(mmi_primitive_value_type_e);
+ memcpy(current, &(handle->datalen), sizeof(size_t));
+ current += sizeof(size_t);
+ memcpy(current, handle->data, handle->datalen);
+
+ *bytes = buffer;
+ *size = total_size;
+ }
+
+ _D("[DEBUG] Success to convert to bytes");
+
+ return MMI_ERROR_NONE;
+}
+
+int mmi_primitive_value_from_bytes(unsigned char *bytes, size_t size, mmi_primitive_value_h *handle)
+{
+ if (nullptr == bytes || nullptr == handle) {
+ _E("[ERROR] Some parameters are invalid");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ unsigned char *current = bytes;
+ mmi_primitive_value_type_e type;
+ memcpy(&type, current, sizeof(mmi_primitive_value_type_e));
+ current += sizeof(mmi_primitive_value_type_e);
+ if (type == MMI_PRIMITIVE_VALUE_TYPE_ARRAY) {
+ size_t datalen;
+ /* This datalen variable will not be used for array type */
+ memcpy(&datalen, current, sizeof(size_t));
+ current += sizeof(size_t);
+ void *data = nullptr;
+ auto value = reinterpret_cast<mmi_primitive_value_s *>(malloc(sizeof(mmi_primitive_value_s)));
+ value->type = type;
+ value->datalen = 0;
+ value->data = nullptr;
+
+ size_t num_elements = 0;
+ while (current < bytes + size) {
+ bool failed = false;
+ mmi_primitive_value_h element = nullptr;
+
+ size_t element_size;
+ memcpy(&element_size, current, sizeof(size_t));
+ current += sizeof(size_t);
+
+ unsigned char *element_bytes = reinterpret_cast<unsigned char *>(malloc(element_size));
+ if (element_bytes) {
+ memcpy(element_bytes, current, element_size);
+ current += element_size;
+ mmi_primitive_value_from_bytes(element_bytes, element_size, &element);
+ free(element_bytes);
+ } else {
+ _E("[ERROR] Fail to allocate memory for element_bytes");
+ failed = true;
+ }
+ if (nullptr == element) {
+ _E("[ERROR] Fail to convert element from bytes");
+ failed = true;
+ }
+
+ if (failed) {
+ /* Since we are in a while loop, value->data should also be freed */
+ size_t num_elements = value->datalen / sizeof(mmi_primitive_value_h);
+ for (size_t i = 0; i < num_elements; i++) {
+ auto element = get_element_pointer_in_array(value, i);
+ mmi_primitive_value_destroy(*element);
+ }
+ free(value->data);
+ free(value);
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ mmi_primitive_value_add_array_element(value, element);
+ num_elements++;
+ }
+
+ *handle = value;
+ } else {
+ size_t datalen;
+ memcpy(&datalen, current, sizeof(size_t));
+ current += sizeof(size_t);
+ void *data = calloc(1, datalen);
+ if (nullptr == data) {
+ _E("[ERROR] Fail to allocate memory for data");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+ memcpy(data, current, datalen);
+
+ auto value = reinterpret_cast<mmi_primitive_value_s *>(malloc(sizeof(mmi_primitive_value_s)));
+ value->type = type;
+ value->datalen = datalen;
+ value->data = data;
+
+ *handle = value;
+ }
+
+ _D("[DEBUG] Success to convert from bytes. type(%d), size(%zu)", type, size);
+
+ return MMI_ERROR_NONE;
+}
+
--- /dev/null
+/*
+ * 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-signal.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;
+ }
+
+ *signal_parameter = (mmi_signal_parameter_s*)calloc(1, sizeof(mmi_signal_parameter_s));
+ if (*signal_parameter == NULL) return -1;
+
+ 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;
+}
+
+MMI_API int mmi_signal_parameter_get_name(mmi_signal_parameter_h signal_parameter, char **name) {
+ if (signal_parameter == NULL || name == NULL) {
+ return -1;
+ }
+ *name = strdup(signal_parameter->name);
+ return 0;
+}
+
+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;
+ }
+ mmi_primitive_value_clone(signal_parameter->value, value);
+ return 0;
+}
+
+MMI_API int mmi_signal_parameter_clone(mmi_signal_parameter_h signal_parameter, mmi_signal_parameter_h *cloned) {
+ if (cloned == NULL) {
+ return -1;
+ }
+
+ *cloned = (mmi_signal_parameter_s*)calloc(1, sizeof(mmi_signal_parameter_s));
+ if (*cloned == NULL) return -1;
+
+ 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;
+}
+
+MMI_API int mmi_signal_parameter_destroy(mmi_signal_parameter_h signal_parameter) {
+ if (signal_parameter == NULL) {
+ return -1;
+ }
+ mmi_primitive_value_destroy(signal_parameter->value);
+ free(signal_parameter);
+ return 0;
+}
+
+MMI_API int mmi_signal_create(const char *name, mmi_signal_h *handle) {
+ if (handle == NULL) {
+ return -1;
+ }
+
+ *handle = (mmi_signal_s*)calloc(1, sizeof(mmi_signal_s));
+ if (*handle == NULL) return -1;
+
+ strncpy((*handle)->name, name, MMI_NAME_MAX_LENGTH - 1);
+ (*handle)->name[MMI_NAME_MAX_LENGTH - 1] = '\0';
+
+ return 0;
+}
+
+MMI_API int mmi_signal_add_parameter(mmi_signal_h handle, mmi_signal_parameter_h parameter) {
+ if (handle == NULL || parameter == NULL) {
+ return -1;
+ }
+
+ if (handle->parameter_count >= MMI_PARAMETER_MAX_COUNT) {
+ return -1;
+ }
+
+ mmi_signal_parameter_clone(parameter, &handle->parameters[handle->parameter_count]);
+ handle->parameter_count++;
+
+ return 0;
+}
+
+MMI_API int mmi_signal_get_name(mmi_signal_h handle, char **name) {
+ if (handle == NULL || name == NULL) {
+ return -1;
+ }
+ *name = handle->name;
+ return 0;
+}
+
+MMI_API int mmi_signal_get_parameter_count(mmi_signal_h handle, int *count) {
+ if (handle == NULL || count == NULL) {
+ return -1;
+ }
+ *count = handle->parameter_count;
+ return 0;
+}
+
+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;
+ }
+
+ if (index < 0 || index >= handle->parameter_count) {
+ return -1;
+ }
+
+ mmi_signal_parameter_clone(handle->parameters[index], parameter);
+
+ return 0;
+}
+
+MMI_API int mmi_signal_destroy(mmi_signal_h handle) {
+ if (handle == NULL) {
+ return -1;
+ }
+
+ for (int i = 0; i < handle->parameter_count; i++) {
+ mmi_signal_parameter_destroy(handle->parameters[i]);
+ }
+
+ free(handle);
+ return 0;
+}
--- /dev/null
+/*
+ * 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_WORKFLOW_INSTANCE_MANAGER_H__
+#define __MMI_WORKFLOW_INSTANCE_MANAGER_H__
+
+#include "mmi.h"
+
+#include <map>
+#include <memory>
+
+namespace mmi {
+
+class WorkflowInstance {
+public:
+ WorkflowInstance(int local_workflow_instance_id, mmi_standard_workflow_type_e workflow_type)
+ : m_local_workflow_instance_id(local_workflow_instance_id), m_workflow_type(workflow_type) {
+ }
+ virtual ~WorkflowInstance() {}
+
+ bool initialize() {
+ return true;
+ }
+
+ bool deinitialize() {
+ return true;
+ }
+
+ int get_local_workflow_instance_id() {
+ return m_local_workflow_instance_id;
+ }
+
+ mmi_standard_workflow_type_e get_workflow_type() {
+ return m_workflow_type;
+ }
+
+ bool add_output_callback(std::string key, mmi_workflow_output_cb callback, void *user_data) {
+ bool ret = false;
+ if (callback) {
+ callbacks[key] = std::make_pair(callback, user_data);
+ ret = true;
+ }
+ return ret;
+ }
+
+ bool call_output_callback(std::string key, mmi_data_h data) {
+ bool ret = false;
+ if (callbacks.find(key) != callbacks.end()) {
+ auto callback = callbacks[key];
+ callback.first(static_cast<mmi_workflow_instance_h>(this), key.c_str(), data, callback.second);
+ ret = true;
+ }
+ return ret;
+ }
+
+private:
+ int m_local_workflow_instance_id;
+ mmi_standard_workflow_type_e m_workflow_type;
+ // TODO: make duplicate possible
+ std::map<std::string, std::pair<mmi_workflow_output_cb, void *>> callbacks;
+};
+
+class WorkflowInstanceManager {
+public:
+ WorkflowInstanceManager() {}
+ virtual ~WorkflowInstanceManager() {}
+
+ bool initialize() {
+ return true;
+ }
+ bool deinitialize() {
+ for (auto instance : m_instances) {
+ instance->deinitialize();
+ delete instance;
+ }
+ m_instances.clear();
+ return true;
+ }
+
+ WorkflowInstance* create(mmi_standard_workflow_type_e type) {
+ WorkflowInstance *newInstance = new(std::nothrow) WorkflowInstance(m_last_local_workflow_instance_id++, type);
+ m_instances.push_back(newInstance);
+ return newInstance;
+ }
+
+ bool destroy(WorkflowInstance *instance) {
+ bool ret = false;
+ auto it = std::find(m_instances.begin(), m_instances.end(), instance);
+ if (it != m_instances.end()) {
+ m_instances.erase(it);
+ instance->deinitialize();
+ delete instance;
+ ret = true;
+ }
+ return ret;
+ }
+
+private:
+ int m_last_local_workflow_instance_id{0};
+ std::vector<WorkflowInstance*> m_instances;
+};
+
+} // namespace mmi
+//
+#endif //__MMI_WORKFLOW_INSTANCE_MANAGER_H__
--- /dev/null
+/*
+ * 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 <algorithm>
+#include <vector>
+#include <map>
+#include <string>
+
+#include <Ecore.h>
+
+#include "mmi.h"
+#include "mmi-plugin-storage.h"
+
+#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;
+
+extern ClientManager g_mmi_client_manager;
+
+MMI_API int mmi_standard_workflow_instance_create(mmi_standard_workflow_type_e type, mmi_workflow_instance_h *instance) {
+ if (nullptr == instance) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ WorkflowInstanceManager *workflow_instance_manager = g_mmi_client_manager.get_workflow_instance_manager();
+ if (nullptr == workflow_instance_manager) {
+ LOGE("[ERROR] Failed to get workflow instance manager");
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ WorkflowInstance *workflow_instance = workflow_instance_manager->create(type);
+ if (workflow_instance) {
+ *instance = static_cast<void*>(workflow_instance);
+
+ CommunicationChannel *channel = g_mmi_client_manager.get_communication_channel();
+ if (channel) {
+ ClientMessageWorkflowInstanceCreate msg;
+ msg.local_workflow_instance_id =
+ workflow_instance->get_local_workflow_instance_id();
+ msg.workflow_type = type;
+ msg.user_data = workflow_instance;
+
+ channel->send(&msg);
+ }
+ } else {
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_workflow_instance_destroy(mmi_workflow_instance_h instance) {
+ if (nullptr == instance) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ WorkflowInstanceManager *workflow_instance_manager = g_mmi_client_manager.get_workflow_instance_manager();
+ if (nullptr == workflow_instance_manager) {
+ LOGE("[ERROR] Failed to get workflow instance manager");
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ CommunicationChannel *channel = g_mmi_client_manager.get_communication_channel();
+ if (channel) {
+ ClientMessageWorkflowInstanceDestroy msg;
+ WorkflowInstance *workflow_instance = static_cast<WorkflowInstance*>(instance);
+ msg.local_workflow_instance_id = workflow_instance->get_local_workflow_instance_id();
+
+ channel->send(&msg);
+
+ workflow_instance_manager->destroy(workflow_instance);
+ }
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_workflow_instance_activate(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();
+ if (nullptr == channel) {
+ LOGE("[ERROR] Failed to get channel");
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ WorkflowInstance *workflow_instance = static_cast<WorkflowInstance*>(instance);
+
+ ClientMessageWorkflowInstanceActivate msg;
+ msg.local_workflow_instance_id = workflow_instance->get_local_workflow_instance_id();
+
+ channel->send(&msg);
+
+ return MMI_ERROR_NONE;
+}
+
+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();
+ if (nullptr == channel) {
+ LOGE("[ERROR] Failed to get channel");
+ return MMI_ERROR_OPERATION_FAILED;
+ }
+
+ WorkflowInstance *workflow_instance = static_cast<WorkflowInstance*>(instance);
+
+ ClientMessageWorkflowInstanceDeactivate msg;
+ msg.local_workflow_instance_id = workflow_instance->get_local_workflow_instance_id();
+
+ channel->send(&msg);
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_workflow_instance_set_attribute(mmi_workflow_instance_h instance, mmi_attribute_h attribute) {
+ if (nullptr == instance) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ CommunicationChannel *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<WorkflowInstance*>(instance);
+
+ ClientMessageWorkflowInstanceSetAttribute msg;
+ msg.local_workflow_instance_id = workflow_instance->get_local_workflow_instance_id();
+ msg.attribute = attribute;
+
+ channel->send(&msg);
+
+ return MMI_ERROR_NONE;
+}
+
+
+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");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (nullptr == name) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ if (nullptr == callback) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ WorkflowInstance *workflow_instance = static_cast<WorkflowInstance*>(instance);
+ workflow_instance->add_output_callback(std::string{name}, callback, user_data);
+
+ return MMI_ERROR_NONE;
+}
--- /dev/null
+/*
+ * 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_WORKFLOW_SCRIPT_PARSER_H__
+#define __MMI_WORKFLOW_SCRIPT_PARSER_H__
+
+#include <string>
+#include <regex>
+#include <vector>
+
+#include "mmi-log.h"
+#include "mmi-node-source.h"
+#include "mmi-node-processor.h"
+#include "mmi-node-logic.h"
+#include "mmi-node-controller.h"
+
+enum class WorkflowScriptSection {
+ NONE,
+ WORKFLOW_INFO,
+ NODE_LIST,
+ LINK_LIST,
+ ATTRIBUTE_LIST,
+ OUTPUT_LIST,
+};
+
+typedef struct {
+ WorkflowScriptSection section;
+ std::regex pattern;
+} WorkflowScriptSectionPattern;
+
+typedef struct {
+ WorkflowScriptSection section;
+ std::string name;
+} WorkflowScriptSectionName;
+
+typedef struct {
+ mmi_standard_workflow_type_e type;
+ std::string name;
+} StandardWorkflowName;
+
+typedef struct {
+ mmi_standard_node_source_type_e type;
+ std::string name;
+} StandardNodeSourceName;
+
+typedef struct {
+ mmi_standard_node_processor_type_e type;
+ std::string name;
+} StandardNodeProcessorName;
+
+typedef struct {
+ mmi_standard_node_logic_type_e type;
+ std::string name;
+} StandardNodeLogicName;
+
+typedef struct {
+ mmi_standard_node_controller_type_e type;
+ std::string name;
+} StandardNodeControllerName;
+
+// trim from start (in place)
+static inline void ltrim(std::string &s) {
+ s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
+ return !std::isspace(ch);
+ }));
+}
+
+// trim from end (in place)
+static inline void rtrim(std::string &s) {
+ s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
+ return !std::isspace(ch);
+ }).base(), s.end());
+}
+
+// trim from both ends (in place)
+static inline void trim(std::string &s) {
+ rtrim(s);
+ ltrim(s);
+}
+
+class WorkflowScriptParser {
+public:
+ WorkflowScriptParser() {
+ m_section_names.push_back({WorkflowScriptSection::WORKFLOW_INFO, "@workflow"});
+ m_section_names.push_back({WorkflowScriptSection::NODE_LIST, "@node-list"});
+ m_section_names.push_back({WorkflowScriptSection::LINK_LIST, "@link-list"});
+ m_section_names.push_back({WorkflowScriptSection::ATTRIBUTE_LIST, "@attribute-list"});
+ m_section_names.push_back({WorkflowScriptSection::OUTPUT_LIST, "@output-list"});
+
+ m_section_patterns.push_back({WorkflowScriptSection::WORKFLOW_INFO, std::regex("^name : ([a-zA-Z_]+)$")});
+ m_section_patterns.push_back({WorkflowScriptSection::NODE_LIST, std::regex("^\\[([a-zA-Z]+)\\] ([a-zA-Z_]+) as ([a-zA-Z0-9_]+)$")});
+ m_section_patterns.push_back({WorkflowScriptSection::LINK_LIST, std::regex("^([a-zA-Z0-9_.]+) -> ([a-zA-Z0-9_.]+)$")});
+ m_section_patterns.push_back({WorkflowScriptSection::ATTRIBUTE_LIST, std::regex("^([a-zA-Z0-9_.]+) as ([a-zA-Z0-9_]+)$")});
+ m_section_patterns.push_back({WorkflowScriptSection::OUTPUT_LIST, std::regex("^([a-zA-Z0-9_.]+) as ([a-zA-Z0-9_]+)$")});
+
+ m_standard_workflow_names.push_back({MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND, "WAKEUPLESS_COMMAND"});
+ m_standard_workflow_names.push_back({MMI_STANDARD_WORKFLOW_VOICE_TOUCH, "VOICE_TOUCH"});
+ m_standard_workflow_names.push_back({MMI_STANDARD_WORKFLOW_USER_RECOGNITION, "USER_RECOGNITION"});
+
+ m_standard_node_source_names.push_back({MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT, "MIC_AMBIENT"});
+ 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_FACE_RECOGNITION, "FACE_RECOGNITION"});
+ m_standard_node_processor_names.push_back({MMI_STANDARD_NODE_PROCESSOR_TYPE_SPEAKER_RECOGNITION, "SPEAKER_RECOGNITION"});
+
+ m_standard_node_logic_names.push_back({MMI_STANDARD_NODE_LOGIC_TYPE_FIXED_STRING_MATCH, "FIXED_STRING_MATCH"});
+ m_standard_node_logic_names.push_back({MMI_STANDARD_NODE_LOGIC_TYPE_USER_COMPARISON, "USER_COMPARISON"});
+
+ m_standard_node_controller_names.push_back({MMI_STANDARD_NODE_CONTROLLER_TYPE_SWITCH, "SWITCH"});
+ }
+ virtual ~WorkflowScriptParser() {
+ }
+
+ bool process_section_declaration(const std::string &line) {
+ for (auto §ion_name : m_section_names) {
+ if (line == section_name.name) {
+ m_current_section = section_name.section;
+ LOGD("section changed to %d, [%s]", static_cast<int>(m_current_section), line.c_str());
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool process_workflow_info(std::smatch matches, mmi_workflow_h workflow) {
+ if (matches.size() == 2) {
+ std::ssub_match sub_match = matches[1];
+ std::string name = sub_match.str();
+ for (auto &standard_workflow_name : m_standard_workflow_names) {
+ if (name == standard_workflow_name.name) {
+ LOGD("standard workflow name matched: %s", name.c_str());
+ mmi_standard_workflow_type_e type = standard_workflow_name.type;
+ if (mmi_workflow_set_type(workflow, type) != MMI_ERROR_NONE) {
+ LOGE("[ERROR] Failed to set standard workflow type");
+ return false;
+ }
+ break;
+ }
+ }
+ }
+ return true;
+ }
+
+ bool process_node_section(std::smatch matches, mmi_workflow_h workflow) {
+ if (matches.size() == 4) {
+ std::ssub_match sub_match_type = matches[1];
+ std::string type = sub_match_type.str();
+
+ if (type.compare("Source") == 0) {
+ std::ssub_match sub_match_name = matches[2];
+ std::string name = sub_match_name.str();
+
+ std::ssub_match sub_match_alias = matches[3];
+ std::string alias = sub_match_alias.str();
+
+ for (auto &standard_node_source_name : m_standard_node_source_names) {
+ if (name == standard_node_source_name.name) {
+ LOGD("standard node source name matched: %s", name.c_str());
+ mmi_standard_node_source_type_e sub_type = standard_node_source_name.type;
+ mmi_node_h node = nullptr;
+ if (mmi_standard_node_create_source(sub_type, &node) != MMI_ERROR_NONE) {
+ LOGE("[ERROR] Failed to create standard node source");
+ return false;
+ }
+ LOGD("standard node source created: %p", node);
+ mmi_workflow_node_add(workflow, alias.c_str(), node);
+ break;
+ }
+ }
+ } else if (type.compare("Processor") == 0) {
+ std::ssub_match sub_match_name = matches[2];
+ std::string name = sub_match_name.str();
+
+ std::ssub_match sub_match_alias = matches[3];
+ std::string alias = sub_match_alias.str();
+
+ for (auto &standard_node_processor_name : m_standard_node_processor_names) {
+ if (name == standard_node_processor_name.name) {
+ LOGD("standard node processor name matched: %s", name.c_str());
+ mmi_standard_node_processor_type_e sub_type = standard_node_processor_name.type;
+ mmi_node_h node = nullptr;
+ if (mmi_standard_node_create_processor(sub_type, &node) != MMI_ERROR_NONE) {
+ LOGE("[ERROR] Failed to create standard node processor");
+ return false;
+ }
+ LOGD("Adding processor node %s as %s", name.c_str(), alias.c_str());
+ mmi_workflow_node_add(workflow, alias.c_str(), node);
+ mmi_node_destroy(node);
+ break;
+ }
+ }
+ } else if (type.compare("Logic") == 0) {
+ std::ssub_match sub_match_name = matches[2];
+ std::string name = sub_match_name.str();
+
+ std::ssub_match sub_match_alias = matches[3];
+ std::string alias = sub_match_alias.str();
+
+ for (auto &standard_node_logic_name : m_standard_node_logic_names) {
+ if (name == standard_node_logic_name.name) {
+ LOGD("standard node logic name matched: %s", name.c_str());
+ mmi_standard_node_logic_type_e sub_type = standard_node_logic_name.type;
+ mmi_node_h node = nullptr;
+ if (mmi_standard_node_create_logic(sub_type, &node) != MMI_ERROR_NONE) {
+ LOGE("[ERROR] Failed to create standard node logic");
+ return false;
+ }
+ LOGD("Adding logic node %s as %s", name.c_str(), alias.c_str());
+ mmi_workflow_node_add(workflow, alias.c_str(), node);
+ mmi_node_destroy(node);
+ break;
+ }
+ }
+ } else if (type.compare("Controller") == 0) {
+ std::ssub_match sub_match_name = matches[2];
+ std::string name = sub_match_name.str();
+
+ std::ssub_match sub_match_alias = matches[3];
+ std::string alias = sub_match_alias.str();
+
+ for (auto &standard_node_controller_name : m_standard_node_controller_names) {
+ if (name == standard_node_controller_name.name) {
+ LOGD("standard node controller name matched: %s", name.c_str());
+ mmi_standard_node_controller_type_e sub_type = standard_node_controller_name.type;
+ mmi_node_h node = nullptr;
+ if (mmi_standard_node_create_controller(sub_type, &node) != MMI_ERROR_NONE) {
+ LOGE("[ERROR] Failed to create standard node controller");
+ return false;
+ }
+ LOGD("Adding controller node %s as %s", name.c_str(), alias.c_str());
+ mmi_workflow_node_add(workflow, alias.c_str(), node);
+ mmi_node_destroy(node);
+ break;
+ }
+ }
+ }
+ }
+ return true;
+ }
+
+ bool process_link_section(std::smatch matches, mmi_workflow_h workflow) {
+ if (matches.size() == 3) {
+ std::ssub_match sub_match_from = matches[1];
+ std::string from = sub_match_from.str();
+
+ std::ssub_match sub_match_to = matches[2];
+ std::string to = sub_match_to.str();
+
+ std::string from_node_name;
+ std::string from_port_name;
+
+ std::string to_node_name;
+ std::string to_port_name;
+
+ size_t from_pos = from.find(".");
+ if (from_pos != std::string::npos) {
+ from_node_name = from.substr(0, from_pos);
+ from_port_name = from.substr(from_pos + 1);
+ } else {
+ LOGE("[ERROR] Invalid 'from' format: %s", from.c_str());
+ return false;
+ }
+
+ size_t to_pos = to.find(".");
+ if (to_pos != std::string::npos) {
+ to_node_name = to.substr(0, to_pos);
+ to_port_name = to.substr(to_pos + 1);
+ } else {
+ LOGE("[ERROR] Invalid 'to' format: %s", to.c_str());
+ return false;
+ }
+
+ LOGD("from_node_name: %s, from_port_name: %s, to_node_name: %s, to_port_name: %s",
+ from_node_name.c_str(), from_port_name.c_str(), to_node_name.c_str(), to_port_name.c_str());
+
+ if (mmi_workflow_link_nodes_by_names(workflow,
+ from_node_name.c_str(), from_port_name.c_str(),
+ to_node_name.c_str(), to_port_name.c_str()) != MMI_ERROR_NONE) {
+ LOGE("[ERROR] Failed to link nodes by names");
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool process_attribute_section(std::smatch matches, mmi_workflow_h workflow) {
+ if (matches.size() == 3) {
+ std::ssub_match sub_match_name = matches[1];
+ std::string identifier = sub_match_name.str();
+
+ std::ssub_match sub_match_value = matches[2];
+ std::string alias = sub_match_value.str();
+
+ LOGD("identifier: %s, alias: %s", identifier.c_str(), alias.c_str());
+
+ size_t pos = identifier.find(".");
+ if (pos != std::string::npos) {
+ std::string node_name = identifier.substr(0, pos);
+ std::string attribute_name = identifier.substr(pos + 1);
+
+ LOGD("node_name: %s, attribute_name: %s", node_name.c_str(), attribute_name.c_str());
+
+ mmi_workflow_attribute_assign(workflow, alias.c_str(), node_name.c_str(), attribute_name.c_str());
+ }
+ }
+ return true;
+ }
+
+ bool process_output_section(std::smatch matches, mmi_workflow_h workflow) {
+ if (matches.size() == 3) {
+ std::ssub_match sub_match_name = matches[1];
+ std::string identifier = sub_match_name.str();
+
+ std::ssub_match sub_match_value = matches[2];
+ std::string alias = sub_match_value.str();
+
+ LOGD("identifier: %s, alias: %s", identifier.c_str(), alias.c_str());
+
+ size_t pos = identifier.find(".");
+ if (pos != std::string::npos) {
+ std::string node_name = identifier.substr(0, pos);
+ std::string port_name = identifier.substr(pos + 1);
+
+ LOGD("node_name: %s, port_name: %s", node_name.c_str(), port_name.c_str());
+
+ mmi_workflow_output_assign(workflow, alias.c_str(), node_name.c_str(), port_name.c_str());
+ }
+ }
+ return true;
+ }
+
+ bool process_section_line(const std::string &line, mmi_workflow_h workflow) {
+ for (auto §ion_pattern : m_section_patterns) {
+ if (m_current_section == section_pattern.section) {
+ if (std::regex_match(line, section_pattern.pattern)) {
+ LOGD("section line matched: %s", line.c_str());
+ std::smatch matches;
+ if (std::regex_search(line, matches, section_pattern.pattern)) {
+ switch (m_current_section) {
+ case WorkflowScriptSection::WORKFLOW_INFO:
+ if (process_workflow_info(matches, workflow) == false) {
+ LOGE("[ERROR] Failed to process workflow info");
+ return false;
+ }
+ break;
+ case WorkflowScriptSection::NODE_LIST:
+ if (process_node_section(matches, workflow) == false) {
+ LOGE("[ERROR] Failed to process node section");
+ return false;
+ }
+ break;
+ case WorkflowScriptSection::LINK_LIST:
+ if (process_link_section(matches, workflow) == false) {
+ LOGE("[ERROR] Failed to process link section");
+ return false;
+ }
+ break;
+ case WorkflowScriptSection::ATTRIBUTE_LIST:
+ if (process_attribute_section(matches, workflow) == false) {
+ LOGE("[ERROR] Failed to process attribute section");
+ return false;
+ }
+ break;
+ case WorkflowScriptSection::OUTPUT_LIST:
+ if (process_output_section(matches, workflow) == false) {
+ LOGE("[ERROR] Failed to process output section");
+ return false;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ bool parse(std::vector<std::string> &lines, mmi_workflow_h *workflow) {
+ if (nullptr == workflow) {
+ LOGE("[ERROR] parameter is null");
+ return false;
+ }
+ create_workflow(workflow);
+ if (nullptr == *workflow) {
+ LOGE("[ERROR] Failed to create workflow");
+ return false;
+ }
+
+ for (auto &line : lines) {
+ trim(line);
+
+ if (line.empty()) {
+ continue;
+ }
+
+ if (std::regex_match(line, m_section_declaration_regex)) {
+ if (process_section_declaration(line) == false) {
+ LOGE("invalid section name: %s", line.c_str());
+ return false;
+ }
+ } else {
+ if (process_section_line(line, *workflow) == false) {
+ LOGE("invalid section line: %s", line.c_str());
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+private:
+ void create_workflow(mmi_workflow_h *workflow) {
+ if (nullptr == workflow) {
+ LOGE("[ERROR] parameter is null");
+ return;
+ }
+
+ mmi_workflow_s *workflow_s = new(std::nothrow) mmi_workflow_s;
+ if (nullptr == workflow_s) {
+ LOGE("[ERROR] Failed to create workflow");
+ return;
+ }
+
+ workflow_s->type = MMI_STANDARD_WORKFLOW_NONE;
+ workflow_s->node_infos = nullptr;
+ workflow_s->node_info_count = 0;
+ workflow_s->link_infos = nullptr;
+ workflow_s->link_info_count = 0;
+ workflow_s->attribute_assignment_infos = nullptr;
+ workflow_s->attribute_assignment_info_count = 0;
+ workflow_s->attribute_default_value_infos = nullptr;
+ workflow_s->attribute_default_value_info_count = 0;
+ workflow_s->output_assignment_infos = nullptr;
+ workflow_s->output_assignment_info_count = 0;
+
+ *workflow = static_cast<mmi_workflow_h>(workflow_s);
+ }
+ void destroy_workflow(mmi_workflow_h workflow) {
+ if (nullptr == workflow) {
+ LOGE("[ERROR] parameter is null");
+ return;
+ }
+
+ mmi_workflow_s *workflow_s = static_cast<mmi_workflow_s*>(workflow);
+ delete workflow_s;
+ }
+
+ WorkflowScriptSection m_current_section{WorkflowScriptSection::NONE};
+
+ std::regex m_section_declaration_regex{"^@[a-zA-Z0-9_-]+$"};
+
+ std::vector<WorkflowScriptSectionName> m_section_names;
+ std::vector<WorkflowScriptSectionPattern> m_section_patterns;
+
+ std::vector<StandardWorkflowName> m_standard_workflow_names;
+
+ std::vector<StandardNodeSourceName> m_standard_node_source_names;
+ std::vector<StandardNodeProcessorName> m_standard_node_processor_names;
+ std::vector<StandardNodeLogicName> m_standard_node_logic_names;
+ std::vector<StandardNodeControllerName> m_standard_node_controller_names;
+
+};
+
+#endif /* __MMI_WORKFLOW_SCRIPT_PARSER_H__ */
--- /dev/null
+/*
+ * 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-log.h"
+#include "mmi-workflow.h"
+
+#include "mmi-workflow-script-parser.h"
+
+#include <fstream>
+
+MMI_API int mmi_workflow_create_from_script(const char *script_path, mmi_workflow_h *workflow) {
+ if (script_path == nullptr || workflow == nullptr) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ std::ifstream script_file(script_path);
+ if (!script_file.is_open()) {
+ LOGE("[ERROR] Failed to open script file");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ std::string line;
+ std::vector<std::string> lines;
+ while (std::getline(script_file, line)) {
+ lines.push_back(line);
+ }
+
+ WorkflowScriptParser parser;
+ *workflow = nullptr;
+ bool result = parser.parse(lines, workflow);
+ if (!result || *workflow == nullptr) {
+ LOGE("[ERROR] Failed to create workflow from data");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ return MMI_ERROR_NONE;
+}
+
--- /dev/null
+/*
+ * 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 <algorithm>
+#include <vector>
+#include <map>
+#include <string>
+
+#include <Ecore.h>
+
+#include "mmi.h"
+#include "mmi-plugin-storage.h"
+
+#include "mmi-log.h"
+
+MMI_API int mmi_workflow_create(mmi_workflow_h *workflow) {
+ if (nullptr == workflow) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_workflow_s *workflow_s = new(std::nothrow) mmi_workflow_s;
+ if (nullptr == workflow_s) {
+ LOGE("[ERROR] Failed to create workflow");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ workflow_s->type = MMI_STANDARD_WORKFLOW_NONE;
+ workflow_s->node_infos = nullptr;
+ workflow_s->node_info_count = 0;
+ workflow_s->link_infos = nullptr;
+ workflow_s->link_info_count = 0;
+ workflow_s->attribute_assignment_infos = nullptr;
+ workflow_s->attribute_assignment_info_count = 0;
+ workflow_s->attribute_default_value_infos = nullptr;
+ workflow_s->attribute_default_value_info_count = 0;
+ workflow_s->output_assignment_infos = nullptr;
+ workflow_s->output_assignment_info_count = 0;
+
+ *workflow = static_cast<mmi_workflow_h>(workflow_s);
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_workflow_set_type(mmi_workflow_h workflow, mmi_standard_workflow_type_e type) {
+ if (nullptr == workflow) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_workflow_s *workflow_s = static_cast<mmi_workflow_s *>(workflow);
+ workflow_s->type = type;
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_workflow_get_type(mmi_workflow_h workflow, mmi_standard_workflow_type_e *type) {
+ if (nullptr == workflow || nullptr == type) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_workflow_s *workflow_s = static_cast<mmi_workflow_s *>(workflow);
+ *type = workflow_s->type;
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_workflow_node_add(mmi_workflow_h workflow, const char *node_name, mmi_node_h node) {
+ if (nullptr == workflow || nullptr == node_name || nullptr == node) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_workflow_s *workflow_s = static_cast<mmi_workflow_s *>(workflow);
+ mmi_workflow_node_info_s *node_infos = workflow_s->node_infos;
+ size_t node_info_count = workflow_s->node_info_count;
+ workflow_s->node_infos = new(std::nothrow) mmi_workflow_node_info_s[node_info_count + 1];
+ if (node_info_count > 0) {
+ memcpy(workflow_s->node_infos, node_infos, sizeof(mmi_workflow_node_info_s) * node_info_count);
+ delete [] node_infos;
+ }
+
+ snprintf(workflow_s->node_infos[node_info_count].name, MMI_NAME_MAX_LENGTH, "%s", node_name);
+ mmi_node_clone(node, &(workflow_s->node_infos[node_info_count].node));
+ workflow_s->node_info_count++;
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_workflow_link_nodes_by_names(mmi_workflow_h workflow,
+ const char *from_node_name, const char *from_port_name, const char *to_node_name, const char *to_port_name) {
+ if (nullptr == from_node_name || nullptr == from_port_name || nullptr == to_node_name || nullptr == to_port_name) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_workflow_s *workflow_s = static_cast<mmi_workflow_s *>(workflow);
+ mmi_workflow_link_info_s *link_infos = workflow_s->link_infos;
+ size_t link_info_count = workflow_s->link_info_count;
+ workflow_s->link_infos = new(std::nothrow) mmi_workflow_link_info_s[link_info_count + 1];
+ if (link_info_count > 0) {
+ memcpy(workflow_s->link_infos, link_infos, sizeof(mmi_workflow_link_info_s) * link_info_count);
+ delete [] link_infos;
+ }
+
+ snprintf(workflow_s->link_infos[link_info_count].from_node_name, MMI_NAME_MAX_LENGTH, "%s", from_node_name);
+ snprintf(workflow_s->link_infos[link_info_count].from_port_name, MMI_NAME_MAX_LENGTH, "%s", from_port_name);
+ snprintf(workflow_s->link_infos[link_info_count].to_node_name, MMI_NAME_MAX_LENGTH, "%s", to_node_name);
+ snprintf(workflow_s->link_infos[link_info_count].to_port_name, MMI_NAME_MAX_LENGTH, "%s", to_port_name);
+
+ workflow_s->link_info_count = link_info_count + 1;
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_workflow_attribute_assign(mmi_workflow_h workflow, const char *attribute_name, const char *target_node_name, const char *target_attribute_name) {
+ if (nullptr == workflow || nullptr == attribute_name || nullptr == target_node_name || nullptr == target_attribute_name) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_workflow_s *workflow_s = static_cast<mmi_workflow_s *>(workflow);
+ 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 (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;
+ }
+
+ snprintf(workflow_s->attribute_assignment_infos[attribute_assignment_info_count].attribute_name, MMI_NAME_MAX_LENGTH, "%s", attribute_name);
+ snprintf(workflow_s->attribute_assignment_infos[attribute_assignment_info_count].target_node_name, MMI_NAME_MAX_LENGTH, "%s", target_node_name);
+ snprintf(workflow_s->attribute_assignment_infos[attribute_assignment_info_count].target_attribute_name, MMI_NAME_MAX_LENGTH, "%s", target_attribute_name);
+
+ workflow_s->attribute_assignment_info_count = attribute_assignment_info_count + 1;
+
+ return MMI_ERROR_NONE;
+}
+
+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");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_workflow_s *workflow_s = static_cast<mmi_workflow_s *>(workflow);
+ 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 (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;
+ }
+
+ mmi_attribute_to_bytes(default_value,
+ &(workflow_s->attribute_default_value_infos[attribute_default_value_info_count].serialized_default_value),
+ &(workflow_s->attribute_default_value_infos[attribute_default_value_info_count].serialized_default_value_size));
+
+ workflow_s->attribute_default_value_info_count = attribute_default_value_info_count + 1;
+
+ 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) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ return MMI_ERROR_NONE;
+}
+
+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) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_workflow_s *workflow_s = static_cast<mmi_workflow_s *>(workflow);
+ mmi_workflow_output_assignment_info_s *output_assignment_infos = workflow_s->output_assignment_infos;
+ size_t output_assignment_info_count = workflow_s->output_assignment_info_count;
+ workflow_s->output_assignment_infos = new(std::nothrow) mmi_workflow_output_assignment_info_s[output_assignment_info_count + 1];
+ if (output_assignment_info_count > 0) {
+ memcpy(workflow_s->output_assignment_infos, output_assignment_infos, sizeof(mmi_workflow_output_assignment_info_s) * output_assignment_info_count);
+ delete [] output_assignment_infos;
+ }
+
+ snprintf(workflow_s->output_assignment_infos[output_assignment_info_count].output_name,MMI_NAME_MAX_LENGTH, "%s", workflow_output);
+ snprintf(workflow_s->output_assignment_infos[output_assignment_info_count].from_node_name, MMI_NAME_MAX_LENGTH, "%s", out_node_name);
+ snprintf(workflow_s->output_assignment_infos[output_assignment_info_count].from_port_name, MMI_NAME_MAX_LENGTH, "%s", node_out_port_name);
+
+ workflow_s->output_assignment_info_count = output_assignment_info_count + 1;
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_workflow_output_assign_by_port(mmi_workflow_h workflow, const char *workflow_output, mmi_port_h port) {
+ if (nullptr == workflow || nullptr == workflow_output || nullptr == port) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_standard_workflow_register(mmi_workflow_h workflow) {
+ if (nullptr == workflow) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_standard_workflow_type_e workflow_type;
+ mmi_workflow_get_type(workflow, &workflow_type);
+
+ const char *identifier = mmi_plugin_storage_get_current_module_identifier();
+ if (nullptr == identifier) {
+ LOGE("[ERROR] identifier is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_plugin_module_workflow_list_s list = mmi_plugin_storage_get_workflow_list(identifier);
+
+ mmi_workflow_h *workflows = list.workflows;
+ size_t workflow_count = list.workflow_count;
+
+ bool duplicated = false;
+
+ for (size_t i = 0; i < workflow_count; i++) {
+ mmi_standard_workflow_type_e type;
+ mmi_workflow_get_type(workflows[i], &type);
+ if (type == workflow_type) {
+ duplicated = true;
+ mmi_workflow_destroy(workflows[i]);
+
+ mmi_workflow_h cloned;
+ mmi_workflow_clone(workflow, &cloned);
+ workflows[i] = cloned;
+ }
+ }
+
+ if (!duplicated) {
+ list.workflows = new(std::nothrow) mmi_workflow_h[workflow_count + 1];
+ if (nullptr == list.workflows) {
+ LOGE("[ERROR] failed to allocate memory");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+ if (workflow_count > 0) {
+ memcpy(list.workflows, workflows, sizeof(mmi_workflow_h) * workflow_count);
+ delete [] workflows;
+ }
+
+ mmi_workflow_h cloned;
+ mmi_workflow_clone(workflow, &cloned);
+ list.workflows[workflow_count] = cloned;
+ list.workflow_count = workflow_count + 1;
+ }
+
+ mmi_plugin_storage_set_workflow_list(list);
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_workflow_clone(mmi_workflow_h workflow, mmi_workflow_h *cloned) {
+ if (nullptr == workflow || nullptr == cloned) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_workflow_s *cloned_s = new(std::nothrow) mmi_workflow_s;
+ if (nullptr == cloned_s) {
+ LOGE("[ERROR] new mmi_workflow_s failed");
+ return MMI_ERROR_OUT_OF_MEMORY;
+ }
+
+ mmi_workflow_s *workflow_s = static_cast<mmi_workflow_s *>(workflow);
+ memcpy(cloned_s, workflow_s, sizeof(mmi_workflow_s));
+
+ cloned_s->node_infos = new(std::nothrow) mmi_workflow_node_info_s[workflow_s->node_info_count];
+ memcpy(cloned_s->node_infos, workflow_s->node_infos, sizeof(mmi_workflow_node_info_s) * workflow_s->node_info_count);
+ for (int i = 0; i < workflow_s->node_info_count; i++) {
+ mmi_node_clone(workflow_s->node_infos[i].node, &(cloned_s->node_infos[i].node));
+ }
+
+ if (workflow_s->link_info_count > 0) {
+ cloned_s->link_infos = new(std::nothrow) mmi_workflow_link_info_s[workflow_s->link_info_count];
+ memcpy(cloned_s->link_infos, workflow_s->link_infos, sizeof(mmi_workflow_link_info_s) * workflow_s->link_info_count);
+ }
+
+ if (workflow_s->attribute_assignment_info_count > 0) {
+ cloned_s->attribute_assignment_infos = new(std::nothrow) mmi_workflow_attribute_assignment_info_s[workflow_s->attribute_assignment_info_count];
+ memcpy(cloned_s->attribute_assignment_infos, workflow_s->attribute_assignment_infos,
+ sizeof(mmi_workflow_attribute_assignment_info_s) * workflow_s->attribute_assignment_info_count);
+ }
+
+ if (workflow_s->attribute_default_value_info_count > 0) {
+ cloned_s->attribute_default_value_infos = new(std::nothrow) mmi_workflow_attribute_default_value_info_s[workflow_s->attribute_default_value_info_count];
+ for (int i = 0; i < workflow_s->attribute_default_value_info_count; i++) {
+ cloned_s->attribute_default_value_infos[i].serialized_default_value =
+ new(std::nothrow) unsigned char[workflow_s->attribute_default_value_infos[i].serialized_default_value_size];
+ memcpy(cloned_s->attribute_default_value_infos[i].serialized_default_value,
+ workflow_s->attribute_default_value_infos[i].serialized_default_value,
+ workflow_s->attribute_default_value_infos[i].serialized_default_value_size);
+ }
+ }
+
+ if (workflow_s->output_assignment_info_count > 0) {
+ cloned_s->output_assignment_infos = new(std::nothrow) mmi_workflow_output_assignment_info_s[workflow_s->output_assignment_info_count];
+ memcpy(cloned_s->output_assignment_infos, workflow_s->output_assignment_infos,
+ sizeof(mmi_workflow_output_assignment_info_s) * workflow_s->output_assignment_info_count);
+ }
+
+ *cloned = cloned_s;
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_workflow_destroy(mmi_workflow_h workflow) {
+ if (nullptr == workflow) {
+ LOGE("[ERROR] parameter is null");
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ mmi_workflow_s *workflow_s = static_cast<mmi_workflow_s*>(workflow);
+
+ for (int i = 0; i < workflow_s->node_info_count; i++) {
+ mmi_node_destroy(workflow_s->node_infos[i].node);
+ }
+ delete [] workflow_s->node_infos;
+ delete [] workflow_s->link_infos;
+ delete [] workflow_s->attribute_assignment_infos;
+ delete [] workflow_s->attribute_default_value_infos;
+ delete [] workflow_s->output_assignment_infos;
+
+ delete workflow_s;
+
+ return MMI_ERROR_NONE;
+}
--- /dev/null
+/*
+ * 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 <algorithm>
+#include <vector>
+#include <map>
+#include <string>
+
+#include <Ecore.h>
+
+#include "mmi-log.h"
+#include "mmi-ipc-tidl.h"
+
+#include "mmi-client-manager.h"
+
+#include "mmi.h"
+
+using namespace mmi;
+using namespace mmi::communication;
+
+static mmi_state_e g_mmi_state{MMI_STATE_NONE};
+static std::vector<std::pair<mmi_state_changed_cb, void*>> 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;
+
+class CommunicationChannelObserver :
+ public SimpleEventObserver<COMMUNICATION_CHANNEL_EVENT_TYPE> {
+public:
+ void on_observer_event(
+ const COMMUNICATION_CHANNEL_EVENT_TYPE &event, std::any data) override {
+ mmi_state_e previous_state = g_mmi_state;
+
+ if (event == COMMUNICATION_CHANNEL_EVENT_TYPE::CONNECTED) {
+ g_mmi_state = MMI_STATE_READY;
+ } else if (event == COMMUNICATION_CHANNEL_EVENT_TYPE::DISCONNECTED) {
+ g_mmi_state = MMI_STATE_NONE;
+ }
+
+ if (previous_state != g_mmi_state) {
+ for (auto& item : g_state_changed_cb_list) {
+ item.first(g_mmi_state, item.second);
+ }
+ }
+ }
+};
+static CommunicationChannelObserver g_communication_channel_observer;
+
+ClientManager g_mmi_client_manager{
+ &g_communication_channel_factory_tidl,
+ &g_communication_channel_observer
+};
+
+MMI_API int mmi_initialize() {
+ LOGE("[SUCCESS] Succeeded to create client");
+ g_mmi_client_manager.initialize();
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_deinitialize() {
+ g_mmi_client_manager.deinitialize();
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_set_state_changed_cb(mmi_state_changed_cb callback, void *user_data) {
+ if (callback == nullptr) {
+ return MMI_ERROR_INVALID_PARAMETER;
+ }
+
+ callback(g_mmi_state, user_data);
+
+ g_state_changed_cb_list.push_back(std::make_pair(callback, user_data));
+
+ return MMI_ERROR_NONE;
+}
+
+MMI_API int mmi_unset_state_changed_cb(mmi_state_changed_cb callback) {
+ auto it = std::find_if(g_state_changed_cb_list.begin(), g_state_changed_cb_list.end(),
+ [callback](const std::pair<mmi_state_changed_cb, void*>& item) {
+ return item.first == callback;
+ });
+
+ if (it != g_state_changed_cb_list.end()) {
+ g_state_changed_cb_list.erase(it);
+ }
+
+ return MMI_ERROR_NONE;
+}
-mmi_tests_srcs = [
- 'mmi-tests.cpp',
- 'mmi-main-test.cpp',
- 'mmi-ipc-test.cpp',
- 'wait-helper.cpp'
- ]
-
-gmock_dep = dependency('gmock', method : 'pkg-config')
-ecore_dep = dependency('ecore', method : 'pkg-config')
-
-executable(
- 'mmi-tests',
- mmi_tests_srcs,
- dependencies : [mmi_declared_dep, gmock_dep, ecore_dep],
- install_dir : mmi_prefix_bindir,
- install : true
- )
+subdir('mmi')
+subdir('mmi-manager')
+++ /dev/null
-/*
- * 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 "mmi.h"
-#include "mmi-tests.h"
-#include "mmi-ipc.h"
-#include "mmi-client.h"
-
-#include <Ecore.h>
-#include <rpc-port-internal.h>
-
-class MMIIpcTest : public ::testing::Test
-{
-public:
- void SetUp(void) override
- {
- ecore_init();
- }
-
- void TearDown(void) override
- {
- ecore_shutdown();
- }
-};
-
-TEST_F(MMIIpcTest, MMIFWIpcInitSuccess)
-{
- int res = mmi_initialize();
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIIpcTest, MMIIpcInitFail)
-{
- int res = mmi_initialize();
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_deinitialize();
-}
-
-static void voice_touch_callback(int input_event_type, const char *result_out, void *user_data)
-{
-}
-
-TEST_F(MMIIpcTest, MMIFWIpcRegisterSuccess)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_register_input_event_result_cb(input_event_type, (rpc_port_proxy_mmi_result_cb_cb)voice_touch_callback);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIIpcTest, MMIFWIpcRegisterFailNoEvent)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_NONE;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_register_input_event_result_cb(MMI_INPUT_EVENT_TYPE_NONE, (rpc_port_proxy_mmi_result_cb_cb)voice_touch_callback);
- EXPECT_EQ(res, MMI_ERROR_INVALID_PARAMETER);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIIpcTest, MMIFWIpcRegisterFailNoCallback)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_register_input_event_result_cb(input_event_type, NULL);
- EXPECT_EQ(res, MMI_ERROR_INVALID_PARAMETER);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIIpcTest, MMIFWIpcRegisterFailNoClient)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_client_destroy();
-
- res = mmi_ipc_register_input_event_result_cb(input_event_type, (rpc_port_proxy_mmi_result_cb_cb)voice_touch_callback);
- EXPECT_EQ(res, MMI_ERROR_OPERATION_FAILED);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIIpcTest, MMIFWIpcRegisterFailNoRpcHandle)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_ipc_deinitialize();
-
- mmi_handle mmi_client = mmi_client_get();
- mmi_client->rpc_h = NULL;
-
- res = mmi_ipc_register_input_event_result_cb(input_event_type, (rpc_port_proxy_mmi_result_cb_cb)voice_touch_callback);
- EXPECT_EQ(res, MMI_ERROR_OPERATION_FAILED);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIIpcTest, MMIFWIpcActivateSuccess)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_register_input_event_result_cb(input_event_type, (rpc_port_proxy_mmi_result_cb_cb)voice_touch_callback);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIIpcTest, MMIFWIpcActivateFailNoEvent)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_register_input_event_result_cb(input_event_type, (rpc_port_proxy_mmi_result_cb_cb)voice_touch_callback);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_activate_input_event(MMI_INPUT_EVENT_TYPE_NONE);
- EXPECT_EQ(res, MMI_ERROR_INVALID_PARAMETER);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIIpcTest, MMIFWIpcActivateFailNoRpcHandle)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_register_input_event_result_cb(input_event_type, (rpc_port_proxy_mmi_result_cb_cb)voice_touch_callback);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_ipc_deinitialize();
-
- mmi_handle mmi_client = mmi_client_get();
- mmi_client->rpc_h = NULL;
-
- res = mmi_ipc_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_OPERATION_FAILED);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIIpcTest, MMIFWIpcActivateFailAlreadyDone)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_register_input_event_result_cb(input_event_type, (rpc_port_proxy_mmi_result_cb_cb)voice_touch_callback);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_OPERATION_FAILED);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIIpcTest, MMIFWIpcDeactivateSuccess)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_register_input_event_result_cb(input_event_type, (rpc_port_proxy_mmi_result_cb_cb)voice_touch_callback);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_deactivate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIIpcTest, MMIFWIpcDeactivateFailNoEvent)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_register_input_event_result_cb(input_event_type, (rpc_port_proxy_mmi_result_cb_cb)voice_touch_callback);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_deactivate_input_event(MMI_INPUT_EVENT_TYPE_NONE);
- EXPECT_EQ(res, MMI_ERROR_INVALID_PARAMETER);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIIpcTest, MMIFWIpcDeactivateFailNoRpcHandle)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_register_input_event_result_cb(input_event_type, (rpc_port_proxy_mmi_result_cb_cb)voice_touch_callback);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_ipc_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_ipc_deinitialize();
-
- mmi_handle mmi_client = mmi_client_get();
- mmi_client->rpc_h = NULL;
-
- res = mmi_ipc_deactivate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_OPERATION_FAILED);
-
- mmi_deinitialize();
-}
+++ /dev/null
-/*
- * 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 "mmi.h"
-#include "mmi-client.h"
-#include "mmi-tests.h"
-#include "mmi-ipc.h"
-
-#include <Ecore.h>
-#include <rpc-port-internal.h>
-
-class MMIMainTest : public ::testing::Test
-{
-public:
- void SetUp(void) override
- {
- ecore_init();
- }
-
- void TearDown(void) override
- {
- ecore_shutdown();
- }
-};
-
-TEST_F(MMIMainTest, MMIMainInit)
-{
- int res = mmi_initialize();
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIMainTest, MmiClientCreateSuccess)
-{
- int res = mmi_client_create();
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_client_destroy();
-}
-
-static void voice_touch_callback(int input_event_type, const char *result_out, void *user_data)
-{
-}
-
-static void voice_recognition_callback(int input_event_type, const char *result_out, void *user_data)
-{
-}
-
-TEST_F(MMIMainTest, MMIClientSetResultCbSuccess)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_client_set_result_cb(input_event_type, voice_touch_callback, NULL);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_handle mmi_client = mmi_client_get();
-
- GList* iter = NULL;
- mmi_result_cb_s *data = NULL;
-
- iter = g_list_first(mmi_client->result_cb_list);
- if(NULL != iter) {
- data = (mmi_result_cb_s*)iter->data;
- EXPECT_NE(data->result_callback, nullptr);
- EXPECT_EQ(data->result_callback, voice_touch_callback);
- EXPECT_EQ(data->input_event_type, input_event_type);
- }
- else {
- EXPECT_TRUE(false);
- }
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIMainTest, MMIClientSetResultCbFail)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_client_set_result_cb(input_event_type, NULL, NULL);
- EXPECT_EQ(res, MMI_ERROR_INVALID_PARAMETER);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIMainTest, MMISetResultCbSuccess)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_set_result_cb(input_event_type, voice_touch_callback, NULL);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIMainTest, MMISetResultCbFail)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_set_result_cb(input_event_type, NULL, NULL);
- EXPECT_EQ(res, MMI_ERROR_INVALID_PARAMETER);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIMainTest, MMIClientDestroyRemoveGList)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_set_result_cb(input_event_type, voice_touch_callback, NULL);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_set_result_cb(MMI_INPUT_EVENT_TYPE_VOICE_RECOGNITION, voice_recognition_callback, NULL);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_client_destroy();
-}
-
-TEST_F(MMIMainTest, MMISetResultCbFailNoClient)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_client_destroy();
-
- res = mmi_set_result_cb(input_event_type, voice_touch_callback, NULL);
- EXPECT_EQ(res, MMI_ERROR_OPERATION_FAILED);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIMainTest, MMISetResultCbFailNoRpcHandle)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_ipc_deinitialize();
-
- mmi_handle mmi_client = mmi_client_get();
- mmi_client->rpc_h = NULL;
-
- res = mmi_set_result_cb(input_event_type, voice_touch_callback, NULL);
- EXPECT_EQ(res, MMI_ERROR_OPERATION_FAILED);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIMainTest, MMIActivateInputEventSuccess)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_set_result_cb(input_event_type, voice_touch_callback, NULL);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIMainTest, MMIActivateInputEventFailNoEvent)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_set_result_cb(input_event_type, voice_touch_callback, NULL);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_activate_input_event(MMI_INPUT_EVENT_TYPE_VOICE_RECOGNITION);
- EXPECT_EQ(res, MMI_ERROR_INVALID_PARAMETER);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIMainTest, MMIActivateInputEventFailNoCallback)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_INVALID_PARAMETER);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIMainTest, MMIActivateInputEventFailNoRpcHandle)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_set_result_cb(input_event_type, voice_touch_callback, NULL);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_ipc_deinitialize();
-
- mmi_handle mmi_client = mmi_client_get();
- mmi_client->rpc_h = NULL;
-
- res = mmi_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_OPERATION_FAILED);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIMainTest, MMIActivateInputEventFailAlreadyDone)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_set_result_cb(input_event_type, voice_touch_callback, NULL);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_OPERATION_FAILED);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIMainTest, MMIDeactivateInputEventSuccess)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_set_result_cb(input_event_type, voice_touch_callback, NULL);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_deactivate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIMainTest, MMIDeactivateInputEventFailNoEvent)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_set_result_cb(input_event_type, voice_touch_callback, NULL);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_deactivate_input_event(MMI_INPUT_EVENT_TYPE_VOICE_RECOGNITION);
- EXPECT_EQ(res, MMI_ERROR_INVALID_PARAMETER);
-
- mmi_deinitialize();
-}
-
-TEST_F(MMIMainTest, MMIDeactivateInputEventFailNoRpcHandle)
-{
- int res = mmi_initialize();
- mmi_input_event_type_e input_event_type = MMI_INPUT_EVENT_TYPE_VOICE_TOUCH;
-
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_set_result_cb(input_event_type, voice_touch_callback, NULL);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- res = mmi_activate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_NONE);
-
- mmi_ipc_deinitialize();
-
- mmi_handle mmi_client = mmi_client_get();
- mmi_client->rpc_h = NULL;
-
- res = mmi_deactivate_input_event(input_event_type);
- EXPECT_EQ(res, MMI_ERROR_OPERATION_FAILED);
-
- mmi_deinitialize();
-}
--- /dev/null
+#include <Ecore.h>
+
+Ecore_Idle_Enterer *_idle_before = nullptr;
+bool g_flag_wait_done = false;
+
+static Eina_Bool _e_cb_idle_before(void *data) {
+ (void) data;
+
+ g_flag_wait_done = true;
+ return ECORE_CALLBACK_RENEW;
+}
+
+void wait_for_dispatch() {
+ g_flag_wait_done = false;
+ _idle_before = ecore_idle_enterer_before_add(_e_cb_idle_before, NULL);
+ while (!g_flag_wait_done) {
+ ecore_main_loop_iterate();
+ }
+ ecore_idle_enterer_del(_idle_before);
+}
\ No newline at end of file
--- /dev/null
+mmi_manager_tests_srcs = [
+ 'mmi-manager-tests.cpp',
+ 'mmi-client-tests.cpp',
+ 'mmi-manager-main-tests.cpp',
+ 'ecore-event-dispatcher.cpp',
+ 'port-instance-manager/mmi-port-instance-manager-tests.cpp',
+ 'node-prototype/mmi-node-prototype-tests.cpp',
+ 'node-prototype-manager/mmi-node-prototype-manager-tests.cpp',
+ 'node-instance-manager/mmi-node-instance-manager-tests.cpp',
+ 'workflow-prototype/mmi-workflow-prototype-tests.cpp',
+ 'workflow-instance/mmi-workflow-instance-tests.cpp',
+ 'workflow-instance-manager/mmi-workflow-instance-manager-tests.cpp',
+ 'plugin-module-registry/mmi-plugin-module-registry-tests.cpp',
+ ]
+
+gmock_dep = dependency('gmock', method : 'pkg-config')
+ecore_dep = dependency('ecore', method : 'pkg-config')
+
+mmi_manager_tests_include_dirs = include_directories(
+ '.',
+ '../../src/common/',
+ '../../src/mmi-manager/',
+ )
+
+tc = executable(
+ 'mmi-manager-tests',
+ mmi_manager_tests_srcs,
+ include_directories : [ mmi_manager_tests_include_dirs ],
+ dependencies : [mmi_manager_declared_dep, gmock_dep, ecore_dep],
+ install_dir : mmi_prefix_bindir,
+ install : true
+ )
+
+test('mmi-manager-tests', tc, args : ['--gtest_output=xml:./mmi-manager-tests.xml'])
--- /dev/null
+/*
+* Copyright © 2021 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 "mmi-client.h"
+#include "mmi-manager.h"
+#include "mmi-manager-tests.h"
+
+using namespace mmi;
+
+class MMIClientTest : public ::testing::Test {
+public:
+ void SetUp(void) override {
+ }
+
+ void TearDown(void) override {
+ }
+
+ ClientManager client_manager;
+};
+
+
+TEST_F(MMIClientTest, MMIClientInitShutdown) {
+ int res = client_manager.initialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ client_manager.deinitialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+}
+
+TEST_F(MMIClientTest, MMIClientAddGetClient) {
+ std::string app_id{"org.tizen.mmi-system-ux-test"};
+ Client *client = nullptr, *client_retrieved = nullptr;
+
+ int res = client_manager.initialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ client = client_manager.add_client(app_id);
+ EXPECT_NE(client, nullptr);
+
+ client_retrieved = client_manager.get_client(app_id);
+ EXPECT_EQ(client_retrieved, client);
+
+ res = client_manager.deinitialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+}
+
+TEST_F(MMIClientTest, MMIClientAddRemoveClient) {
+ std::string app_id{"org.tizen.mmi-system-ux-test"};
+ Client *client = nullptr;
+
+ int res = client_manager.initialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ client = client_manager.add_client(app_id);
+ EXPECT_NE(client, nullptr);
+
+ res = client_manager.remove_client(app_id);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ res = client_manager.deinitialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+}
+
+TEST_F(MMIClientTest, MMIClientSetGetClientUID) {
+ std::string app_id{"org.tizen.mmi-system-ux-test"};
+ Client *client = nullptr;
+ uid_t uid = 1;
+
+ int res = client_manager.initialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ client = client_manager.add_client(app_id);
+
+ res = client_manager.set_client_uid(client, uid);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ uid_t retrieved = client_manager.get_client_uid(client);
+ EXPECT_EQ(uid, retrieved);
+
+ res = client_manager.remove_client(app_id);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ res = client_manager.deinitialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+}
+
+TEST_F(MMIClientTest, MMIClientSetGetClientPID) {
+ std::string app_id{"org.tizen.mmi-system-ux-test"};
+ Client *client = nullptr;
+ pid_t pid = 1;
+
+ int res = client_manager.initialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ client = client_manager.add_client(app_id);
+
+ res = client_manager.set_client_pid(client, pid);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ pid_t retrieved = client_manager.get_client_pid(client);
+ EXPECT_EQ(pid, retrieved);
+
+ res = client_manager.remove_client(app_id);
+
+ res = client_manager.deinitialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+}
+
+TEST_F(MMIClientTest, MMIClientGetClientSender) {
+ std::string app_id{"org.tizen.mmi-system-ux-test"};
+ std::string sender;
+ Client *client = nullptr;
+
+ int res = client_manager.initialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ client = client_manager.add_client(app_id);
+
+ sender = client_manager.get_client_sender(client);
+ EXPECT_EQ(sender, app_id);
+
+ res = client_manager.remove_client(app_id);
+ EXPECT_EQ(res, 0);
+
+ res = client_manager.deinitialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+}
+
--- /dev/null
+/*
+* Copyright © 2021 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 "mmi-manager.h"
+#include "mmi-manager-tests.h"
+#include "mmi-self-container.h"
+
+namespace {
+
+using namespace mmi;
+using namespace mmi::communication;
+
+class CommunicationChannelManagerDummy : public CommunicationChannelManager {
+public:
+ int connect() override {
+ return MMI_ERROR_NONE;
+ }
+ int disconnect() override {
+ return MMI_ERROR_NONE;
+ }
+ int send(communication::Message *message) override {
+ return MMI_ERROR_NONE;
+ }
+
+ void on_observer_event(
+ const WORKFLOW_OUTPUT_EVENT_TYPE &event, std::any data) override {
+ return;
+ }
+};
+
+struct CommunicationChannelFactoryDummy : public CommunicationChannelManagerFactory {
+ std::shared_ptr<CommunicationChannelManager> create_channel() override {
+ return std::make_shared<CommunicationChannelManagerDummy>();
+ }
+};
+
+class MMIMANAGERMainTest : public ::testing::Test {
+public:
+ void SetUp(void) override {
+ }
+
+ void TearDown(void) override {
+ }
+
+};
+
+
+TEST_F(MMIMANAGERMainTest, MMIMANAGERMainInit) {
+ int res = 0;
+
+ mmi::Manager manager(
+ std::make_shared<CommunicationChannelFactoryDummy>(),
+ std::make_shared<PluginModuleProxyFactorySelfContainerTest>());
+ res = manager.initialize();
+
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ res = manager.deinitialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+}
+
+} // namespace
--- /dev/null
+/*
+* Copyright © 2021 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 "mmi-manager-tests.h"
+
+int main(int argc, char **argv) {
+ auto testResults = false;
+
+#ifdef TIZEN_TEST_GCOV
+ setenv("GCOV_PREFIX", "/tmp", 1);
+#endif
+ try {
+ ::testing::InitGoogleMock(&argc, argv);
+ ::testing::FLAGS_gtest_death_test_style = "fast";
+ } catch ( ... ) {
+ PRINT("Error occurred while trying to initialize GoogleTest.\n");
+ exit(EXIT_FAILURE);
+ }
+
+ try {
+ testResults = (RUN_ALL_TESTS() == 0) ? true : false;
+ } catch (const ::testing::internal::GoogleTestFailureException &e) {
+ testResults = false;
+ PRINT("GoogleTestFailureException has been thrown: %s\n", e.what());
+ }
+
+#ifdef TIZEN_TEST_GCOV
+ __gcov_flush();
+#endif
+ return (testResults ? 0 : 1);
+}
+
--- /dev/null
+/*
+* Copyright © 2021 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_MANAGER_TESTS_H__
+#define __MMI_MANAGER_TESTS_H__
+
+#include <stdio.h>
+#include <gmock/gmock.h>
+#include <Ecore.h>
+
+#define PRINT printf
+
+#ifdef TIZEN_TEST_GCOV
+extern "C" void __gcov_flush(void);
+#endif
+extern void wait_for_dispatch();
+
+using ::testing::TestWithParam;
+using ::testing::Bool;
+using ::testing::Values;
+using ::testing::Combine;
+
+#endif //__MMI_MANAGER_TESTS_H__
--- /dev/null
+#include <iostream>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include "mmi-node-instance-manager.h"
+#include "mmi-self-container.h"
+
+using namespace mmi;
+
+extern "C" {
+ /* Add wrapper functions here with __wrap_ and __real prefix
+ Example :
+
+ int __real_vconf_get_int(const char *in_key, int *intval);
+ int __wrap_vconf_get_int(const char *in_key, int *intval)
+ {
+ if (strcmp(in_key, "TestKey") == 0)
+ return 0;
+
+ return __real_vconf_get_int(in_key, intval);
+ }
+ */
+}
+
+namespace {
+
+class NodePrototypeStoreDummy : public INodePrototypeStore {
+public:
+ virtual bool add_node_prototype(std::shared_ptr<NodePrototype> prototype) override {
+ return true;
+ }
+ virtual std::shared_ptr<NodePrototype> get_node_prototype(
+ mmi_standard_node_type_e type, mmi_standard_node_sub_type_e sub_type) override {
+ last_query = std::make_pair(type, sub_type);
+ return nullptr;
+ }
+
+ std::pair<mmi_standard_node_type_e, mmi_standard_node_sub_type_e> last_query;
+};
+
+class PluginModuleProxyProviderDummy : public IPluginModuleProxyProvider {
+public:
+ PluginModuleProxyProviderDummy() {
+ proxy = factory.create(
+ PluginModuleInfo{mmi_plugin_module_type_e::SELF_CONTAINED, "dummy"});
+ }
+ virtual std::shared_ptr<IPluginModuleProxy> get_plugin_module_proxy(
+ PluginModuleInfo plugin_module_info) override {
+ return proxy;
+ }
+
+ PluginModuleProxyFactorySelfContainerTest factory;
+ std::shared_ptr<IPluginModuleProxy> proxy;
+};
+
+class NodeInstanceManagerTest : public testing::Test {
+public:
+ NodeInstanceManagerTest() {
+ }
+ virtual ~NodeInstanceManagerTest() {
+ }
+ void SetUp() override {
+ prototype_store = std::make_shared<NodePrototypeStoreDummy>();
+ plugin_module_proxy_provider = std::make_shared<PluginModuleProxyProviderDummy>();
+
+ manager.set_node_prototype_store(prototype_store);
+ manager.set_plugin_module_proxy_provider(plugin_module_proxy_provider);
+
+ ASSERT_NE(prototype_store, nullptr);
+ ASSERT_NE(plugin_module_proxy_provider, nullptr);
+ }
+ void TearDown() override {
+ }
+
+ NodeInstanceManager manager;
+
+ std::shared_ptr<NodePrototypeStoreDummy> prototype_store;
+ std::shared_ptr<PluginModuleProxyProviderDummy> plugin_module_proxy_provider;
+};
+
+TEST_F(NodeInstanceManagerTest, ProperNodePrototypeQueriedWhenCreatingNodeInstance) {
+ prototype_store->last_query = std::make_pair(
+ MMI_STANDARD_NODE_TYPE_NONE, std::monostate{});
+
+ std::shared_ptr<NodeInstance> instance = manager.create_node_instance(
+ MMI_STANDARD_NODE_TYPE_PROCESSOR, MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR );
+
+ ASSERT_EQ(prototype_store->last_query.first, MMI_STANDARD_NODE_TYPE_PROCESSOR);
+ ASSERT_EQ(prototype_store->last_query.second, mmi_standard_node_sub_type_e{MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR});
+}
+
+} // namespace
+
+#ifdef TEST_MAIN_REQUIRED
+int main(int argc, char** argv) {
+ std::cout << "Starting tests" << std::endl;
+ testing::InitGoogleTest(&argc, argv);
+ int ret = RUN_ALL_TESTS();
+ return ret;
+}
+#endif
--- /dev/null
+#include <iostream>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include "mmi-node-prototype-manager.h"
+
+using namespace mmi;
+
+extern "C" {
+ /* Add wrapper functions here with __wrap_ and __real prefix
+ Example :
+
+ int __real_vconf_get_int(const char *in_key, int *intval);
+ int __wrap_vconf_get_int(const char *in_key, int *intval)
+ {
+ if (strcmp(in_key, "TestKey") == 0)
+ return 0;
+
+ return __real_vconf_get_int(in_key, intval);
+ }
+ */
+}
+
+namespace {
+
+class NodePrototypeManagerTest : public testing::Test {
+public:
+ NodePrototypeManagerTest() {
+ }
+ virtual ~NodePrototypeManagerTest() {
+ }
+ void SetUp() override {
+ valid_prototype = std::make_shared<NodePrototype>();
+ ASSERT_TRUE(valid_prototype != nullptr);
+
+ valid_prototype->set_plugin_module_info(
+ PluginModuleInfo{mmi_plugin_module_type_e::SHARED_LIBRARY, "test.so"});
+
+ valid_prototype->set_type(MMI_STANDARD_NODE_TYPE_SOURCE);
+ valid_prototype->set_sub_type(MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT);
+
+ ASSERT_TRUE(valid_prototype->is_valid());
+ }
+ void TearDown() override {
+ }
+
+ NodePrototypeManager manager;
+ std::shared_ptr<NodePrototype> valid_prototype;
+};
+
+TEST_F(NodePrototypeManagerTest, NodePrototypeManagerProperlyAddedAndRetrieved_p) {
+ manager.add_node_prototype(valid_prototype);
+
+ auto prototype = manager.get_node_prototype(
+ valid_prototype->get_type(),
+ valid_prototype->get_sub_type());
+
+ ASSERT_TRUE(prototype != nullptr);
+}
+
+TEST_F(NodePrototypeManagerTest, NodePrototypeManagerRefusesInvalidPrototype_n) {
+ auto invalid_prototype = std::make_shared<NodePrototype>();
+
+ invalid_prototype->set_type(MMI_STANDARD_NODE_TYPE_SOURCE);
+ invalid_prototype->set_sub_type(MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR);
+
+ manager.add_node_prototype(invalid_prototype);
+
+ auto prototype = manager.get_node_prototype(
+ invalid_prototype->get_type(),
+ invalid_prototype->get_sub_type());
+
+ ASSERT_TRUE(prototype == nullptr);
+}
+
+} // namespace
+
+#ifdef TEST_MAIN_REQUIRED
+int main(int argc, char** argv) {
+ std::cout << "Starting tests" << std::endl;
+ testing::InitGoogleTest(&argc, argv);
+ int ret = RUN_ALL_TESTS();
+ return ret;
+}
+#endif
--- /dev/null
+#include <iostream>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include "mmi-node-prototype.h"
+
+using namespace mmi;
+
+extern "C" {
+ /* Add wrapper functions here with __wrap_ and __real prefix
+ Example :
+
+ int __real_vconf_get_int(const char *in_key, int *intval);
+ int __wrap_vconf_get_int(const char *in_key, int *intval)
+ {
+ if (strcmp(in_key, "TestKey") == 0)
+ return 0;
+
+ return __real_vconf_get_int(in_key, intval);
+ }
+ */
+}
+
+namespace {
+
+class NodePrototypeTest : public testing::Test {
+public:
+ NodePrototypeTest() {
+ }
+ virtual ~NodePrototypeTest() {
+ }
+ void SetUp() override {
+ prototype = std::make_shared<NodePrototype>();
+ ASSERT_TRUE(prototype != nullptr);
+ }
+ void TearDown() override {
+ }
+ std::shared_ptr<NodePrototype> prototype;
+};
+
+TEST_F(NodePrototypeTest, NodePrototypeValidationSucceedsForDifferentNodeTypes_p) {
+ prototype->set_plugin_module_info(
+ PluginModuleInfo{mmi_plugin_module_type_e::SHARED_LIBRARY, "test.so"});
+
+ prototype->set_type(MMI_STANDARD_NODE_TYPE_SOURCE);
+ prototype->set_sub_type(MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT);
+ ASSERT_TRUE(prototype->is_valid());
+
+ prototype->set_type(MMI_STANDARD_NODE_TYPE_PROCESSOR);
+ prototype->set_sub_type(MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR);
+ ASSERT_TRUE(prototype->is_valid());
+
+ prototype->set_type(MMI_STANDARD_NODE_TYPE_LOGIC);
+ prototype->set_sub_type(MMI_STANDARD_NODE_LOGIC_TYPE_FIXED_STRING_MATCH);
+ ASSERT_TRUE(prototype->is_valid());
+}
+
+TEST_F(NodePrototypeTest, NodePrototypeValidationFailsWithNoSubtype_n) {
+ prototype->set_plugin_module_info(
+ PluginModuleInfo{mmi_plugin_module_type_e::SHARED_LIBRARY, "test.so"});
+
+ prototype->set_type(MMI_STANDARD_NODE_TYPE_SOURCE);
+ /* No sub type provided */
+
+ ASSERT_FALSE(prototype->is_valid());
+}
+
+TEST_F(NodePrototypeTest, NodePrototypeValidationFailsWithIncorrectSubtype_n) {
+ prototype->set_plugin_module_info(
+ PluginModuleInfo{mmi_plugin_module_type_e::SHARED_LIBRARY, "test.so"});
+
+ prototype->set_type(MMI_STANDARD_NODE_TYPE_SOURCE);
+ /* PROCESSOR sub type for SOURCE type */
+ prototype->set_sub_type(MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR);
+
+ ASSERT_FALSE(prototype->is_valid());
+}
+
+TEST_F(NodePrototypeTest, NodePrototypeValidationFailsWithNoPluginModuleInfo_n) {
+ prototype->set_plugin_module_info(
+ PluginModuleInfo{mmi_plugin_module_type_e::SHARED_LIBRARY, ""});
+ /* No plugin module identifier provided */
+
+ prototype->set_type(MMI_STANDARD_NODE_TYPE_SOURCE);
+ prototype->set_sub_type(MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT);
+
+ ASSERT_FALSE(prototype->is_valid());
+}
+
+TEST_F(NodePrototypeTest, PortInfoProperlyAdded_p) {
+ ASSERT_TRUE(prototype->get_port_infos().size() == 0);
+
+ PortInfo port_info_1 = {"test_port_1", MMI_PORT_TYPE_IN, MMI_DATA_TYPE_TEXT, "test_description"};
+ prototype->add_port_info(port_info_1);
+
+ PortInfo port_info_2 = {"test_port_2", MMI_PORT_TYPE_OUT, MMI_DATA_TYPE_BOOLEAN, "test_description"};
+ prototype->add_port_info(port_info_2);
+
+ ASSERT_TRUE(prototype->get_port_infos().size() == 2);
+}
+
+TEST_F(NodePrototypeTest, PortInfoWithSameNameNotAdded_n) {
+ ASSERT_TRUE(prototype->get_port_infos().size() == 0);
+
+ PortInfo port_info_1 = {"test_port_1", MMI_PORT_TYPE_IN, MMI_DATA_TYPE_TEXT, "test_description"};
+ prototype->add_port_info(port_info_1);
+
+ PortInfo port_info_2 = {"test_port_1", MMI_PORT_TYPE_OUT, MMI_DATA_TYPE_BOOLEAN, "test_description"};
+ prototype->add_port_info(port_info_2);
+
+ ASSERT_TRUE(prototype->get_port_infos().size() == 1);
+}
+
+TEST_F(NodePrototypeTest, AttributeProperlyAdded_p) {
+ ASSERT_TRUE(prototype->get_attribute_infos().size() == 0);
+
+ AttributeInfo attribute_info_1 = {"test_attribute_1", MMI_PRIMITIVE_VALUE_TYPE_INT};
+ prototype->add_attribute_info(attribute_info_1);
+
+ AttributeInfo attribute_info_2 = {"test_attribute_2", MMI_PRIMITIVE_VALUE_TYPE_STRING};
+ prototype->add_attribute_info(attribute_info_2);
+
+ ASSERT_TRUE(prototype->get_attribute_infos().size() == 2);
+}
+
+TEST_F(NodePrototypeTest, AttributeWithSameNameNotAdded_n) {
+ ASSERT_TRUE(prototype->get_attribute_infos().size() == 0);
+
+ AttributeInfo attribute_info_1 = {"test_attribute_1", MMI_PRIMITIVE_VALUE_TYPE_INT};
+ prototype->add_attribute_info(attribute_info_1);
+
+ AttributeInfo attribute_info_2 = {"test_attribute_1", MMI_PRIMITIVE_VALUE_TYPE_STRING};
+ prototype->add_attribute_info(attribute_info_2);
+
+ ASSERT_TRUE(prototype->get_attribute_infos().size() == 1);
+}
+
+} // namespace
+
+#ifdef TEST_MAIN_REQUIRED
+int main(int argc, char** argv) {
+ std::cout << "Starting tests" << std::endl;
+ testing::InitGoogleTest(&argc, argv);
+ int ret = RUN_ALL_TESTS();
+ return ret;
+}
+#endif
--- /dev/null
+#include <iostream>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include "mmi-plugin-module-registry.h"
+#include "mmi-self-container.h"
+
+using namespace mmi;
+
+extern "C" {
+ /* Add wrapper functions here with __wrap_ and __real prefix
+ Example :
+
+ int __real_vconf_get_int(const char *in_key, int *intval);
+ int __wrap_vconf_get_int(const char *in_key, int *intval)
+ {
+ if (strcmp(in_key, "TestKey") == 0)
+ return 0;
+
+ return __real_vconf_get_int(in_key, intval);
+ }
+ */
+}
+
+namespace {
+
+class NodePrototypeStoreDummy : public INodePrototypeStore {
+public:
+ virtual bool add_node_prototype(std::shared_ptr<NodePrototype> prototype) override {
+ _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()),
+ static_cast<int>(prototype->get_plugin_module_info().plugin_module_type),
+ prototype->get_plugin_module_info().plugin_module_identifier.c_str());
+
+ for (auto& port : prototype->get_port_infos()) {
+ _D("Port info: name=%s, port_type=%d, data_type=%d, data_description=%s",
+ port.name.c_str(), port.port_type, port.data_type, port.data_description.c_str());
+ }
+
+ for (auto& attribute : prototype->get_attribute_infos()) {
+ _D("Attribute info: name=%s, value_type=%d",
+ attribute.name.c_str(), attribute.value_type);
+ }
+
+ return true;
+ }
+ virtual std::shared_ptr<NodePrototype> get_node_prototype(
+ mmi_standard_node_type_e type, mmi_standard_node_sub_type_e sub_type) override {
+ for (auto &prototype : m_prototypes) {
+ if (prototype->get_type() == type && prototype->get_sub_type() == sub_type) {
+ return prototype;
+ }
+ }
+ return nullptr;
+ }
+ size_t get_prototype_count() {
+ return m_prototypes.size();
+ }
+ std::vector<std::shared_ptr<NodePrototype>> m_prototypes;
+};
+
+class WorkflowPrototypeStoreDummy : public IWorkflowPrototypeStore {
+public:
+ virtual bool add_workflow_prototype(std::shared_ptr<WorkflowPrototype> prototype) override {
+ _D("Adding prototype : %d", prototype->is_valid());
+ m_prototypes.push_back(prototype);
+
+ _D("Workflow prototype added: type=%d, plugin_module_type=%d, plugin_module_identifier=%s",
+ prototype->get_type(),
+ static_cast<int>(prototype->get_plugin_module_info().plugin_module_type),
+ 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(" link_infos:");
+ for (auto& elem : prototype->get_link_infos()) {
+ _D(" from_node_name=%s, from_port_name=%s, to_node_name=%s, to_port_name=%s",
+ elem.from_node_name.c_str(), elem.from_port_name.c_str(),
+ elem.to_node_name.c_str(), elem.to_port_name.c_str());
+ }
+ _D(" output_assignment_infos:");
+ for (auto& elem : prototype->get_output_assignment_infos()) {
+ _D(" output_name=%s, from_node_name=%s, from_port_name=%s",
+ elem.output_name.c_str(), elem.from_node_name.c_str(), elem.from_port_name.c_str());
+ }
+
+ return true;
+ }
+ virtual std::shared_ptr<WorkflowPrototype> get_workflow_prototype(
+ mmi_standard_workflow_type_e type) override {
+ for (auto &prototype : m_prototypes) {
+ if (prototype->get_type() == type) {
+ return prototype;
+ }
+ }
+ return nullptr;
+ }
+ size_t get_prototype_count() {
+ return m_prototypes.size();
+ }
+ std::vector<std::shared_ptr<WorkflowPrototype>> m_prototypes;
+};
+
+/* Derived class to access protected members */
+class PluginModuleRegistry_Derived : public PluginModuleRegistry {
+public:
+ typedef std::pair<mmi_plugin_module_type_e, std::string> plugin_module_map_key;
+ std::map<plugin_module_map_key, std::weak_ptr<IPluginModuleProxy>>& get_plugin_modules() {
+ return m_plugin_modules;
+ }
+};
+
+class PluginModuleRegistryTest : public testing::Test {
+public:
+ PluginModuleRegistryTest() {
+ }
+ virtual ~PluginModuleRegistryTest() {
+ }
+ void SetUp() override {
+ factory = std::make_shared<PluginModuleProxyFactorySelfContainerTest>();
+ node_prototype_store = std::make_shared<NodePrototypeStoreDummy>();
+ workflow_prototype_store = std::make_shared<WorkflowPrototypeStoreDummy>();
+ registry.set_plugin_module_proxy_factory(factory);
+ registry.set_node_prototype_store(node_prototype_store);
+ registry.set_workflow_prototype_store(workflow_prototype_store);
+ }
+ void TearDown() override {
+ }
+
+ std::shared_ptr<PluginModuleProxyFactorySelfContainerTest> factory;
+ std::shared_ptr<INodePrototypeStore> node_prototype_store;
+ std::shared_ptr<IWorkflowPrototypeStore> workflow_prototype_store;
+ PluginModuleRegistry_Derived registry;
+};
+
+TEST_F(PluginModuleRegistryTest, PluginModuleProxyProperlyCreated_p) {
+ registry.initialize();
+
+ std::map<PluginModuleRegistry_Derived::plugin_module_map_key, std::weak_ptr<IPluginModuleProxy>>& plugin_modules = registry.get_plugin_modules();
+
+ auto plugin_module = registry.get_plugin_module_proxy(
+ PluginModuleInfo{mmi_plugin_module_type_e::SHARED_LIBRARY, "dummy.so"});
+ ASSERT_NE(nullptr, plugin_module);
+
+ auto it = plugin_modules.find(std::make_pair(
+ mmi_plugin_module_type_e::SHARED_LIBRARY, "dummy.so"));
+
+ ASSERT_NE(plugin_modules.end(), it);
+
+ /* Reference count should be 1 */
+ ASSERT_EQ(1, it->second.use_count());
+
+ registry.deinitialize();
+}
+
+TEST_F(PluginModuleRegistryTest, PluginModuleProxyProperlyDestroyedWhenGoesOutOfScope_p) {
+ registry.initialize();
+
+ std::map<PluginModuleRegistry_Derived::plugin_module_map_key, std::weak_ptr<IPluginModuleProxy>>& plugin_modules = registry.get_plugin_modules();
+
+ {
+ auto plugin_module = registry.get_plugin_module_proxy(
+ PluginModuleInfo{mmi_plugin_module_type_e::SHARED_LIBRARY, "dummy.so"});
+ ASSERT_NE(nullptr, plugin_module);
+
+ std::map<PluginModuleRegistry_Derived::plugin_module_map_key, std::weak_ptr<IPluginModuleProxy>>& plugin_modules = registry.get_plugin_modules();
+ auto it = plugin_modules.find(std::make_pair(mmi_plugin_module_type_e::SHARED_LIBRARY, "dummy.so"));
+
+ ASSERT_NE(plugin_modules.end(), it);
+ ASSERT_EQ(1, it->second.use_count());
+ }
+
+ auto it = plugin_modules.find(std::make_pair(mmi_plugin_module_type_e::SHARED_LIBRARY, "dummy.so"));
+
+ ASSERT_NE(plugin_modules.end(), it);
+
+ /* Reference count should be 0, since the 'plugin_module' variable went out of scope */
+ ASSERT_EQ(0, it->second.use_count());
+
+ registry.deinitialize();
+}
+
+TEST_F(PluginModuleRegistryTest, PluginModuleProxyNotCreatedAgainWhenAlreadyExists_n) {
+ registry.initialize();
+
+ std::map<PluginModuleRegistry_Derived::plugin_module_map_key, std::weak_ptr<IPluginModuleProxy>>& plugin_modules = registry.get_plugin_modules();
+
+ auto plugin_module_1 = registry.get_plugin_module_proxy(
+ PluginModuleInfo{mmi_plugin_module_type_e::SHARED_LIBRARY, "dummy.so"});
+ ASSERT_NE(nullptr, plugin_module_1);
+
+ /* There should be 2 plugin modules by now :
+ * 1. "default.so", which is created in the 'initialize' function
+ * 2. "dummy.so", which is created in the previous line
+ * */
+ ASSERT_EQ(plugin_modules.size(), 2);
+
+ auto plugin_module_2 = registry.get_plugin_module_proxy(
+ PluginModuleInfo{mmi_plugin_module_type_e::SHARED_LIBRARY, "dummy.so"});
+ ASSERT_NE(nullptr, plugin_module_2);
+
+ /* Size should not be incremented */
+ ASSERT_EQ(plugin_modules.size(), 2);
+
+ auto it = plugin_modules.find(std::make_pair(mmi_plugin_module_type_e::SHARED_LIBRARY, "dummy.so"));
+ ASSERT_NE(plugin_modules.end(), it);
+
+ /* Reference count should be 2, since both 'plugin_module_1' and 'plugin_module_2' variables are pointing to the same object */
+ ASSERT_EQ(2, it->second.use_count());
+
+ registry.deinitialize();
+}
+
+TEST_F(PluginModuleRegistryTest, DummyNodeInfoProperlyCreatedAndRetrieved_p) {
+ registry.initialize();
+
+ bool ret = registry.load_node_prototypes();
+ ASSERT_TRUE(ret);
+
+ auto asr_node = node_prototype_store->get_node_prototype(MMI_STANDARD_NODE_TYPE_PROCESSOR, MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR);
+ ASSERT_NE(nullptr, asr_node);
+
+ auto match_node = node_prototype_store->get_node_prototype(MMI_STANDARD_NODE_TYPE_LOGIC, MMI_STANDARD_NODE_LOGIC_TYPE_FIXED_STRING_MATCH);
+ ASSERT_NE(nullptr, match_node);
+
+ registry.deinitialize();
+}
+
+TEST_F(PluginModuleRegistryTest, NonExistingNodeNotRetrieved_n) {
+ registry.initialize();
+
+ bool ret = registry.load_node_prototypes();
+ ASSERT_TRUE(ret);
+
+ auto node = node_prototype_store->get_node_prototype(MMI_STANDARD_NODE_TYPE_PROCESSOR, MMI_STANDARD_NODE_PROCESSOR_TYPE_NONE);
+ ASSERT_EQ(nullptr, node);
+
+ registry.deinitialize();
+}
+
+TEST_F(PluginModuleRegistryTest, DummyWorkflowInfoProperlyCreatedAndRetrieved_p) {
+ registry.initialize();
+
+ bool ret = registry.load_workflow_prototypes();
+ ASSERT_TRUE(ret);
+
+ auto workflow = workflow_prototype_store->get_workflow_prototype(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND);
+ ASSERT_NE(nullptr, workflow);
+
+ registry.deinitialize();
+}
+
+TEST_F(PluginModuleRegistryTest, NonExistingWorkflowNotRetrieved_n) {
+ registry.initialize();
+
+ bool ret = registry.load_workflow_prototypes();
+ ASSERT_TRUE(ret);
+
+ auto workflow = workflow_prototype_store->get_workflow_prototype(MMI_STANDARD_WORKFLOW_VOICE_TOUCH);
+ ASSERT_EQ(nullptr, workflow);
+
+ registry.deinitialize();
+}
+
+} // namespace
+
+#ifdef TEST_MAIN_REQUIRED
+int main(int argc, char** argv) {
+ std::cout << "Starting tests" << std::endl;
+ testing::InitGoogleTest(&argc, argv);
+ int ret = RUN_ALL_TESTS();
+ return ret;
+}
+#endif
--- /dev/null
+#include <iostream>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include "mmi-port-instance-manager.h"
+
+using namespace mmi;
+
+extern "C" {
+ /* Add wrapper functions here with __wrap_ and __real prefix
+ Example :
+
+ int __real_vconf_get_int(const char *in_key, int *intval);
+ int __wrap_vconf_get_int(const char *in_key, int *intval)
+ {
+ if (strcmp(in_key, "TestKey") == 0)
+ return 0;
+
+ return __real_vconf_get_int(in_key, intval);
+ }
+ */
+}
+
+namespace {
+
+class PortInstanceManagerTest : public testing::Test {
+public:
+ PortInstanceManagerTest() {
+ }
+ virtual ~PortInstanceManagerTest() {
+ }
+ void SetUp() override {
+ }
+ void TearDown() override {
+ }
+
+ PortInstanceManager manager;
+};
+
+TEST_F(PortInstanceManagerTest, func1) {
+ ASSERT_TRUE(true);
+}
+
+} // namespace
+
+#ifdef TEST_MAIN_REQUIRED
+int main(int argc, char** argv) {
+ std::cout << "Starting tests" << std::endl;
+ testing::InitGoogleTest(&argc, argv);
+ int ret = RUN_ALL_TESTS();
+ return ret;
+}
+#endif
--- /dev/null
+#include <iostream>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include "mmi-self-container.h"
+#include "mmi-workflow-instance-manager.h"
+
+using namespace mmi;
+using namespace mmi::communication;
+
+extern "C" {
+ /* Add wrapper functions here with __wrap_ and __real prefix
+ Example :
+
+ int __real_vconf_get_int(const char *in_key, int *intval);
+ int __wrap_vconf_get_int(const char *in_key, int *intval)
+ {
+ if (strcmp(in_key, "TestKey") == 0)
+ return 0;
+
+ return __real_vconf_get_int(in_key, intval);
+ }
+ */
+}
+
+namespace {
+
+class CommunicationChannelDummy : public CommunicationChannel {
+public:
+ int connect() override {
+ return MMI_ERROR_NONE;
+ }
+ int disconnect() override {
+ return MMI_ERROR_NONE;
+ }
+ int send(communication::Message *message) override {
+ return MMI_ERROR_NONE;
+ }
+
+};
+
+class NodePrototypeStoreDummy : public INodePrototypeStore {
+public:
+ virtual bool add_node_prototype(std::shared_ptr<NodePrototype> prototype) override {
+ node_prototypes.push_back(prototype);
+ return true;
+ }
+ virtual std::shared_ptr<NodePrototype> get_node_prototype(
+ mmi_standard_node_type_e type, mmi_standard_node_sub_type_e sub_type) override {
+ for (auto& prototype : node_prototypes) {
+ if (prototype->get_type() == type &&
+ prototype->get_sub_type() == sub_type) {
+ return prototype;
+ }
+ }
+ return nullptr;
+ }
+ std::vector<std::shared_ptr<NodePrototype>> node_prototypes;
+};
+
+class NodeInstanceManagerDummy : public INodeInstanceManager {
+public:
+ NodeInstanceManagerDummy() {
+ node_prototype_store = std::make_shared<NodePrototypeStoreDummy>();
+
+ auto mic_prototype = std::make_shared<NodePrototype>();
+ mic_prototype->set_type(MMI_STANDARD_NODE_TYPE_SOURCE);
+ mic_prototype->set_sub_type(MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT);
+ PortInfo mic_audio{"AUDIO", MMI_PORT_TYPE_OUT, MMI_DATA_TYPE_AUDIO, "audio data"};
+ mic_prototype->add_port_info(mic_audio);
+ node_prototype_store->add_node_prototype(mic_prototype);
+
+ auto asr_prototype = std::make_shared<NodePrototype>();
+ asr_prototype->set_type(MMI_STANDARD_NODE_TYPE_PROCESSOR);
+ asr_prototype->set_sub_type(MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR);
+ PortInfo asr_audio{"AUDIO", MMI_PORT_TYPE_IN, MMI_DATA_TYPE_AUDIO, "audio data"};
+ asr_prototype->add_port_info(asr_audio);
+ node_prototype_store->add_node_prototype(asr_prototype);
+ }
+
+ virtual std::shared_ptr<NodeInstance> create_node_instance(
+ mmi_standard_node_type_e node_type,
+ mmi_standard_node_sub_type_e node_sub_type) override {
+ create_requests.push_back(std::make_pair(node_type, node_sub_type));
+ auto node_instance = std::make_shared<NodeInstance>(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);
+ node_instance->initialize();
+ }
+ return node_instance;
+ }
+ virtual bool destroy_node_instance(
+ std::shared_ptr<NodeInstance> node_instance) override {
+ destroy_requests++;
+ return true;
+ }
+ virtual bool link_node_instances(
+ std::shared_ptr<NodeInstance> from_node_instance,
+ std::shared_ptr<NodeInstance> to_node_instance,
+ std::optional<std::string> from_port_name,
+ std::optional<std::string> to_port_name) override {
+ if (from_node_instance && to_node_instance) {
+ std::shared_ptr<NodePrototype> from_prototype =
+ node_prototype_store->get_node_prototype(
+ from_node_instance->get_node_type(), from_node_instance->get_node_sub_type());
+ std::shared_ptr<NodePrototype> to_prototype =
+ node_prototype_store->get_node_prototype(
+ to_node_instance->get_node_type(), to_node_instance->get_node_sub_type());
+ if (from_prototype->has_port_with_name(from_port_name.value()) &&
+ to_prototype->has_port_with_name(to_port_name.value())) {
+ valid_link_requests++;
+ }
+ }
+ return true;
+ }
+ void set_plugin_module_proxy_provider(std::shared_ptr<IPluginModuleProxyProvider> provider) {
+ plugin_module_proxy_provider = std::move(provider);
+ }
+ std::shared_ptr<NodePrototypeStoreDummy> node_prototype_store;
+ std::shared_ptr<IPluginModuleProxyProvider> plugin_module_proxy_provider;
+ std::vector<std::pair<mmi_standard_node_type_e, mmi_standard_node_sub_type_e>> create_requests;
+ size_t destroy_requests{0};
+ size_t valid_link_requests{0};
+};
+
+class WorkflowPrototypeStoreDummy : public IWorkflowPrototypeStore {
+public:
+ bool add_workflow_prototype(std::shared_ptr<WorkflowPrototype> prototype) override {
+ last_added_workflow_prototype = prototype;
+ return true;
+ }
+ std::shared_ptr<WorkflowPrototype> get_workflow_prototype(mmi_standard_workflow_type_e type) override {
+ last_requested_workflow_type = type;
+ return last_added_workflow_prototype;
+ }
+ mmi_standard_workflow_type_e last_requested_workflow_type;
+ std::shared_ptr<WorkflowPrototype> last_added_workflow_prototype;
+};
+class PluginModuleProxyProviderDummy : public IPluginModuleProxyProvider {
+public:
+ PluginModuleProxyProviderDummy() {
+ proxy = factory.create(
+ PluginModuleInfo{mmi_plugin_module_type_e::SELF_CONTAINED, "dummy"});
+ }
+ virtual std::shared_ptr<IPluginModuleProxy> get_plugin_module_proxy(
+ const PluginModuleInfo plugin_module_info) override {
+ return proxy;
+ }
+ PluginModuleProxyFactorySelfContainerTest factory;
+ std::shared_ptr<IPluginModuleProxy> proxy;
+};
+
+/* Derived class to access protected members */
+class WorkflowInstanceManager_Derived : public WorkflowInstanceManager {
+public:
+ std::vector<std::shared_ptr<WorkflowInstance>> get_workflow_instances() {
+ return m_workflow_instances;
+ }
+};
+
+class WorkflowInstanceManagerTest : public testing::Test {
+public:
+ WorkflowInstanceManagerTest() {
+ plugin_module_proxy_provider = std::make_shared<PluginModuleProxyProviderDummy>();
+
+ node_instance_manager = std::make_shared<NodeInstanceManagerDummy>();
+ node_instance_manager->set_plugin_module_proxy_provider(plugin_module_proxy_provider);
+
+ workflow_prototype_store = std::make_shared<WorkflowPrototypeStoreDummy>();
+
+ workflow_instance_manager = std::make_shared<WorkflowInstanceManager_Derived>();
+ if (workflow_instance_manager) {
+ workflow_instance_manager->set_workflow_prototype_store(workflow_prototype_store);
+ workflow_instance_manager->set_plugin_module_proxy_provider(plugin_module_proxy_provider);
+ workflow_instance_manager->set_node_instance_manager(node_instance_manager);
+ }
+ }
+ virtual ~WorkflowInstanceManagerTest() {
+ }
+ void SetUp() override {
+ workflow_instance_manager->initialize();
+ channel.add_observer(workflow_instance_manager.get());
+ }
+ void TearDown() override {
+ workflow_instance_manager->deinitialize();
+ channel.remove_observer(workflow_instance_manager.get());
+ }
+
+ CommunicationChannelDummy channel;
+
+ std::shared_ptr<NodeInstanceManagerDummy> node_instance_manager;
+
+ std::shared_ptr<WorkflowPrototypeStoreDummy> workflow_prototype_store;
+ std::shared_ptr<PluginModuleProxyProviderDummy> plugin_module_proxy_provider;
+
+ std::shared_ptr<WorkflowInstanceManager_Derived> workflow_instance_manager;
+};
+
+TEST_F(WorkflowInstanceManagerTest, WorkflowInstanceCreatedProperly_p) {
+ ClientMessageWorkflowInstanceCreate msg;
+ msg.sender = std::string{"client-1"};
+ msg.local_workflow_instance_id = 0;
+ msg.workflow_type = MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND;
+
+ channel.notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, static_cast<Message*>(&msg));
+
+ std::shared_ptr<WorkflowInstance> instance = workflow_instance_manager->get_workflow_instance(
+ msg.sender, msg.local_workflow_instance_id);
+ ASSERT_NE(instance, nullptr);
+}
+
+TEST_F(WorkflowInstanceManagerTest, WorkflowInstanceNotCreatedProperlyWhenDuplicated_n) {
+ ClientMessageWorkflowInstanceCreate msg;
+ msg.sender = std::string{"client-1"};
+ msg.local_workflow_instance_id = 0;
+ msg.workflow_type = MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND;
+
+ channel.notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, static_cast<Message*>(&msg));
+
+ std::shared_ptr<WorkflowInstance> instance = workflow_instance_manager->get_workflow_instance(
+ msg.sender, msg.local_workflow_instance_id);
+ ASSERT_NE(instance, nullptr);
+ ASSERT_EQ(workflow_instance_manager->get_workflow_instances().size(), 1);
+
+ channel.notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, static_cast<Message*>(&msg));
+
+ ASSERT_EQ(workflow_instance_manager->get_workflow_instances().size(), 1);
+}
+
+TEST_F(WorkflowInstanceManagerTest, ProperWorkflowTypeRequestedForInstanceCreation_p) {
+ workflow_prototype_store->last_requested_workflow_type = MMI_STANDARD_WORKFLOW_NONE;
+
+ ClientMessageWorkflowInstanceCreate msg;
+ msg.sender = std::string{"client-1"};
+ msg.local_workflow_instance_id = 0;
+ msg.workflow_type = MMI_STANDARD_WORKFLOW_VOICE_TOUCH;
+
+ channel.notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, static_cast<Message*>(&msg));
+
+ std::shared_ptr<WorkflowInstance> instance = workflow_instance_manager->get_workflow_instance(
+ msg.sender, msg.local_workflow_instance_id);
+ ASSERT_NE(instance, nullptr);
+
+ ASSERT_EQ(workflow_prototype_store->last_requested_workflow_type, MMI_STANDARD_WORKFLOW_VOICE_TOUCH);
+}
+
+TEST_F(WorkflowInstanceManagerTest, AllWorkflowInstanceDeletedOnDeinitialize_p) {
+ ClientMessageWorkflowInstanceCreate msg;
+ msg.sender = std::string{"client-1"};
+ msg.local_workflow_instance_id = 0;
+ msg.workflow_type = MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND;
+
+ channel.notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, static_cast<Message*>(&msg));
+
+ ASSERT_EQ(workflow_instance_manager->get_workflow_instances().size(), 1);
+
+ workflow_instance_manager->deinitialize();
+ ASSERT_EQ(workflow_instance_manager->get_workflow_instances().size(), 0);
+}
+
+TEST_F(WorkflowInstanceManagerTest, NodeInstanceCreationRequestedForWorkflowInstanceCreation_p) {
+ ASSERT_EQ(node_instance_manager->create_requests.size(), 0);
+
+ auto prototype = std::make_shared<WorkflowPrototype>();
+ prototype->set_type(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND);
+
+ /* Add 2 nodes to the workflow prototype */
+ prototype->add_node_info(mmi::NodeInfo{
+ "MIC", MMI_STANDARD_NODE_TYPE_SOURCE, MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT});
+ prototype->add_node_info(mmi::NodeInfo{
+ "ASR", MMI_STANDARD_NODE_TYPE_PROCESSOR, MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR});
+ workflow_prototype_store->add_workflow_prototype(prototype);
+
+ ClientMessageWorkflowInstanceCreate msg;
+ msg.sender = std::string{"client-1"};
+ msg.local_workflow_instance_id = 0;
+ msg.workflow_type = MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND;
+
+ channel.notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, static_cast<Message*>(&msg));
+
+ ASSERT_EQ(node_instance_manager->create_requests.size(), 2);
+}
+
+TEST_F(WorkflowInstanceManagerTest, NodeInstanceDestroyRequestedOnWorkflowDestruction_p) {
+ auto prototype = std::make_shared<WorkflowPrototype>();
+ prototype->set_type(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND);
+
+ /* Add 2 nodes to the workflow prototype */
+ prototype->add_node_info(mmi::NodeInfo{
+ "MIC", MMI_STANDARD_NODE_TYPE_SOURCE, MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT});
+ prototype->add_node_info(mmi::NodeInfo{
+ "ASR", MMI_STANDARD_NODE_TYPE_PROCESSOR, MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR});
+ workflow_prototype_store->add_workflow_prototype(prototype);
+
+ ClientMessageWorkflowInstanceCreate create_msg;
+ create_msg.sender = std::string{"client-1"};
+ create_msg.local_workflow_instance_id = 0;
+ create_msg.workflow_type = MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND;
+
+ channel.notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, static_cast<Message*>(&create_msg));
+
+ ASSERT_EQ(node_instance_manager->destroy_requests, 0);
+
+ ClientMessageWorkflowInstanceDestroy destroy_msg;
+ destroy_msg.sender = std::string{"client-1"};
+ destroy_msg.local_workflow_instance_id = 0;
+
+ channel.notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, static_cast<Message*>(&destroy_msg));
+ ASSERT_EQ(node_instance_manager->destroy_requests, 2);
+}
+
+TEST_F(WorkflowInstanceManagerTest, NodeInstanceDestroyRequestedOnClientDisconnection_p) {
+ auto prototype = std::make_shared<WorkflowPrototype>();
+ prototype->set_type(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND);
+
+ /* Add 2 nodes to the workflow prototype */
+ prototype->add_node_info(mmi::NodeInfo{
+ "MIC", MMI_STANDARD_NODE_TYPE_SOURCE, MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT});
+ prototype->add_node_info(mmi::NodeInfo{
+ "ASR", MMI_STANDARD_NODE_TYPE_PROCESSOR, MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR});
+ workflow_prototype_store->add_workflow_prototype(prototype);
+
+ ClientMessageWorkflowInstanceCreate create_msg;
+ create_msg.sender = std::string{"client-1"};
+ create_msg.local_workflow_instance_id = 0;
+ create_msg.workflow_type = MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND;
+
+ channel.notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, static_cast<Message*>(&create_msg));
+
+ ASSERT_EQ(node_instance_manager->destroy_requests, 0);
+
+ channel.notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::DISCONNECTED, std::string{"client-1"});
+
+ ASSERT_EQ(node_instance_manager->destroy_requests, 2);
+}
+
+TEST_F(WorkflowInstanceManagerTest, LinkCreatedIfLinkInfoIsProvided_p) {
+ auto prototype = std::make_shared<WorkflowPrototype>();
+ prototype->set_type(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND);
+
+ /* Add 2 nodes to the workflow prototype */
+ prototype->add_node_info(mmi::NodeInfo{
+ "MIC", MMI_STANDARD_NODE_TYPE_SOURCE, MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT});
+ prototype->add_node_info(mmi::NodeInfo{
+ "ASR", MMI_STANDARD_NODE_TYPE_PROCESSOR, MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR});
+ prototype->add_link_info(mmi::LinkInfo{
+ "MIC", "AUDIO", "ASR", "AUDIO"});
+ workflow_prototype_store->add_workflow_prototype(prototype);
+
+ ClientMessageWorkflowInstanceCreate create_msg;
+ create_msg.sender = std::string{"client-1"};
+ create_msg.local_workflow_instance_id = 0;
+ create_msg.workflow_type = MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND;
+
+ channel.notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, static_cast<Message*>(&create_msg));
+
+ ASSERT_NE(node_instance_manager->valid_link_requests, 0);
+}
+
+TEST_F(WorkflowInstanceManagerTest, LinkNotCreatedIfLinkInfoIsNotProvided_n) {
+ auto prototype = std::make_shared<WorkflowPrototype>();
+ prototype->set_type(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND);
+
+ /* Add 2 nodes to the workflow prototype */
+ prototype->add_node_info(mmi::NodeInfo{
+ "MIC", MMI_STANDARD_NODE_TYPE_SOURCE, MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT});
+ prototype->add_node_info(mmi::NodeInfo{
+ "ASR", MMI_STANDARD_NODE_TYPE_PROCESSOR, MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR});
+ workflow_prototype_store->add_workflow_prototype(prototype);
+
+ ClientMessageWorkflowInstanceCreate create_msg;
+ create_msg.sender = std::string{"client-1"};
+ create_msg.local_workflow_instance_id = 0;
+ create_msg.workflow_type = MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND;
+
+ channel.notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, static_cast<Message*>(&create_msg));
+
+ ASSERT_EQ(node_instance_manager->valid_link_requests, 0);
+}
+
+TEST_F(WorkflowInstanceManagerTest, LinkNotCreatedIfPortNameIsInvalid_n) {
+ auto prototype = std::make_shared<WorkflowPrototype>();
+ prototype->set_type(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND);
+
+ /* Add 2 nodes to the workflow prototype */
+ prototype->add_node_info(mmi::NodeInfo{
+ "MIC", MMI_STANDARD_NODE_TYPE_SOURCE, MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT});
+ prototype->add_node_info(mmi::NodeInfo{
+ "ASR", MMI_STANDARD_NODE_TYPE_PROCESSOR, MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR});
+ prototype->add_link_info(mmi::LinkInfo{
+ "MIC", "UNKNOWN_PORT", "ASR", "AUDIO"});
+ workflow_prototype_store->add_workflow_prototype(prototype);
+
+ ClientMessageWorkflowInstanceCreate create_msg;
+ create_msg.sender = std::string{"client-1"};
+ create_msg.local_workflow_instance_id = 0;
+ create_msg.workflow_type = MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND;
+
+ channel.notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, static_cast<Message*>(&create_msg));
+
+ ASSERT_EQ(node_instance_manager->valid_link_requests, 0);
+}
+
+TEST_F(WorkflowInstanceManagerTest, LinkNotCreatedIfNodeNameIsInvalid_n) {
+ auto prototype = std::make_shared<WorkflowPrototype>();
+ prototype->set_type(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND);
+
+ /* Add 2 nodes to the workflow prototype */
+ prototype->add_node_info(mmi::NodeInfo{
+ "MIC", MMI_STANDARD_NODE_TYPE_SOURCE, MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT});
+ prototype->add_node_info(mmi::NodeInfo{
+ "ASR", MMI_STANDARD_NODE_TYPE_PROCESSOR, MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR});
+ prototype->add_link_info(mmi::LinkInfo{
+ "UNKNOWN_NODE", "AUDIO", "ASR", "AUDIO"});
+ workflow_prototype_store->add_workflow_prototype(prototype);
+
+ ClientMessageWorkflowInstanceCreate create_msg;
+ create_msg.sender = std::string{"client-1"};
+ create_msg.local_workflow_instance_id = 0;
+ create_msg.workflow_type = MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND;
+
+ channel.notify_observers(
+ COMMUNICATION_CHANNEL_EVENT_TYPE::MESSAGE_RECEIVED, static_cast<Message*>(&create_msg));
+
+ ASSERT_EQ(node_instance_manager->valid_link_requests, 0);
+}
+
+} // namespace
+
+#ifdef TEST_MAIN_REQUIRED
+int main(int argc, char** argv) {
+ std::cout << "Starting tests" << std::endl;
+ testing::InitGoogleTest(&argc, argv);
+ int ret = RUN_ALL_TESTS();
+ return ret;
+}
+#endif
--- /dev/null
+#include <iostream>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include "mmi-self-container.h"
+#include "mmi-workflow-instance.h"
+#include "mmi-workflow-prototype.h"
+#include "mmi-workflow-prototype-manager.h"
+
+using namespace mmi;
+
+extern "C" {
+/* Add wrapper functions here with __wrap_ and __real prefix
+Example :
+
+int __real_vconf_get_int(const char *in_key, int *intval);
+int __wrap_vconf_get_int(const char *in_key, int *intval)
+{
+ if (strcmp(in_key, "TestKey") == 0)
+ return 0;
+
+ return __real_vconf_get_int(in_key, intval);
+}
+*/
+}
+
+class WorkflowPrototypeStoreDummy : public IWorkflowPrototypeStore {
+public:
+ bool add_workflow_prototype(std::shared_ptr<WorkflowPrototype> prototype) override {
+ return true;
+ }
+ std::shared_ptr<WorkflowPrototype> get_workflow_prototype(mmi_standard_workflow_type_e type) override {
+ auto prototype = std::make_shared<WorkflowPrototype>();
+ prototype->set_type(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND);
+
+ /* Add 2 nodes to the workflow prototype */
+ prototype->add_node_info(mmi::NodeInfo{
+ "MIC", MMI_STANDARD_NODE_TYPE_SOURCE, MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT});
+ 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.target_node_name = "ASR";
+ attribute_assignment_info.target_attribute_name = "CANDIDATE";
+ prototype->add_attribute_assignment_info(attribute_assignment_info);
+ return prototype;
+ }
+};
+
+class NodePrototypeStoreDummy : public INodePrototypeStore {
+public:
+ virtual bool add_node_prototype(std::shared_ptr<NodePrototype> prototype) override {
+ node_prototypes.push_back(prototype);
+ return true;
+ }
+ virtual std::shared_ptr<NodePrototype> get_node_prototype(
+ mmi_standard_node_type_e type, mmi_standard_node_sub_type_e sub_type) override {
+ for (auto& prototype : node_prototypes) {
+ if (prototype->get_type() == type &&
+ prototype->get_sub_type() == sub_type) {
+ return prototype;
+ }
+ }
+ return nullptr;
+ }
+ std::vector<std::shared_ptr<NodePrototype>> node_prototypes;
+};
+
+class NodeInstanceManagerDummy : public INodeInstanceManager {
+public:
+ NodeInstanceManagerDummy() {
+ node_prototype_store = std::make_shared<NodePrototypeStoreDummy>();
+
+ auto mic_prototype = std::make_shared<NodePrototype>();
+ mic_prototype->set_type(MMI_STANDARD_NODE_TYPE_SOURCE);
+ mic_prototype->set_sub_type(MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT);
+ PortInfo mic_audio{"AUDIO", MMI_PORT_TYPE_OUT, MMI_DATA_TYPE_AUDIO, "audio data"};
+ mic_prototype->add_port_info(mic_audio);
+ node_prototype_store->add_node_prototype(mic_prototype);
+
+ auto asr_prototype = std::make_shared<NodePrototype>();
+ asr_prototype->set_type(MMI_STANDARD_NODE_TYPE_PROCESSOR);
+ asr_prototype->set_sub_type(MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR);
+ PortInfo asr_audio{"AUDIO", MMI_PORT_TYPE_IN, MMI_DATA_TYPE_AUDIO, "audio data"};
+ asr_prototype->add_port_info(asr_audio);
+ node_prototype_store->add_node_prototype(asr_prototype);
+ }
+
+ virtual std::shared_ptr<NodeInstance> 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<NodeInstance>(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);
+ node_instance->initialize();
+ }
+ return node_instance;
+ }
+ virtual bool destroy_node_instance(
+ std::shared_ptr<NodeInstance> node_instance) override {
+ return true;
+ }
+ virtual bool link_node_instances(
+ std::shared_ptr<NodeInstance> from_node_instance,
+ std::shared_ptr<NodeInstance> to_node_instance,
+ std::optional<std::string> from_port_name,
+ std::optional<std::string> to_port_name) override {
+ return true;
+ }
+ void set_plugin_module_proxy_provider(std::shared_ptr<IPluginModuleProxyProvider> provider) {
+ plugin_module_proxy_provider = provider;
+ }
+ std::shared_ptr<NodePrototypeStoreDummy> node_prototype_store;
+ std::shared_ptr<IPluginModuleProxyProvider> plugin_module_proxy_provider;
+};
+
+class PluginModuleProxyProviderDummy : public IPluginModuleProxyProvider {
+public:
+ PluginModuleProxyProviderDummy() {
+ proxy = factory.create(
+ PluginModuleInfo{mmi_plugin_module_type_e::SELF_CONTAINED, "dummy"});
+ }
+ virtual std::shared_ptr<IPluginModuleProxy> get_plugin_module_proxy(
+ const PluginModuleInfo plugin_module_info) override {
+ return proxy;
+ }
+ PluginModuleProxyFactorySelfContainerTest factory;
+ std::shared_ptr<IPluginModuleProxy> proxy;
+};
+
+class WorkflowInstanceTest : public testing::Test
+{
+public:
+ WorkflowInstanceTest() {
+ workflow_prototype_store = std::make_shared<WorkflowPrototypeStoreDummy>();
+ node_instance_manager = std::make_shared<NodeInstanceManagerDummy>();
+ plugin_module_proxy_provider = std::make_shared<PluginModuleProxyProviderDummy>();
+ }
+ virtual ~WorkflowInstanceTest() {
+ }
+ void SetUp() override {
+ workflow_instance = std::make_shared<WorkflowInstance>();
+ 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);
+ }
+ if (node_instance_manager) {
+ node_instance_manager->set_plugin_module_proxy_provider(plugin_module_proxy_provider);
+ }
+ }
+ void TearDown() override {
+ workflow_instance.reset();
+ }
+ std::shared_ptr<WorkflowInstance> workflow_instance;
+ std::shared_ptr<PluginModuleProxyProviderDummy> plugin_module_proxy_provider;
+ std::shared_ptr<WorkflowPrototypeStoreDummy> workflow_prototype_store;
+ std::shared_ptr<NodeInstanceManagerDummy> node_instance_manager;
+};
+
+TEST_F(WorkflowInstanceTest, WorkflowAttributePassedToNodeAttribute_p) {
+ ASSERT_NE(workflow_instance, nullptr);
+ workflow_instance->initialize();
+ mmi_primitive_value_h value = nullptr;
+ mmi_primitive_value_create_int(5, &value);
+ mmi_attribute_h attribute = nullptr;
+ mmi_attribute_create(value, "CANDIDATE", &attribute);
+ ASSERT_TRUE(workflow_instance->set_attribute(attribute));
+ workflow_instance->deinitialize();
+ mmi_attribute_destroy(attribute);
+ mmi_primitive_value_destroy(value);
+}
+
+#ifdef TEST_MAIN_REQUIRED
+int main(int argc, char** argv) {
+ std::cout << "Starting tests" << std::endl;
+ testing::InitGoogleTest(&argc, argv);
+ int ret = RUN_ALL_TESTS();
+ return ret;
+}
+#endif
--- /dev/null
+#include <iostream>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include "mmi-workflow-prototype.h"
+
+using namespace mmi;
+
+extern "C" {
+ /* Add wrapper functions here with __wrap_ and __real prefix
+ Example :
+
+ int __real_vconf_get_int(const char *in_key, int *intval);
+ int __wrap_vconf_get_int(const char *in_key, int *intval)
+ {
+ if (strcmp(in_key, "TestKey") == 0)
+ return 0;
+
+ return __real_vconf_get_int(in_key, intval);
+ }
+ */
+}
+
+namespace {
+
+class WorkflowPrototypeTest : public testing::Test {
+public:
+ WorkflowPrototypeTest() {
+ }
+ virtual ~WorkflowPrototypeTest() {
+ }
+ void SetUp() override {
+ prototype = std::make_shared<WorkflowPrototype>();
+ ASSERT_TRUE(prototype != nullptr);
+ }
+ void TearDown() override {
+ }
+
+ std::shared_ptr<WorkflowPrototype> prototype;
+};
+
+TEST_F(WorkflowPrototypeTest, WorkflowPrototypeValidationSucceeds_p) {
+ prototype->set_plugin_module_info(
+ PluginModuleInfo{mmi_plugin_module_type_e::SHARED_LIBRARY, "test.so"});
+
+ prototype->set_type(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND);
+ ASSERT_TRUE(prototype->is_valid());
+}
+
+TEST_F(WorkflowPrototypeTest, WorkflowPrototypeValidationFailsWithNoType_n) {
+ prototype->set_plugin_module_info(
+ PluginModuleInfo{mmi_plugin_module_type_e::SHARED_LIBRARY, "test.so"});
+
+ /* No type provided */
+
+ ASSERT_FALSE(prototype->is_valid());
+}
+
+} // namespace
+
+#ifdef TEST_MAIN_REQUIRED
+int main(int argc, char** argv) {
+ std::cout << "Starting tests" << std::endl;
+ testing::InitGoogleTest(&argc, argv);
+ int ret = RUN_ALL_TESTS();
+ return ret;
+}
+#endif
--- /dev/null
+/*
+ * 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 <gmock/gmock.h>
+
+#include <mmi-error.h>
+#include <mmi-attribute.h>
+
+
+class MMIAttributeTest : public ::testing::Test {
+public:
+ void SetUp(void) override {
+ mmiAttribute = nullptr;
+ cloned_attribute = nullptr;
+ primitiveValue = nullptr;
+ }
+
+ void TearDown(void) override {
+ if (nullptr != mmiAttribute) {
+ mmi_attribute_destroy(mmiAttribute);
+ mmiAttribute = nullptr;
+ }
+
+ if (nullptr != cloned_attribute) {
+ mmi_attribute_destroy(cloned_attribute);
+ cloned_attribute = nullptr;
+ }
+
+ if (nullptr != primitiveValue) {
+ mmi_primitive_value_destroy(primitiveValue);
+ primitiveValue = nullptr;
+ }
+ }
+
+ mmi_attribute_h mmiAttribute = nullptr;
+ mmi_attribute_h cloned_attribute = nullptr;
+ mmi_primitive_value_h primitiveValue = nullptr;
+};
+
+TEST_F(MMIAttributeTest, MMIAttributeCreate_p) {
+ constexpr int sourceInt = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceInt, &primitiveValue), MMI_ERROR_NONE);
+ ASSERT_NE(primitiveValue, nullptr);
+
+ constexpr const char *name = "Attribute";
+ ASSERT_EQ(mmi_attribute_create(primitiveValue, name, &mmiAttribute), MMI_ERROR_NONE);
+ ASSERT_NE(mmiAttribute, nullptr);
+}
+
+TEST_F(MMIAttributeTest, MMIAttributeCreate_n1) {
+ constexpr int sourceInt = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceInt, &primitiveValue), MMI_ERROR_NONE);
+ ASSERT_NE(primitiveValue, nullptr);
+
+ constexpr const char *name = "Attribute";
+ EXPECT_EQ(mmi_attribute_create(nullptr, name, &mmiAttribute), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_attribute_create(primitiveValue, nullptr, &mmiAttribute), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_attribute_create(primitiveValue, name, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIAttributeTest, MMIAttributeCreate_n2) {
+ constexpr int sourceInt = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceInt, &primitiveValue), MMI_ERROR_NONE);
+ ASSERT_NE(primitiveValue, nullptr);
+
+ EXPECT_EQ(mmi_attribute_create(primitiveValue, "", &mmiAttribute), 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_attribute_create(primitiveValue, name, &mmiAttribute), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIAttributeTest, MMIAttributeGetName_p) {
+ constexpr int sourceInt = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceInt, &primitiveValue), MMI_ERROR_NONE);
+ ASSERT_NE(primitiveValue, nullptr);
+
+ constexpr const char *name = "Attribute";
+ ASSERT_EQ(mmi_attribute_create(primitiveValue, name, &mmiAttribute), MMI_ERROR_NONE);
+ ASSERT_NE(mmiAttribute, nullptr);
+
+ char *temp_name = nullptr;
+ ASSERT_EQ(mmi_attribute_get_name(mmiAttribute, &temp_name), MMI_ERROR_NONE);
+ ASSERT_NE(temp_name, nullptr);
+ EXPECT_STREQ(temp_name, name);
+ free(temp_name);
+}
+
+TEST_F(MMIAttributeTest, MMIAttributeGetName_n) {
+ constexpr int sourceInt = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceInt, &primitiveValue), MMI_ERROR_NONE);
+ ASSERT_NE(primitiveValue, nullptr);
+
+ constexpr const char *name = "Attribute";
+ ASSERT_EQ(mmi_attribute_create(primitiveValue, name, &mmiAttribute), MMI_ERROR_NONE);
+ ASSERT_NE(mmiAttribute, nullptr);
+
+ char *temp_name = nullptr;
+ EXPECT_EQ(mmi_attribute_get_name(nullptr, &temp_name), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_attribute_get_name(mmiAttribute, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIAttributeTest, MMIAttributeGetValue_p) {
+ constexpr int sourceInt = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceInt, &primitiveValue), MMI_ERROR_NONE);
+ ASSERT_NE(primitiveValue, nullptr);
+
+ constexpr const char *name = "Attribute";
+ ASSERT_EQ(mmi_attribute_create(primitiveValue, name, &mmiAttribute), MMI_ERROR_NONE);
+ ASSERT_NE(mmiAttribute, nullptr);
+
+ mmi_primitive_value_h temp_value = nullptr;
+ ASSERT_EQ(mmi_attribute_get_value(mmiAttribute, &temp_value), MMI_ERROR_NONE);
+ ASSERT_NE(temp_value, nullptr);
+
+ mmi_primitive_value_type_e type = MMI_PRIMITIVE_VALUE_TYPE_ARRAY;
+ EXPECT_EQ(mmi_primitive_value_get_type(temp_value, &type), MMI_ERROR_NONE);
+ EXPECT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_INT);
+
+ int value = -1;
+ EXPECT_EQ(mmi_primitive_value_get_int(temp_value, &value), MMI_ERROR_NONE);
+ EXPECT_EQ(value, sourceInt);
+
+ EXPECT_EQ(mmi_primitive_value_destroy(temp_value), MMI_ERROR_NONE);
+}
+
+TEST_F(MMIAttributeTest, MMIAttributeGetValue_n) {
+ constexpr int sourceInt = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceInt, &primitiveValue), MMI_ERROR_NONE);
+ ASSERT_NE(primitiveValue, nullptr);
+
+ constexpr const char *name = "Attribute";
+ ASSERT_EQ(mmi_attribute_create(primitiveValue, name, &mmiAttribute), MMI_ERROR_NONE);
+ ASSERT_NE(mmiAttribute, nullptr);
+
+ mmi_primitive_value_h temp_value = nullptr;
+ EXPECT_EQ(mmi_attribute_get_value(nullptr, &temp_value), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_attribute_get_value(mmiAttribute, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIAttributeTest, MMIAttributeClone_p) {
+ constexpr int sourceInt = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceInt, &primitiveValue), MMI_ERROR_NONE);
+ ASSERT_NE(primitiveValue, nullptr);
+
+ constexpr const char *name = "Attribute";
+ ASSERT_EQ(mmi_attribute_create(primitiveValue, name, &mmiAttribute), MMI_ERROR_NONE);
+ ASSERT_NE(mmiAttribute, nullptr);
+
+ ASSERT_EQ(mmi_attribute_clone(mmiAttribute, &cloned_attribute), MMI_ERROR_NONE);
+ ASSERT_NE(cloned_attribute, nullptr);
+
+ char *temp_name = nullptr;
+ ASSERT_EQ(mmi_attribute_get_name(cloned_attribute, &temp_name), MMI_ERROR_NONE);
+ ASSERT_NE(temp_name, nullptr);
+ EXPECT_STREQ(temp_name, name);
+ free(temp_name);
+
+ mmi_primitive_value_h temp_value = nullptr;
+ ASSERT_EQ(mmi_attribute_get_value(mmiAttribute, &temp_value), MMI_ERROR_NONE);
+ ASSERT_NE(temp_value, nullptr);
+
+ mmi_primitive_value_type_e type = MMI_PRIMITIVE_VALUE_TYPE_ARRAY;
+ EXPECT_EQ(mmi_primitive_value_get_type(temp_value, &type), MMI_ERROR_NONE);
+ EXPECT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_INT);
+
+ int value = -1;
+ EXPECT_EQ(mmi_primitive_value_get_int(temp_value, &value), MMI_ERROR_NONE);
+ EXPECT_EQ(value, sourceInt);
+
+ EXPECT_EQ(mmi_primitive_value_destroy(temp_value), MMI_ERROR_NONE);
+}
+
+TEST_F(MMIAttributeTest, MMIAttributeClone_n) {
+ constexpr int sourceInt = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceInt, &primitiveValue), MMI_ERROR_NONE);
+ ASSERT_NE(primitiveValue, nullptr);
+
+ constexpr const char *name = "Attribute";
+ ASSERT_EQ(mmi_attribute_create(primitiveValue, name, &mmiAttribute), MMI_ERROR_NONE);
+ ASSERT_NE(mmiAttribute, nullptr);
+
+ EXPECT_EQ(mmi_attribute_clone(nullptr, &cloned_attribute), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_attribute_clone(mmiAttribute, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIAttributeTest, MMIDataDestroy_p1) {
+ constexpr int sourceInt = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceInt, &primitiveValue), MMI_ERROR_NONE);
+ ASSERT_NE(primitiveValue, nullptr);
+
+ constexpr const char *name = "Attribute";
+ ASSERT_EQ(mmi_attribute_create(primitiveValue, name, &mmiAttribute), MMI_ERROR_NONE);
+ ASSERT_NE(mmiAttribute, nullptr);
+
+ ASSERT_EQ(mmi_attribute_destroy(mmiAttribute), MMI_ERROR_NONE);
+ mmiAttribute = nullptr;
+}
+
+TEST_F(MMIAttributeTest, MMIDataDestroy_n) {
+ ASSERT_EQ(mmi_attribute_destroy(nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIAttributeTest, MMIAttributeBytesConversion_p) {
+ constexpr int sourceInt = 5;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceInt, &primitiveValue), MMI_ERROR_NONE);
+ ASSERT_NE(primitiveValue, nullptr);
+
+ constexpr const char *name = "Attribute";
+ ASSERT_EQ(mmi_attribute_create(primitiveValue, name, &mmiAttribute), MMI_ERROR_NONE);
+ ASSERT_NE(mmiAttribute, nullptr);
+
+ unsigned char *bytes = nullptr;
+ size_t size = 0;
+ ASSERT_EQ(mmi_attribute_to_bytes(mmiAttribute, &bytes, &size), MMI_ERROR_NONE);
+ ASSERT_NE(bytes, nullptr);
+
+ ASSERT_EQ(mmi_attribute_destroy(mmiAttribute), MMI_ERROR_NONE);
+ mmiAttribute = nullptr;
+
+ mmi_attribute_h restoredAttribute = nullptr;
+ ASSERT_EQ(mmi_attribute_from_bytes(bytes, size, &restoredAttribute), MMI_ERROR_NONE);
+ ASSERT_NE(restoredAttribute, nullptr);
+
+ free(bytes);
+
+ char *temp_name = nullptr;
+ ASSERT_EQ(mmi_attribute_get_name(restoredAttribute, &temp_name), MMI_ERROR_NONE);
+ ASSERT_NE(temp_name, nullptr);
+ EXPECT_STREQ(temp_name, name);
+ free(temp_name);
+
+ mmi_primitive_value_h temp_value = nullptr;
+ ASSERT_EQ(mmi_attribute_get_value(restoredAttribute, &temp_value), MMI_ERROR_NONE);
+ ASSERT_NE(temp_value, nullptr);
+
+ mmi_primitive_value_type_e type = MMI_PRIMITIVE_VALUE_TYPE_BOOL;
+ EXPECT_EQ(mmi_primitive_value_get_type(temp_value, &type), MMI_ERROR_NONE);
+ EXPECT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_INT);
+
+ int value = -1;
+ EXPECT_EQ(mmi_primitive_value_get_int(temp_value, &value), MMI_ERROR_NONE);
+ EXPECT_EQ(value, sourceInt);
+
+ mmi_primitive_value_destroy(temp_value);
+ temp_value = nullptr;
+
+ mmi_attribute_destroy(restoredAttribute);
+ restoredAttribute = nullptr;
+}
--- /dev/null
+mmi_tests_srcs = [
+ 'mmi-tests.cpp',
+ 'mmi-main-test.cpp',
+ 'mmi-ipc-test.cpp',
+ 'mmi-data-test.cpp',
+ 'attribute/mmi-attribute-test.cpp',
+ 'primitive-value/mmi-primitive-value-test.cpp',
+ 'workflow/mmi-workflow-test.cpp',
+ ]
+
+gmock_dep = dependency('gmock', method : 'pkg-config')
+ecore_dep = dependency('ecore', method : 'pkg-config')
+
+tc = executable(
+ 'mmi-tests',
+ mmi_tests_srcs,
+ dependencies : [mmi_declared_dep, gmock_dep, ecore_dep],
+ install_dir : mmi_prefix_bindir,
+ install : true
+ )
+
+test('mmi-tests', tc, args : ['--gtest_output=xml:./mmi-tests.xml'])
--- /dev/null
+/*
+ * 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-tests.h"
+#include <mmi-error.h>
+#include <mmi-data.h>
+
+
+class MMIDataTest : public ::testing::Test {
+public:
+ void SetUp(void) override {
+ mmiData = nullptr;
+ for (size_t i = 0; i < MAX_ARRAY_LENGTH; i++) {
+ arrayElement[i] = nullptr;
+ }
+ }
+
+ void TearDown(void) override {
+ if (nullptr != mmiData) {
+ mmi_data_destroy(mmiData);
+ mmiData = nullptr;
+ }
+
+ for (size_t i = 0; i < MAX_ARRAY_LENGTH; i++) {
+ if (nullptr != arrayElement[i]) {
+ mmi_data_destroy(arrayElement[i]);
+ arrayElement[i] = nullptr;
+ }
+ }
+ }
+
+ static constexpr size_t MAX_ARRAY_LENGTH = 5;
+
+ mmi_data_h mmiData = nullptr;
+ mmi_data_h arrayElement[MAX_ARRAY_LENGTH] = {nullptr, };
+};
+
+TEST_F(MMIDataTest, MMIDataCreateDataByInt_p) {
+ constexpr int sourceValue = 0;
+ ASSERT_EQ(mmi_data_create_int(sourceValue, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+}
+
+TEST_F(MMIDataTest, MMIDataCreateDataByInt_n) {
+ constexpr int sourceValue = 0;
+ EXPECT_EQ(mmi_data_create_int(sourceValue, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataCreateDataByText_p) {
+ constexpr const char *sourceValue = "Hello";
+ ASSERT_EQ(mmi_data_create_text(sourceValue, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+}
+
+TEST_F(MMIDataTest, MMIDataCreateDataByText_n) {
+ constexpr const char *sourceValue = "Hello";
+ EXPECT_EQ(mmi_data_create_text(sourceValue, nullptr), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_data_create_text(nullptr, &mmiData), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataCreateDataByAudio_p) {
+ constexpr size_t DATA_LENGTH = 10;
+ constexpr char sourceValue[DATA_LENGTH] = {1, };
+ ASSERT_EQ(mmi_data_create_audio(sourceValue, DATA_LENGTH, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+}
+
+TEST_F(MMIDataTest, MMIDataCreateDataByAudio_n) {
+ constexpr size_t DATA_LENGTH = 10;
+ constexpr char sourceValue[DATA_LENGTH] = {1, };
+ EXPECT_EQ(mmi_data_create_audio(nullptr, DATA_LENGTH, &mmiData), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_data_create_audio(sourceValue, 0, &mmiData), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_data_create_audio(sourceValue, DATA_LENGTH, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataCreateDataByArray_p) {
+ EXPECT_EQ(mmi_data_create_array(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+}
+
+TEST_F(MMIDataTest, MMIDataCreateDataByArray_n) {
+ EXPECT_EQ(mmi_data_create_array(nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataAddElementIntoArray_p) {
+ ASSERT_EQ(mmi_data_create_array(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ constexpr int COUNT_ELEMENTS = 2;
+ constexpr int source[COUNT_ELEMENTS] = {1, 2};
+ for (size_t i = 0; i < COUNT_ELEMENTS; i++) {
+ ASSERT_EQ(mmi_data_create_int(source[i], &arrayElement[i]), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_data_add_array_element(mmiData, arrayElement[i]), MMI_ERROR_NONE);
+ arrayElement[i] = nullptr;
+ }
+}
+
+TEST_F(MMIDataTest, MMIDataAddElementIntoArray_n1) {
+ ASSERT_EQ(mmi_data_create_array(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ constexpr int sourceInt = 1;
+ constexpr const char *sourceText = "Hello";
+ ASSERT_EQ(mmi_data_create_int(sourceInt, &arrayElement[0]), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_data_create_text(sourceText, &arrayElement[1]), MMI_ERROR_NONE);
+
+ EXPECT_EQ(mmi_data_add_array_element(nullptr, arrayElement[0]), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_data_add_array_element(mmiData, nullptr), MMI_ERROR_INVALID_PARAMETER);
+
+ ASSERT_EQ(mmi_data_add_array_element(mmiData, arrayElement[0]), MMI_ERROR_NONE);
+ arrayElement[0] = nullptr;
+ EXPECT_EQ(mmi_data_add_array_element(mmiData, arrayElement[1]), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataAddElementIntoArray_n2) {
+ constexpr int sourceInt = 1;
+ EXPECT_EQ(mmi_data_create_int(sourceInt, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ ASSERT_EQ(mmi_data_create_int(sourceInt, &arrayElement[0]), MMI_ERROR_NONE);
+ ASSERT_NE(arrayElement, nullptr);
+
+ EXPECT_EQ(mmi_data_add_array_element(mmiData, arrayElement[0]), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataCreateDataByStruct_p) {
+ EXPECT_EQ(mmi_data_create_struct(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+}
+
+TEST_F(MMIDataTest, MMIDataCreateDataByStruct_n) {
+ EXPECT_EQ(mmi_data_create_struct(nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataAddElementIntoStruct_p) {
+ ASSERT_EQ(mmi_data_create_struct(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ constexpr int sourceInt = 1;
+ constexpr const char *sourceText = "Hello";
+ ASSERT_EQ(mmi_data_create_int(sourceInt, &arrayElement[0]), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_data_create_text(sourceText, &arrayElement[1]), MMI_ERROR_NONE);
+
+ constexpr int COUNT_ELEMENTS = 2;
+ constexpr const char *name[COUNT_ELEMENTS] = {"Element1", "Element2"};
+ for (size_t i = 0; i < COUNT_ELEMENTS; i++) {
+ ASSERT_EQ(mmi_data_set_struct_element(mmiData, name[i], arrayElement[i]), MMI_ERROR_NONE);
+ arrayElement[i] = nullptr;
+ }
+}
+
+TEST_F(MMIDataTest, MMIDataAddElementIntoStruct_n1) {
+ ASSERT_EQ(mmi_data_create_array(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ constexpr int sourceInt = 1;
+ ASSERT_EQ(mmi_data_create_int(sourceInt, &arrayElement[0]), MMI_ERROR_NONE);
+
+ constexpr const char *name = "Element";
+ ASSERT_EQ(mmi_data_set_struct_element(nullptr, name, arrayElement[0]), MMI_ERROR_INVALID_PARAMETER);
+ ASSERT_EQ(mmi_data_set_struct_element(mmiData, nullptr, arrayElement[0]), MMI_ERROR_INVALID_PARAMETER);
+ ASSERT_EQ(mmi_data_set_struct_element(mmiData, name, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataGetElementFromStruct_p) {
+ ASSERT_EQ(mmi_data_create_struct(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ constexpr int sourceInt = 1;
+ constexpr const char *sourceText = "Hello";
+ ASSERT_EQ(mmi_data_create_int(sourceInt, &arrayElement[0]), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_data_create_text(sourceText, &arrayElement[1]), MMI_ERROR_NONE);
+
+ constexpr int COUNT_ELEMENTS = 2;
+ constexpr const char *name[COUNT_ELEMENTS] = {"Element1", "Element2"};
+ for (size_t i = 0; i < COUNT_ELEMENTS; i++) {
+ ASSERT_EQ(mmi_data_set_struct_element(mmiData, name[i], arrayElement[i]), MMI_ERROR_NONE);
+ arrayElement[i] = nullptr;
+ }
+
+ size_t count = 0;
+ ASSERT_EQ(mmi_data_get_struct_count(mmiData, &count), MMI_ERROR_NONE);
+ ASSERT_EQ(count, COUNT_ELEMENTS);
+
+ const char *element_name = nullptr;
+ mmi_data_h element_value = nullptr;
+
+ EXPECT_EQ(mmi_data_get_struct_element_name(mmiData, 0, &element_name), MMI_ERROR_NONE);
+ EXPECT_STREQ(element_name, "Element1");
+ EXPECT_EQ(mmi_data_get_struct_element_value(mmiData, 0, &element_value), MMI_ERROR_NONE);
+ int intValue = 0;
+ EXPECT_EQ(mmi_data_get_int(element_value, &intValue), MMI_ERROR_NONE);
+ EXPECT_EQ(intValue, sourceInt);
+
+ EXPECT_EQ(mmi_data_get_struct_element_name(mmiData, 1, &element_name), MMI_ERROR_NONE);
+ EXPECT_STREQ(element_name, "Element2");
+ EXPECT_EQ(mmi_data_get_struct_element_value(mmiData, 1, &element_value), MMI_ERROR_NONE);
+ const char *textValue = nullptr;
+ EXPECT_EQ(mmi_data_get_text(element_value, &textValue), MMI_ERROR_NONE);
+ EXPECT_STREQ(textValue, sourceText);
+}
+
+TEST_F(MMIDataTest, MMIDataGetType_p) {
+ mmi_data_h tempValue = nullptr;
+ mmi_data_type_e type = MMI_DATA_TYPE_ARRAY;
+
+ EXPECT_EQ(mmi_data_create_int(0, &tempValue), MMI_ERROR_NONE);
+ EXPECT_EQ(mmi_data_get_type(tempValue, &type), MMI_ERROR_NONE);
+ EXPECT_EQ(type, MMI_DATA_TYPE_INTEGER);
+ EXPECT_EQ(mmi_data_destroy(tempValue), MMI_ERROR_NONE);
+ tempValue = nullptr;
+
+ EXPECT_EQ(mmi_data_create_text("Hello", &tempValue), MMI_ERROR_NONE);
+ EXPECT_EQ(mmi_data_get_type(tempValue, &type), MMI_ERROR_NONE);
+ EXPECT_EQ(type, MMI_DATA_TYPE_TEXT);
+ 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);
+ EXPECT_EQ(mmi_data_get_type(tempValue, &type), MMI_ERROR_NONE);
+ EXPECT_EQ(type, MMI_DATA_TYPE_AUDIO);
+ EXPECT_EQ(mmi_data_destroy(tempValue), MMI_ERROR_NONE);
+ tempValue = nullptr;
+
+ EXPECT_EQ(mmi_data_create_array(&tempValue), MMI_ERROR_NONE);
+ EXPECT_EQ(mmi_data_get_type(tempValue, &type), MMI_ERROR_NONE);
+ EXPECT_EQ(type, MMI_DATA_TYPE_ARRAY);
+ EXPECT_EQ(mmi_data_destroy(tempValue), MMI_ERROR_NONE);
+ tempValue = nullptr;
+
+ EXPECT_EQ(mmi_data_create_struct(&tempValue), MMI_ERROR_NONE);
+ EXPECT_EQ(mmi_data_get_type(tempValue, &type), MMI_ERROR_NONE);
+ EXPECT_EQ(type, MMI_DATA_TYPE_STRUCT);
+ EXPECT_EQ(mmi_data_destroy(tempValue), MMI_ERROR_NONE);
+ tempValue = nullptr;
+}
+
+TEST_F(MMIDataTest, MMIDataGetType_n) {
+ ASSERT_EQ(mmi_data_create_array(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ mmi_data_type_e type = MMI_DATA_TYPE_ARRAY;
+ EXPECT_EQ(mmi_data_get_type(nullptr, &type), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_data_get_type(mmiData, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataGetIntValue_p) {
+ constexpr int sourceInt = 1;
+ ASSERT_EQ(mmi_data_create_int(sourceInt, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ int targetValue = -1;
+ EXPECT_EQ(mmi_data_get_int(mmiData, &targetValue), MMI_ERROR_NONE);
+ EXPECT_EQ(targetValue, sourceInt);
+}
+
+TEST_F(MMIDataTest, MMIDataGetIntValue_n1) {
+ constexpr int sourceInt = 1;
+ ASSERT_EQ(mmi_data_create_int(sourceInt, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ int targetValue = -1;
+ EXPECT_EQ(mmi_data_get_int(nullptr, &targetValue), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_data_get_int(mmiData, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataGetIntValue_n2) {
+ constexpr const char *sourceText = "Hello";
+ ASSERT_EQ(mmi_data_create_text(sourceText, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ int targetValue = -1;
+ EXPECT_EQ(mmi_data_get_int(mmiData, &targetValue), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataGetTextValue_p) {
+ constexpr const char *sourceText = "Hello";
+ ASSERT_EQ(mmi_data_create_text(sourceText, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ const char *textInData = nullptr;
+ EXPECT_EQ(mmi_data_get_text(mmiData, &textInData), MMI_ERROR_NONE);
+ EXPECT_STREQ(textInData, sourceText);
+}
+
+TEST_F(MMIDataTest, MMIDataGetTextValue_n1) {
+ constexpr const char *sourceText = "Hello";
+ ASSERT_EQ(mmi_data_create_text(sourceText, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ const char *textInData = nullptr;
+ EXPECT_EQ(mmi_data_get_text(nullptr, &textInData), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_data_get_text(mmiData, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataGetTextValue_n2) {
+ constexpr int sourceInt = 1;
+ ASSERT_EQ(mmi_data_create_int(sourceInt, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ const char *textInData = nullptr;
+ EXPECT_EQ(mmi_data_get_text(mmiData, &textInData), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataGetArrayCount_p) {
+ ASSERT_EQ(mmi_data_create_array(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ constexpr int COUNT_ELEMENTS = 2;
+ constexpr int source[COUNT_ELEMENTS] = {1, 2};
+ for (size_t i = 0; i < COUNT_ELEMENTS; i++) {
+ size_t count = 10;
+ EXPECT_EQ(mmi_data_get_array_count(mmiData, &count), MMI_ERROR_NONE);
+ EXPECT_EQ(count, i);
+
+ ASSERT_EQ(mmi_data_create_int(source[i], &arrayElement[i]), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_data_add_array_element(mmiData, arrayElement[i]), MMI_ERROR_NONE);
+ arrayElement[i] = nullptr;
+ }
+
+ size_t count = 10;
+ EXPECT_EQ(mmi_data_get_array_count(mmiData, &count), MMI_ERROR_NONE);
+ EXPECT_EQ(count, COUNT_ELEMENTS);
+}
+
+TEST_F(MMIDataTest, MMIDataGetArrayCount_n1) {
+ ASSERT_EQ(mmi_data_create_array(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ size_t count = 0;
+ EXPECT_EQ(mmi_data_get_array_count(nullptr, &count), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_data_get_array_count(mmiData, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataGetArrayCount_n2) {
+ int sourceValue = 0;
+ ASSERT_EQ(mmi_data_create_int(sourceValue, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ size_t count = 0;
+ EXPECT_EQ(mmi_data_get_array_count(mmiData, &count), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataGetArrayElement_p) {
+ ASSERT_EQ(mmi_data_create_array(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ constexpr int COUNT_ELEMENTS = 2;
+ constexpr int source[COUNT_ELEMENTS] = {1, 2};
+ for (size_t i = 0; i < COUNT_ELEMENTS; i++) {
+ ASSERT_EQ(mmi_data_create_int(source[i], &arrayElement[i]), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_data_add_array_element(mmiData, arrayElement[i]), MMI_ERROR_NONE);
+ arrayElement[i] = nullptr;
+ }
+
+ size_t count = 0;
+ EXPECT_EQ(mmi_data_get_array_count(mmiData, &count), MMI_ERROR_NONE);
+ EXPECT_EQ(count, COUNT_ELEMENTS);
+
+ for (size_t i = 0; i < count; i++) {
+ mmi_data_h element = nullptr;
+ EXPECT_EQ(mmi_data_get_array_element(mmiData, i, &element), MMI_ERROR_NONE);
+
+ mmi_data_type_e type = MMI_DATA_TYPE_ANY;
+ EXPECT_EQ(mmi_data_get_type(element, &type), MMI_ERROR_NONE);
+ EXPECT_EQ(type, MMI_DATA_TYPE_INTEGER);
+
+ int data = 0;
+ EXPECT_EQ(mmi_data_get_int(element, &data), MMI_ERROR_NONE);
+ EXPECT_EQ(data, source[i]);
+ }
+}
+
+TEST_F(MMIDataTest, MMIDataGetArrayElement_n1) {
+ ASSERT_EQ(mmi_data_create_array(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ mmi_data_h element = nullptr;
+ EXPECT_EQ(mmi_data_get_array_element(mmiData, 0, &element), MMI_ERROR_INVALID_PARAMETER);
+
+ constexpr int COUNT_ELEMENTS = 2;
+ constexpr int source[COUNT_ELEMENTS] = {1, 2};
+ for (size_t i = 0; i < COUNT_ELEMENTS; i++) {
+ ASSERT_EQ(mmi_data_create_int(source[i], &arrayElement[i]), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_data_add_array_element(mmiData, arrayElement[i]), MMI_ERROR_NONE);
+ arrayElement[i] = nullptr;
+ }
+
+ size_t count = 0;
+ EXPECT_EQ(mmi_data_get_array_count(mmiData, &count), MMI_ERROR_NONE);
+ EXPECT_EQ(count, COUNT_ELEMENTS);
+
+ EXPECT_EQ(mmi_data_get_array_element(nullptr, 0, &element), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_data_get_array_element(mmiData, count, &element), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_data_get_array_element(mmiData, 0, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataGetArrayElement_n2) {
+ int sourceValue = 0;
+ ASSERT_EQ(mmi_data_create_int(sourceValue, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ mmi_data_h element = nullptr;
+ EXPECT_EQ(mmi_data_get_array_element(mmiData, 0, &element), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataGetStructElement_p) {
+ ASSERT_EQ(mmi_data_create_struct(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ constexpr int sourceInt = 1;
+ ASSERT_EQ(mmi_data_create_int(sourceInt, &arrayElement[0]), MMI_ERROR_NONE);
+
+ constexpr const char *name = "Element";
+ EXPECT_EQ(mmi_data_set_struct_element(mmiData, name, arrayElement[0]), MMI_ERROR_NONE);
+ arrayElement[0] = nullptr;
+
+ mmi_data_h element = nullptr;
+ EXPECT_EQ(mmi_data_get_struct_element(mmiData, name, &element), MMI_ERROR_NONE);
+ EXPECT_NE(element, nullptr);
+}
+
+TEST_F(MMIDataTest, MMIDataGetStructElement_n1) {
+ ASSERT_EQ(mmi_data_create_struct(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ constexpr const char *name = "Element";
+ mmi_data_h element = nullptr;
+ EXPECT_EQ(mmi_data_get_struct_element(mmiData, name, &element), MMI_ERROR_INVALID_PARAMETER);
+
+ constexpr int sourceInt = 1;
+ ASSERT_EQ(mmi_data_create_int(sourceInt, &arrayElement[0]), MMI_ERROR_NONE);
+ EXPECT_EQ(mmi_data_set_struct_element(mmiData, name, arrayElement[0]), MMI_ERROR_NONE);
+ arrayElement[0] = nullptr;
+
+ EXPECT_EQ(mmi_data_get_struct_element(nullptr, name, &element), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_data_get_struct_element(mmiData, nullptr, &element), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_data_get_struct_element(mmiData, name, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataGetStructElement_n2) {
+ int sourceValue = 0;
+ ASSERT_EQ(mmi_data_create_int(sourceValue, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ constexpr const char *name = "Element";
+ mmi_data_h element = nullptr;
+ EXPECT_EQ(mmi_data_get_struct_element(mmiData, name, &element), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIDataTest, MMIDataDestroy_p1) {
+ int sourceValue = 0;
+ ASSERT_EQ(mmi_data_create_int(sourceValue, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ ASSERT_EQ(mmi_data_destroy(mmiData), MMI_ERROR_NONE);
+ mmiData = nullptr;
+}
+
+TEST_F(MMIDataTest, MMIDataDestroy_p2) {
+ const char *sourceValue = "Hello";
+ EXPECT_EQ(mmi_data_create_text(sourceValue, &mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ ASSERT_EQ(mmi_data_destroy(mmiData), MMI_ERROR_NONE);
+ mmiData = nullptr;
+}
+
+TEST_F(MMIDataTest, MMIDataDestroy_p3) {
+ ASSERT_EQ(mmi_data_create_array(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ constexpr int COUNT_ELEMENTS = 2;
+ constexpr int source[COUNT_ELEMENTS] = {1, 2};
+ for (size_t i = 0; i < COUNT_ELEMENTS; i++) {
+ ASSERT_EQ(mmi_data_create_int(source[i], &arrayElement[i]), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_data_add_array_element(mmiData, arrayElement[i]), MMI_ERROR_NONE);
+ arrayElement[i] = nullptr;
+ }
+
+ ASSERT_EQ(mmi_data_destroy(mmiData), MMI_ERROR_NONE);
+ mmiData = nullptr;
+}
+
+TEST_F(MMIDataTest, MMIDataDestroy_p4) {
+ ASSERT_EQ(mmi_data_create_struct(&mmiData), MMI_ERROR_NONE);
+ ASSERT_NE(mmiData, nullptr);
+
+ constexpr int sourceInt = 1;
+ constexpr const char *sourceText = "Hello";
+ ASSERT_EQ(mmi_data_create_int(sourceInt, &arrayElement[0]), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_data_create_text(sourceText, &arrayElement[1]), MMI_ERROR_NONE);
+
+ constexpr int COUNT_ELEMENTS = 2;
+ constexpr const char *name[COUNT_ELEMENTS] = {"Element1", "Element2"};
+ for (size_t i = 0; i < COUNT_ELEMENTS; i++) {
+ ASSERT_EQ(mmi_data_set_struct_element(mmiData, name[i], arrayElement[i]), MMI_ERROR_NONE);
+ arrayElement[i] = nullptr;
+ }
+
+ ASSERT_EQ(mmi_data_destroy(mmiData), MMI_ERROR_NONE);
+ mmiData = nullptr;
+}
+
+TEST_F(MMIDataTest, MMIDataDestroy_n) {
+ ASSERT_EQ(mmi_data_destroy(nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
--- /dev/null
+/*
+ * 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 "mmi.h"
+#include "mmi-tests.h"
+#include "mmi-ipc-tidl.h"
+
+#include <Ecore.h>
+#include <rpc-port-internal.h>
+
+static mmi_state_e g_state = MMI_STATE_NONE;
+static int state_changed_cb(mmi_state_e state, void *user_data) {
+ g_state = state;
+ return MMI_ERROR_NONE;
+}
+
+static void wait_until_connected(int msec) {
+ int i = 0;
+ while (g_state != MMI_STATE_READY && i < msec) {
+ ecore_main_loop_iterate();
+ usleep(1000);
+ i++;
+ }
+}
+
+class MMIIpcTest : public ::testing::Test {
+public:
+ void SetUp(void) override {
+ ecore_init();
+ }
+
+ void TearDown(void) override {
+ ecore_shutdown();
+ }
+};
+
+TEST_F(MMIIpcTest, MMIFWIpcInitSuccess_p) {
+ int res = mmi_initialize();
+
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ mmi_deinitialize();
+}
+
+TEST_F(MMIIpcTest, MMIFWIpcWorkflowInstanceCreationSuccess_p) {
+ int res = mmi_initialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ res = mmi_set_state_changed_cb(state_changed_cb, nullptr);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ wait_until_connected(1000);
+
+ mmi_workflow_instance_h instance = nullptr;
+ res = mmi_standard_workflow_instance_create(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND, &instance);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ res = mmi_unset_state_changed_cb(state_changed_cb);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ res = mmi_deinitialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+}
+
+TEST_F(MMIIpcTest, MMIFWIpcWorkflowInstanceSetAttributeSuccess_p) {
+ int res = mmi_initialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ res = mmi_set_state_changed_cb(state_changed_cb, nullptr);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ wait_until_connected(1000);
+
+ mmi_workflow_instance_h instance = nullptr;
+ res = mmi_standard_workflow_instance_create(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND, &instance);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ mmi_attribute_h attribute = nullptr;
+ constexpr size_t COMMAND_NUM = 2;
+ const char *commands[] = {"Open", "Close"};
+ res = mmi_attribute_create_string_array("COMMANDS", commands, COMMAND_NUM, &attribute);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ res = mmi_workflow_instance_set_attribute(instance, attribute);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ res = mmi_unset_state_changed_cb(state_changed_cb);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ res = mmi_deinitialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+}
+
+TEST_F(MMIIpcTest, MMIFWIpcWorkflowInstanceActivateSuccess_p) {
+ int res = mmi_initialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ res = mmi_set_state_changed_cb(state_changed_cb, nullptr);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ wait_until_connected(1000);
+
+ mmi_workflow_instance_h instance = nullptr;
+ res = mmi_standard_workflow_instance_create(MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND, &instance);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ res = mmi_workflow_instance_activate(instance);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ res = mmi_unset_state_changed_cb(state_changed_cb);
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ res = mmi_deinitialize();
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+}
--- /dev/null
+/*
+ * 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 "mmi.h"
+#include "mmi-tests.h"
+#include "mmi-ipc-tidl.h"
+
+#include <Ecore.h>
+#include <rpc-port-internal.h>
+
+static int state_changed_cb(mmi_state_e state, void *user_data) {
+ return MMI_ERROR_NONE;
+}
+
+class MMIMainTest : public ::testing::Test {
+public:
+ void SetUp(void) override {
+ ecore_init();
+ }
+
+ void TearDown(void) override {
+ ecore_shutdown();
+ }
+};
+
+TEST_F(MMIMainTest, MMIMainInit) {
+ int res = mmi_initialize();
+
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ mmi_deinitialize();
+}
+
+TEST_F(MMIMainTest, MmiClientCreateSuccess) {
+ int res = mmi_initialize();
+
+ EXPECT_EQ(res, MMI_ERROR_NONE);
+
+ mmi_deinitialize();
+}
+
+
#include "mmi-tests.h"
-int main(int argc, char **argv)
-{
- auto testResults = false;
+int main(int argc, char **argv) {
+ auto testResults = false;
#ifdef TIZEN_TEST_GCOV
- setenv("GCOV_PREFIX", "/tmp", 1);
+ setenv("GCOV_PREFIX", "/tmp", 1);
#endif
- try
- {
- ::testing::InitGoogleMock(&argc, argv);
- ::testing::FLAGS_gtest_death_test_style = "fast";
- }
- catch ( ... )
- {
- PRINT("Error occurred while trying to initialize GoogleTest.\n");
- exit(EXIT_FAILURE);
- }
+ try {
+ ::testing::InitGoogleMock(&argc, argv);
+ ::testing::FLAGS_gtest_death_test_style = "fast";
+ } catch ( ... ) {
+ PRINT("Error occurred while trying to initialize GoogleTest.\n");
+ exit(EXIT_FAILURE);
+ }
- try
- {
- testResults = (RUN_ALL_TESTS() == 0) ? true : false;
- }
- catch (const ::testing::internal::GoogleTestFailureException &e)
- {
- testResults = false;
- PRINT("GoogleTestFailureException has been thrown: %s\n", e.what());
- }
+ try {
+ testResults = (RUN_ALL_TESTS() == 0) ? true : false;
+ } catch (const ::testing::internal::GoogleTestFailureException &e) {
+ testResults = false;
+ PRINT("GoogleTestFailureException has been thrown: %s\n", e.what());
+ }
#ifdef TIZEN_TEST_GCOV
- __gcov_flush();
+ __gcov_flush();
#endif
- return testResults;
+ return (testResults ? 0 : 1);
}
#ifdef TIZEN_TEST_GCOV
extern "C" void __gcov_flush(void);
#endif
-extern void wait_for_connect();
using ::testing::TestWithParam;
using ::testing::Bool;
--- /dev/null
+/*
+ * 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 <gmock/gmock.h>
+
+#include <mmi-error.h>
+#include <mmi-primitive-value.h>
+
+
+class MMIPrimitiveValueTest : public ::testing::Test {
+public:
+ void SetUp(void) override {
+ primitiveValue = nullptr;
+ arrayElement1 = nullptr;
+ arrayElement2 = nullptr;
+ }
+
+ void TearDown(void) override {
+ if (nullptr != primitiveValue) {
+ mmi_primitive_value_destroy(primitiveValue);
+ }
+
+ if (nullptr != arrayElement1) {
+ mmi_primitive_value_destroy(arrayElement1);
+ }
+
+ if (nullptr != arrayElement2) {
+ mmi_primitive_value_destroy(arrayElement2);
+ }
+
+ primitiveValue = nullptr;
+ arrayElement1 = nullptr;
+ arrayElement2 = nullptr;
+ }
+
+ mmi_primitive_value_h primitiveValue = nullptr;
+ mmi_primitive_value_h arrayElement1 = nullptr;
+ mmi_primitive_value_h arrayElement2 = nullptr;
+};
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveCreateValueByInt_p) {
+ int sourceValue = 0;
+ EXPECT_EQ(mmi_primitive_value_create_int(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveCreateValueByInt_n) {
+ int sourceValue = 0;
+ EXPECT_EQ(mmi_primitive_value_create_int(sourceValue, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveCreateValueByFloat_p) {
+ float sourceValue = 0.0;
+ EXPECT_EQ(mmi_primitive_value_create_float(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveCreateValueByFloat_n) {
+ float sourceValue = 0.0;
+ EXPECT_EQ(mmi_primitive_value_create_float(sourceValue, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveCreateValueByString_p) {
+ const char *sourceValue = "Hello";
+ EXPECT_EQ(mmi_primitive_value_create_string(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveCreateValueByString_n) {
+ const char *sourceValue = "Hello";
+ EXPECT_EQ(mmi_primitive_value_create_string(sourceValue, nullptr), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_primitive_value_create_string(nullptr, &primitiveValue), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveCreateValueByBool_p) {
+ bool sourceValue = true;
+ EXPECT_EQ(mmi_primitive_value_create_bool(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveCreateValueByBool_n) {
+ bool sourceValue = true;
+ EXPECT_EQ(mmi_primitive_value_create_bool(sourceValue, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveCreateValueByArray_p) {
+ EXPECT_EQ(mmi_primitive_value_create_array(&primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveCreateValueByArray_n) {
+ EXPECT_EQ(mmi_primitive_value_create_array(nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveAddElementIntoArray_p) {
+ ASSERT_EQ(mmi_primitive_value_create_array(&primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ int source1 = 1, source2 = 2;
+ ASSERT_EQ(mmi_primitive_value_create_int(source1, &arrayElement1), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_primitive_value_create_int(source2, &arrayElement2), MMI_ERROR_NONE);
+
+ ASSERT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement1), MMI_ERROR_NONE);
+ arrayElement1 = nullptr;
+ ASSERT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement2), MMI_ERROR_NONE);
+ arrayElement2 = nullptr;
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveAddElementIntoArray_n1) {
+ ASSERT_EQ(mmi_primitive_value_create_array(&primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ int source1 = 1;
+ float source2 = 2.0;
+ ASSERT_EQ(mmi_primitive_value_create_int(source1, &arrayElement1), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_primitive_value_create_float(source2, &arrayElement2), MMI_ERROR_NONE);
+
+ EXPECT_EQ(mmi_primitive_value_add_array_element(nullptr, arrayElement1), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_primitive_value_add_array_element(primitiveValue, nullptr), MMI_ERROR_INVALID_PARAMETER);
+
+ ASSERT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement1), MMI_ERROR_NONE);
+ arrayElement1 = nullptr;
+ EXPECT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement2), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveAddElementIntoArray_n2) {
+ int sourceValue = 0;
+ EXPECT_EQ(mmi_primitive_value_create_int(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ int source1 = 1;
+ ASSERT_EQ(mmi_primitive_value_create_int(source1, &arrayElement1), MMI_ERROR_NONE);
+ EXPECT_NE(arrayElement1, nullptr);
+
+ EXPECT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement1), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetType_p) {
+ mmi_primitive_value_h tempIntValue = nullptr;
+ mmi_primitive_value_type_e tempIntType = MMI_PRIMITIVE_VALUE_TYPE_ARRAY;
+
+ EXPECT_EQ(mmi_primitive_value_create_int(0, &tempIntValue), MMI_ERROR_NONE);
+ EXPECT_EQ(mmi_primitive_value_get_type(tempIntValue, &tempIntType), MMI_ERROR_NONE);
+ EXPECT_EQ(tempIntType, MMI_PRIMITIVE_VALUE_TYPE_INT);
+ EXPECT_EQ(mmi_primitive_value_destroy(tempIntValue), MMI_ERROR_NONE);
+
+ mmi_primitive_value_h tempFloatValue = nullptr;
+ mmi_primitive_value_type_e tempFloatType = MMI_PRIMITIVE_VALUE_TYPE_ARRAY;
+
+ EXPECT_EQ(mmi_primitive_value_create_float(0.0, &tempFloatValue), MMI_ERROR_NONE);
+ EXPECT_EQ(mmi_primitive_value_get_type(tempFloatValue, &tempFloatType), MMI_ERROR_NONE);
+ EXPECT_EQ(tempFloatType, MMI_PRIMITIVE_VALUE_TYPE_FLOAT);
+ EXPECT_EQ(mmi_primitive_value_destroy(tempFloatValue), MMI_ERROR_NONE);
+
+ mmi_primitive_value_h tempStringValue = nullptr;
+ mmi_primitive_value_type_e tempStringType = MMI_PRIMITIVE_VALUE_TYPE_ARRAY;
+
+ EXPECT_EQ(mmi_primitive_value_create_string("Hello", &tempStringValue), MMI_ERROR_NONE);
+ EXPECT_EQ(mmi_primitive_value_get_type(tempStringValue, &tempStringType), MMI_ERROR_NONE);
+ EXPECT_EQ(tempStringType, MMI_PRIMITIVE_VALUE_TYPE_STRING);
+ EXPECT_EQ(mmi_primitive_value_destroy(tempStringValue), MMI_ERROR_NONE);
+
+ mmi_primitive_value_h tempBoolValue = nullptr;
+ mmi_primitive_value_type_e tempBoolType = MMI_PRIMITIVE_VALUE_TYPE_ARRAY;
+
+ EXPECT_EQ(mmi_primitive_value_create_bool(true, &tempBoolValue), MMI_ERROR_NONE);
+ EXPECT_EQ(mmi_primitive_value_get_type(tempBoolValue, &tempBoolType), MMI_ERROR_NONE);
+ EXPECT_EQ(tempBoolType, MMI_PRIMITIVE_VALUE_TYPE_BOOL);
+ EXPECT_EQ(mmi_primitive_value_destroy(tempBoolValue), MMI_ERROR_NONE);
+
+ mmi_primitive_value_h tempArrayValue = nullptr;
+ mmi_primitive_value_type_e tempArrayType = MMI_PRIMITIVE_VALUE_TYPE_INT;
+
+ EXPECT_EQ(mmi_primitive_value_create_array(&tempArrayValue), MMI_ERROR_NONE);
+ EXPECT_EQ(mmi_primitive_value_get_type(tempArrayValue, &tempArrayType), MMI_ERROR_NONE);
+ EXPECT_EQ(tempArrayType, MMI_PRIMITIVE_VALUE_TYPE_ARRAY);
+ EXPECT_EQ(mmi_primitive_value_destroy(tempArrayValue), MMI_ERROR_NONE);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetType_n) {
+ float sourceValue = 0.0;
+ ASSERT_EQ(mmi_primitive_value_create_float(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ mmi_primitive_value_type_e type = MMI_PRIMITIVE_VALUE_TYPE_ARRAY;
+ EXPECT_EQ(mmi_primitive_value_get_type(nullptr, &type), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_primitive_value_get_type(primitiveValue, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetIntValue_p) {
+ int sourceValue = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ int targetValue = -1;
+ EXPECT_EQ(mmi_primitive_value_get_int(primitiveValue, &targetValue), MMI_ERROR_NONE);
+ EXPECT_EQ(targetValue, sourceValue);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetIntValue_n1) {
+ int sourceValue = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ int targetValue = -1;
+ EXPECT_EQ(mmi_primitive_value_get_int(nullptr, &targetValue), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_primitive_value_get_int(primitiveValue, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetIntValue_n2) {
+ float sourceValue = 0.0;
+ ASSERT_EQ(mmi_primitive_value_create_float(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ int targetValue = -1;
+ EXPECT_EQ(mmi_primitive_value_get_int(primitiveValue, &targetValue), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetFloatValue_p) {
+ float sourceValue = 0;
+ ASSERT_EQ(mmi_primitive_value_create_float(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ float targetValue = -1.0;
+ EXPECT_EQ(mmi_primitive_value_get_float(primitiveValue, &targetValue), MMI_ERROR_NONE);
+ EXPECT_EQ(targetValue, sourceValue);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetFloatValue_n1) {
+ float sourceValue = 0;
+ ASSERT_EQ(mmi_primitive_value_create_float(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ float targetValue = -1.0;
+ EXPECT_EQ(mmi_primitive_value_get_float(nullptr, &targetValue), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_primitive_value_get_float(primitiveValue, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetFloatValue_n2) {
+ int sourceValue = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ float targetValue = -1.0;
+ EXPECT_EQ(mmi_primitive_value_get_float(primitiveValue, &targetValue), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetStringValue_p) {
+ const char *sourceValue = "Hello";
+ ASSERT_EQ(mmi_primitive_value_create_string(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ const char *targetValue = nullptr;
+ EXPECT_EQ(mmi_primitive_value_get_string(primitiveValue, &targetValue), MMI_ERROR_NONE);
+ EXPECT_STREQ(targetValue, sourceValue);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetStringValue_n1) {
+ const char *sourceValue = "Hello";
+ ASSERT_EQ(mmi_primitive_value_create_string(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ const char *targetValue = nullptr;
+ EXPECT_EQ(mmi_primitive_value_get_string(nullptr, &targetValue), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_primitive_value_get_string(primitiveValue, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetStringValue_n2) {
+ int sourceValue = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ const char *targetValue = nullptr;
+ EXPECT_EQ(mmi_primitive_value_get_string(primitiveValue, &targetValue), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetArrayCount_p) {
+ ASSERT_EQ(mmi_primitive_value_create_array(&primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ size_t count = 10;
+ EXPECT_EQ(mmi_primitive_value_get_array_count(primitiveValue, &count), MMI_ERROR_NONE);
+ EXPECT_EQ(count, 0);
+
+ int source1 = 1, source2 = 2;
+ ASSERT_EQ(mmi_primitive_value_create_int(source1, &arrayElement1), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_primitive_value_create_int(source2, &arrayElement2), MMI_ERROR_NONE);
+
+ ASSERT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement1), MMI_ERROR_NONE);
+ arrayElement1 = nullptr;
+ ASSERT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement2), MMI_ERROR_NONE);
+ arrayElement2 = nullptr;
+
+ EXPECT_EQ(mmi_primitive_value_get_array_count(primitiveValue, &count), MMI_ERROR_NONE);
+ EXPECT_EQ(count, 2);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetArrayCount_n1) {
+ ASSERT_EQ(mmi_primitive_value_create_array(&primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ size_t count = 0;
+ EXPECT_EQ(mmi_primitive_value_get_array_count(nullptr, &count), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_primitive_value_get_array_count(primitiveValue, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetArrayCount_n2) {
+ int sourceValue = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ size_t count = 0;
+ EXPECT_EQ(mmi_primitive_value_get_array_count(primitiveValue, &count), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetArrayElement_p) {
+ ASSERT_EQ(mmi_primitive_value_create_array(&primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ const int source[] = {1, 2};
+ ASSERT_EQ(mmi_primitive_value_create_int(source[0], &arrayElement1), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_primitive_value_create_int(source[1], &arrayElement2), MMI_ERROR_NONE);
+
+ EXPECT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement1), MMI_ERROR_NONE);
+ arrayElement1 = nullptr;
+ EXPECT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement2), MMI_ERROR_NONE);
+ arrayElement2 = nullptr;
+
+ size_t count = 0;
+ EXPECT_EQ(mmi_primitive_value_get_array_count(primitiveValue, &count), MMI_ERROR_NONE);
+ EXPECT_EQ(count, 2);
+
+ for (size_t i = 0; i < count; i++) {
+ mmi_primitive_value_h element = nullptr;
+ EXPECT_EQ(mmi_primitive_value_get_array_element(primitiveValue, i, &element), MMI_ERROR_NONE);
+
+ mmi_primitive_value_type_e type = MMI_PRIMITIVE_VALUE_TYPE_BOOL;
+ EXPECT_EQ(mmi_primitive_value_get_type(element, &type), MMI_ERROR_NONE);
+ EXPECT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_INT);
+
+ int data = 0;
+ EXPECT_EQ(mmi_primitive_value_get_int(element, &data), MMI_ERROR_NONE);
+ EXPECT_EQ(data, source[i]);
+ }
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetArrayElement_n1) {
+ ASSERT_EQ(mmi_primitive_value_create_array(&primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ size_t count = 0;
+ EXPECT_EQ(mmi_primitive_value_get_array_count(nullptr, &count), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_primitive_value_get_array_count(primitiveValue, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveGetArrayElement_n2) {
+ int sourceValue = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ size_t count = 0;
+ EXPECT_EQ(mmi_primitive_value_get_array_count(primitiveValue, &count), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveCloneValue_p1) {
+ int sourceValue = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ mmi_primitive_value_h clonedValue = nullptr;
+ EXPECT_EQ(mmi_primitive_value_clone(primitiveValue, &clonedValue), MMI_ERROR_NONE);
+
+ mmi_primitive_value_type_e type = MMI_PRIMITIVE_VALUE_TYPE_BOOL;
+ EXPECT_EQ(mmi_primitive_value_get_type(clonedValue, &type), MMI_ERROR_NONE);
+ EXPECT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_INT);
+
+ int data = 0;
+ EXPECT_EQ(mmi_primitive_value_get_int(clonedValue, &data), MMI_ERROR_NONE);
+ EXPECT_EQ(data, sourceValue);
+
+ EXPECT_EQ(mmi_primitive_value_destroy(clonedValue), MMI_ERROR_NONE);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveCloneValue_p2) {
+ const char *sourceValue = "Hello";
+ EXPECT_EQ(mmi_primitive_value_create_string(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ mmi_primitive_value_h clonedValue = nullptr;
+ EXPECT_EQ(mmi_primitive_value_clone(primitiveValue, &clonedValue), MMI_ERROR_NONE);
+
+ mmi_primitive_value_type_e type = MMI_PRIMITIVE_VALUE_TYPE_BOOL;
+ EXPECT_EQ(mmi_primitive_value_get_type(clonedValue, &type), MMI_ERROR_NONE);
+ EXPECT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_STRING);
+
+ const char *data = nullptr;
+ EXPECT_EQ(mmi_primitive_value_get_string(clonedValue, &data), MMI_ERROR_NONE);
+ EXPECT_STREQ(data, sourceValue);
+
+ EXPECT_EQ(mmi_primitive_value_destroy(clonedValue), MMI_ERROR_NONE);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveCloneValue_p3) {
+ ASSERT_EQ(mmi_primitive_value_create_array(&primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ const int source[] = {1, 2};
+ ASSERT_EQ(mmi_primitive_value_create_int(source[0], &arrayElement1), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_primitive_value_create_int(source[1], &arrayElement2), MMI_ERROR_NONE);
+
+ ASSERT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement1), MMI_ERROR_NONE);
+ arrayElement1 = nullptr;
+ ASSERT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement2), MMI_ERROR_NONE);
+ arrayElement2 = nullptr;
+
+ mmi_primitive_value_h clonedValue = nullptr;
+ EXPECT_EQ(mmi_primitive_value_clone(primitiveValue, &clonedValue), MMI_ERROR_NONE);
+
+ size_t count = 0;
+ EXPECT_EQ(mmi_primitive_value_get_array_count(clonedValue, &count), MMI_ERROR_NONE);
+ EXPECT_EQ(count, 2);
+
+ for (size_t i = 0; i < count; i++) {
+ mmi_primitive_value_h element = nullptr;
+ EXPECT_EQ(mmi_primitive_value_get_array_element(clonedValue, i, &element), MMI_ERROR_NONE);
+
+ mmi_primitive_value_type_e type = MMI_PRIMITIVE_VALUE_TYPE_BOOL;
+ EXPECT_EQ(mmi_primitive_value_get_type(element, &type), MMI_ERROR_NONE);
+ EXPECT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_INT);
+
+ int data = 0;
+ EXPECT_EQ(mmi_primitive_value_get_int(element, &data), MMI_ERROR_NONE);
+ EXPECT_EQ(data, source[i]);
+ }
+
+ EXPECT_EQ(mmi_primitive_value_destroy(clonedValue), MMI_ERROR_NONE);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveCloneValue_n) {
+ int sourceValue = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ mmi_primitive_value_h clonedValue = nullptr;
+ EXPECT_EQ(mmi_primitive_value_clone(nullptr, &clonedValue), MMI_ERROR_INVALID_PARAMETER);
+ EXPECT_EQ(mmi_primitive_value_clone(primitiveValue, nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveDestroy_p1) {
+ int sourceValue = 0;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ ASSERT_EQ(mmi_primitive_value_destroy(primitiveValue), MMI_ERROR_NONE);
+ primitiveValue = nullptr;
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveDestroy_p2) {
+ const char *sourceValue = "Hello";
+ EXPECT_EQ(mmi_primitive_value_create_string(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ ASSERT_EQ(mmi_primitive_value_destroy(primitiveValue), MMI_ERROR_NONE);
+ primitiveValue = nullptr;
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveDestroy_p3) {
+ ASSERT_EQ(mmi_primitive_value_create_array(&primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ const int source[] = {1, 2};
+ ASSERT_EQ(mmi_primitive_value_create_int(source[0], &arrayElement1), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_primitive_value_create_int(source[1], &arrayElement2), MMI_ERROR_NONE);
+
+ EXPECT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement1), MMI_ERROR_NONE);
+ arrayElement1 = nullptr;
+ EXPECT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement2), MMI_ERROR_NONE);
+ arrayElement2 = nullptr;
+
+ ASSERT_EQ(mmi_primitive_value_destroy(primitiveValue), MMI_ERROR_NONE);
+ primitiveValue = nullptr;
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveDestroy_n) {
+ ASSERT_EQ(mmi_primitive_value_destroy(nullptr), MMI_ERROR_INVALID_PARAMETER);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveBytesConversionIntValue_p) {
+ int sourceValue = 3;
+ ASSERT_EQ(mmi_primitive_value_create_int(sourceValue, &primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ unsigned char *bytes = nullptr;
+ size_t length = 0;
+ ASSERT_EQ(mmi_primitive_value_to_bytes(primitiveValue, &bytes, &length), MMI_ERROR_NONE);
+
+ mmi_primitive_value_destroy(primitiveValue);
+ primitiveValue = nullptr;
+
+ mmi_primitive_value_h restoredValue = nullptr;
+ ASSERT_EQ(mmi_primitive_value_from_bytes(bytes, length, &restoredValue), MMI_ERROR_NONE);
+
+ free(bytes);
+
+ mmi_primitive_value_type_e type = MMI_PRIMITIVE_VALUE_TYPE_BOOL;
+ ASSERT_EQ(mmi_primitive_value_get_type(restoredValue, &type), MMI_ERROR_NONE);
+ ASSERT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_INT);
+
+ int data = 0;
+ ASSERT_EQ(mmi_primitive_value_get_int(restoredValue, &data), MMI_ERROR_NONE);
+ ASSERT_EQ(data, sourceValue);
+
+ ASSERT_EQ(mmi_primitive_value_destroy(restoredValue), MMI_ERROR_NONE);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveBytesConversionIntArray_p) {
+ ASSERT_EQ(mmi_primitive_value_create_array(&primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ constexpr size_t SOURCE_COUNT = 2;
+ const int source[SOURCE_COUNT] = {1, 2};
+ ASSERT_EQ(mmi_primitive_value_create_int(source[0], &arrayElement1), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_primitive_value_create_int(source[1], &arrayElement2), MMI_ERROR_NONE);
+
+ ASSERT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement1), MMI_ERROR_NONE);
+ arrayElement1 = nullptr;
+ ASSERT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement2), MMI_ERROR_NONE);
+ arrayElement2 = nullptr;
+
+ unsigned char *bytes = nullptr;
+ size_t length = 0;
+ ASSERT_EQ(mmi_primitive_value_to_bytes(primitiveValue, &bytes, &length), MMI_ERROR_NONE);
+
+ mmi_primitive_value_destroy(primitiveValue);
+ primitiveValue = nullptr;
+ mmi_primitive_value_destroy(arrayElement1);
+ arrayElement1 = nullptr;
+ mmi_primitive_value_destroy(arrayElement2);
+ arrayElement2 = nullptr;
+
+ mmi_primitive_value_h restoredValue = nullptr;
+ ASSERT_EQ(mmi_primitive_value_from_bytes(bytes, length, &restoredValue), MMI_ERROR_NONE);
+
+ free(bytes);
+
+ mmi_primitive_value_type_e type = MMI_PRIMITIVE_VALUE_TYPE_BOOL;
+ ASSERT_EQ(mmi_primitive_value_get_type(restoredValue, &type), MMI_ERROR_NONE);
+ ASSERT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_ARRAY);
+
+ size_t count = 0;
+ ASSERT_EQ(mmi_primitive_value_get_array_count(restoredValue, &count), MMI_ERROR_NONE);
+ ASSERT_EQ(count, SOURCE_COUNT);
+
+ for (size_t i = 0; i < count; ++i) {
+ int data = 0;
+ mmi_primitive_value_h element = nullptr;
+ ASSERT_EQ(mmi_primitive_value_get_array_element(restoredValue, i, &element), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_primitive_value_get_type(element, &type), MMI_ERROR_NONE);
+ ASSERT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_INT);
+ ASSERT_EQ(mmi_primitive_value_get_int(element, &data), MMI_ERROR_NONE);
+ ASSERT_EQ(data, source[i]);
+ }
+ ASSERT_EQ(mmi_primitive_value_destroy(restoredValue), MMI_ERROR_NONE);
+}
+
+TEST_F(MMIPrimitiveValueTest, MMIPrimitiveBytesConversionStringArray_p) {
+ ASSERT_EQ(mmi_primitive_value_create_array(&primitiveValue), MMI_ERROR_NONE);
+ EXPECT_NE(primitiveValue, nullptr);
+
+ constexpr size_t SOURCE_COUNT = 2;
+ const char *source[SOURCE_COUNT] = {"1", "Number 2"};
+ ASSERT_EQ(mmi_primitive_value_create_string(source[0], &arrayElement1), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_primitive_value_create_string(source[1], &arrayElement2), MMI_ERROR_NONE);
+
+ ASSERT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement1), MMI_ERROR_NONE);
+ arrayElement1 = nullptr;
+ ASSERT_EQ(mmi_primitive_value_add_array_element(primitiveValue, arrayElement2), MMI_ERROR_NONE);
+ arrayElement2 = nullptr;
+
+ unsigned char *bytes = nullptr;
+ size_t length = 0;
+ ASSERT_EQ(mmi_primitive_value_to_bytes(primitiveValue, &bytes, &length), MMI_ERROR_NONE);
+
+ mmi_primitive_value_destroy(primitiveValue);
+ primitiveValue = nullptr;
+ mmi_primitive_value_destroy(arrayElement1);
+ arrayElement1 = nullptr;
+ mmi_primitive_value_destroy(arrayElement2);
+ arrayElement2 = nullptr;
+
+ mmi_primitive_value_h restoredValue = nullptr;
+ ASSERT_EQ(mmi_primitive_value_from_bytes(bytes, length, &restoredValue), MMI_ERROR_NONE);
+
+ free(bytes);
+
+ mmi_primitive_value_type_e type = MMI_PRIMITIVE_VALUE_TYPE_BOOL;
+ ASSERT_EQ(mmi_primitive_value_get_type(restoredValue, &type), MMI_ERROR_NONE);
+ ASSERT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_ARRAY);
+
+ size_t count = 0;
+ ASSERT_EQ(mmi_primitive_value_get_array_count(restoredValue, &count), MMI_ERROR_NONE);
+ ASSERT_EQ(count, SOURCE_COUNT);
+
+ for (size_t i = 0; i < count; ++i) {
+ mmi_primitive_value_h element = nullptr;
+ ASSERT_EQ(mmi_primitive_value_get_array_element(restoredValue, i, &element), MMI_ERROR_NONE);
+ ASSERT_EQ(mmi_primitive_value_get_type(element, &type), MMI_ERROR_NONE);
+ ASSERT_EQ(type, MMI_PRIMITIVE_VALUE_TYPE_STRING);
+ const char *data = nullptr;
+ EXPECT_EQ(mmi_primitive_value_get_string(element, &data), MMI_ERROR_NONE);
+ ASSERT_STREQ(data, source[i]);
+ }
+ ASSERT_EQ(mmi_primitive_value_destroy(restoredValue), MMI_ERROR_NONE);
+}
--- /dev/null
+#include <iostream>
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include <mmi-workflow.h>
+#include <mmi-node-source.h>
+#include <mmi-node-processor.h>
+#include <mmi-node-logic.h>
+
+#include "mmi-workflow-script-parser.h"
+
+#include <string>
+#include <sstream>
+#include <vector>
+
+extern "C" {
+/* Add wrapper functions here with __wrap_ and __real prefix
+Example :
+
+int __real_vconf_get_int(const char *in_key, int *intval);
+int __wrap_vconf_get_int(const char *in_key, int *intval)
+{
+ if (strcmp(in_key, "TestKey") == 0)
+ return 0;
+
+ return __real_vconf_get_int(in_key, intval);
+}
+*/
+}
+
+class MMIWorkflowTest : public ::testing::Test {
+public:
+ void SetUp(void) override {
+ mmi_workflow_create(&m_workflow);
+
+ mmi_workflow_set_type(m_workflow, MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND);
+
+ m_node_mic = nullptr;
+ /* FIXME: node should be 'found' instead of 'created' */
+ mmi_standard_node_create_source(MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT, &m_node_mic);
+ mmi_workflow_node_add(m_workflow, "MIC", m_node_mic);
+
+ m_node_asr = nullptr;
+ mmi_standard_node_create_processor(MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR, &m_node_asr);
+ mmi_workflow_node_add(m_workflow, "ASR", m_node_asr);
+
+ m_node_match = nullptr;
+ mmi_standard_node_create_logic(MMI_STANDARD_NODE_LOGIC_TYPE_FIXED_STRING_MATCH, &m_node_match);
+ mmi_workflow_node_add(m_workflow, "MATCH", m_node_match);
+
+ mmi_workflow_link_nodes_by_names(m_workflow, "MIC", "AUDIO", "ASR", "AUDIO");
+ mmi_workflow_link_nodes_by_names(m_workflow, "ASR", "FINAL_RESULT", "MATCH", "TEXT");
+
+ mmi_workflow_attribute_assign(m_workflow, "COMMANDS", "MATCH", "CANDIDATES");
+
+ mmi_workflow_output_assign(m_workflow, "COMMAND", "MATCH", "MATCHED_CANDIDATE");
+ }
+
+ void TearDown(void) override {
+ mmi_node_destroy(m_node_match);
+ mmi_node_destroy(m_node_asr);
+ mmi_node_destroy(m_node_mic);
+
+ mmi_workflow_destroy(m_workflow);
+ }
+
+ mmi_workflow_h m_workflow{nullptr};
+ mmi_node_h m_node_mic{nullptr};
+ mmi_node_h m_node_asr{nullptr};
+ mmi_node_h m_node_match{nullptr};
+};
+
+static bool compare_workflow_prototype(mmi_workflow_h first, mmi_workflow_h second) {
+ if (first == nullptr || second == nullptr) {
+ return false;
+ }
+ mmi_workflow_s *first_workflow = (mmi_workflow_s *)first;
+ mmi_workflow_s *second_workflow = (mmi_workflow_s *)second;
+
+ if (first_workflow->type != second_workflow->type) {
+ return false;
+ }
+
+ if (first_workflow->node_info_count != second_workflow->node_info_count) {
+ return false;
+ }
+
+ for (size_t i = 0; i < first_workflow->node_info_count; i++) {
+ if (strcmp(first_workflow->node_infos[i].name, second_workflow->node_infos[i].name) != 0) {
+ return false;
+ }
+
+ mmi_standard_node_type_e first_type;
+ mmi_standard_node_type_e second_type;
+ mmi_node_get_type(first_workflow->node_infos[i].node, &first_type);
+ mmi_node_get_type(second_workflow->node_infos[i].node, &second_type);
+
+ if (first_type != second_type) {
+ return false;
+ }
+
+ switch(first_type) {
+ case MMI_STANDARD_NODE_TYPE_SOURCE:
+ {
+ mmi_standard_node_source_type_e first_source_type;
+ mmi_standard_node_source_type_e second_source_type;
+ mmi_standard_node_get_source_type(first_workflow->node_infos[i].node, &first_source_type);
+ mmi_standard_node_get_source_type(second_workflow->node_infos[i].node, &second_source_type);
+
+ if (first_source_type != second_source_type) {
+ return false;
+ }
+ }
+ break;
+ case MMI_STANDARD_NODE_TYPE_PROCESSOR:
+ {
+ mmi_standard_node_processor_type_e first_processor_type;
+ mmi_standard_node_processor_type_e second_processor_type;
+ mmi_standard_node_get_processor_type(first_workflow->node_infos[i].node, &first_processor_type);
+ mmi_standard_node_get_processor_type(second_workflow->node_infos[i].node, &second_processor_type);
+
+ if (first_processor_type != second_processor_type) {
+ return false;
+ }
+ }
+ break;
+ case MMI_STANDARD_NODE_TYPE_LOGIC:
+ {
+ mmi_standard_node_logic_type_e first_logic_type;
+ mmi_standard_node_logic_type_e second_logic_type;
+ mmi_standard_node_get_logic_type(first_workflow->node_infos[i].node, &first_logic_type);
+ mmi_standard_node_get_logic_type(second_workflow->node_infos[i].node, &second_logic_type);
+
+ if (first_logic_type != second_logic_type) {
+ return false;
+ }
+ }
+ break;
+ default:
+ return false;
+ }
+ }
+
+ if (first_workflow->link_info_count != second_workflow->link_info_count) {
+ return false;
+ }
+
+ for (size_t i = 0; i < first_workflow->link_info_count; i++) {
+ if (strcmp(first_workflow->link_infos[i].from_node_name, second_workflow->link_infos[i].from_node_name) != 0) {
+ return false;
+ }
+ if (strcmp(first_workflow->link_infos[i].from_port_name, second_workflow->link_infos[i].from_port_name) != 0) {
+ return false;
+ }
+ if (strcmp(first_workflow->link_infos[i].to_node_name, second_workflow->link_infos[i].to_node_name) != 0) {
+ return false;
+ }
+ if (strcmp(first_workflow->link_infos[i].to_port_name, second_workflow->link_infos[i].to_port_name) != 0) {
+ return false;
+ }
+ }
+
+ if (first_workflow->attribute_assignment_info_count != second_workflow->attribute_assignment_info_count) {
+ return false;
+ }
+
+ for (size_t i = 0; i < first_workflow->attribute_assignment_info_count; i++) {
+ if (strcmp(first_workflow->attribute_assignment_infos[i].attribute_name, second_workflow->attribute_assignment_infos[i].attribute_name) != 0) {
+ return false;
+ }
+ if (strcmp(first_workflow->attribute_assignment_infos[i].target_node_name, second_workflow->attribute_assignment_infos[i].target_node_name) != 0) {
+ return false;
+ }
+ if (strcmp(first_workflow->attribute_assignment_infos[i].target_attribute_name, second_workflow->attribute_assignment_infos[i].target_attribute_name) != 0) {
+ return false;
+ }
+ }
+
+ if (first_workflow->output_assignment_info_count != second_workflow->output_assignment_info_count) {
+ return false;
+ }
+
+ for (size_t i = 0; i < first_workflow->output_assignment_info_count; i++) {
+ if (strcmp(first_workflow->output_assignment_infos[i].output_name, second_workflow->output_assignment_infos[i].output_name) != 0) {
+ return false;
+ }
+ if (strcmp(first_workflow->output_assignment_infos[i].from_node_name, second_workflow->output_assignment_infos[i].from_node_name) != 0) {
+ return false;
+ }
+ if (strcmp(first_workflow->output_assignment_infos[i].from_port_name, second_workflow->output_assignment_infos[i].from_port_name) != 0) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+TEST_F(MMIWorkflowTest, TestCompareFunction_p1) {
+ mmi_workflow_h workflow = nullptr;
+
+ mmi_workflow_create(&workflow);
+
+ mmi_workflow_set_type(workflow, MMI_STANDARD_WORKFLOW_WAKEUPLESS_COMMAND);
+
+ mmi_node_h node_mic = nullptr;
+ /* FIXME: node should be 'found' instead of 'created' */
+ mmi_standard_node_create_source(MMI_STANDARD_NODE_SOURCE_TYPE_MIC_AMBIENT, &node_mic);
+ mmi_workflow_node_add(workflow, "MIC", node_mic);
+
+ mmi_node_h node_asr = nullptr;
+ mmi_standard_node_create_processor(MMI_STANDARD_NODE_PROCESSOR_TYPE_ASR, &node_asr);
+ mmi_workflow_node_add(workflow, "ASR", node_asr);
+
+ mmi_node_h node_match = nullptr;
+ mmi_standard_node_create_logic(MMI_STANDARD_NODE_LOGIC_TYPE_FIXED_STRING_MATCH, &node_match);
+ mmi_workflow_node_add(workflow, "MATCH", node_match);
+
+ mmi_workflow_link_nodes_by_names(workflow, "MIC", "AUDIO", "ASR", "AUDIO");
+ mmi_workflow_link_nodes_by_names(workflow, "ASR", "FINAL_RESULT", "MATCH", "TEXT");
+
+ mmi_workflow_attribute_assign(workflow, "COMMANDS", "MATCH", "CANDIDATES");
+
+ mmi_workflow_output_assign(workflow, "COMMAND", "MATCH", "MATCHED_CANDIDATE");
+
+ EXPECT_TRUE(compare_workflow_prototype(m_workflow, workflow));
+
+ mmi_node_destroy(node_match);
+ mmi_node_destroy(node_asr);
+ mmi_node_destroy(node_mic);
+
+ mmi_workflow_destroy(workflow);
+}
+
+TEST_F(MMIWorkflowTest, TestCompareFunction_p2) {
+ mmi_workflow_h workflow = nullptr;
+
+ mmi_workflow_clone(m_workflow, &workflow);
+
+ EXPECT_TRUE(compare_workflow_prototype(m_workflow, workflow));
+
+ mmi_workflow_destroy(workflow);
+}
+
+TEST_F(MMIWorkflowTest, TestCompareFunction_n1) {
+ mmi_workflow_h workflow = nullptr;
+
+ mmi_workflow_clone(m_workflow, &workflow);
+
+ mmi_node_h node_regex_match = nullptr;
+ mmi_standard_node_create_logic(MMI_STANDARD_NODE_LOGIC_TYPE_REGEX_STRING_MATCH, &node_regex_match);
+ mmi_workflow_node_add(workflow, "REGEX_MATCH", node_regex_match);
+
+ EXPECT_FALSE(compare_workflow_prototype(m_workflow, workflow));
+
+ mmi_node_destroy(node_regex_match);
+
+ mmi_workflow_destroy(workflow);
+}
+
+TEST_F(MMIWorkflowTest, MMIWorkflowCreateFromScript_p1) {
+ mmi_workflow_h workflow = NULL;
+ const char *script = NULL;
+ int ret = MMI_ERROR_NONE;
+
+ std::string script_data = R"(
+@workflow
+name : WAKEUPLESS_COMMAND
+
+@node-list
+[Source] MIC_AMBIENT as MIC
+[Processor] ASR as ASR
+[Logic] FIXED_STRING_MATCH as MATCH
+
+@link-list
+MIC.AUDIO -> ASR.AUDIO
+ASR.FINAL_RESULT -> MATCH.TEXT
+
+@attribute-list
+MATCH.CANDIDATES as COMMANDS
+
+@output-list
+MATCH.MATCHED_CANDIDATE as COMMAND
+ )";
+
+ std::vector<std::string> lines;
+ std::stringstream ss(script_data);
+ std::string line;
+ while (std::getline(ss, line)) {
+ lines.push_back(line);
+ }
+
+ WorkflowScriptParser parser;
+ parser.parse(lines, &workflow);
+
+ EXPECT_TRUE(compare_workflow_prototype(m_workflow, workflow));
+
+ mmi_workflow_destroy(workflow);
+}
+
+++ /dev/null
-#include "mmi.h"
-#include "mmi-tests.h"
-#include "mmi-ipc.h"
-
-#include <Ecore.h>
-
-void wait_for_connect()
-{
- int timer = 0;
- while (!mmi_ipc_is_connected() && timer < MAX_WAIT_TIME)
- {
- ecore_main_loop_iterate();
- timer++;
- }
-}
\ No newline at end of file
interface mmi {
- void result_cb(int input_event_type, string result_out) delegate;
+ void result_cb(string source_name, bundle data) delegate;
- int register_input_event(int input_event_type, result_cb callback);
-
- int activate_input_event(int input_event_type);
- int deactivate_input_event(int input_event_type);
+ 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_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);
}