Sync internal API behavior with product code
[platform/core/system/libsvi.git] / src / feedback.c
index e03c950..02e083a 100644 (file)
 
 
 #include <stdio.h>
+#include <stdbool.h>
 #include <string.h>
+#include <limits.h>
+
 #include "feedback.h"
 #include "feedback-internal.h"
-#include "feedback-log.h"
-
-#define MAX_PATH_LENGTH      256
-#define NOT_ASSIGNED         NULL
+#include "profiles.h"
+#include "devices.h"
+#include "log.h"
+#include "dbus.h"
 
 #ifndef API
 #define API __attribute__ ((visibility("default")))
 #endif
 
-static feedback_h feedback_handle = NOT_ASSIGNED;
+static unsigned int init_cnt;
+static pthread_mutex_t fmutex = PTHREAD_MUTEX_INITIALIZER;
 
-API int feedback_initialize()
+//LCOV_EXCL_START Not called Callback
+static int restart_callback()
 {
-       int err = -1;
+       const struct device_ops *dev;
 
-       if (feedback_handle != NOT_ASSIGNED) {
-               FEEDBACK_LOG("Already initialized");
-               return FEEDBACK_ERROR_NONE;
+       dev = find_device(FEEDBACK_TYPE_VIBRATION);
+       if (!dev) {
+               _E("Not supported device : type(FEEDBACK_TYPE_VIBRATION)"); //LCOV_EXCL_LINE
+               return -1;
        }
+       if (dev->init)
+               dev->init();
+       return 0;
+}
+//LCOV_EXCL_STOP
 
-       err = feedback_init(&feedback_handle);
-       if (FEEDBACK_FAILED(err)) {
-               FEEDBACK_ERROR("feedback_init is failed");
-               return FEEDBACK_ERROR_OPERATION_FAILED;
+API int feedback_initialize(void)
+{
+       int ret;
+
+       pthread_mutex_lock(&fmutex);
+       if (!profile) {
+               _E("there is no valid profile module."); //LCOV_EXCL_LINE
+               pthread_mutex_unlock(&fmutex);
+               return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE System Error
        }
 
+       if (init_cnt++ > 0) {
+               pthread_mutex_unlock(&fmutex);
+               return FEEDBACK_ERROR_NONE;
+       }
+
+       ret = register_signal_handler(restart_callback);
+       if (ret < 0)
+               _E("Fail to register signal handler: %d", ret); //LCOV_EXCL_LINE System Error
+
+       /* initialize device */
+       devices_init();
+
+       /* initialize profile feature */
+       if (profile->init)
+               profile->init();
+
+       pthread_mutex_unlock(&fmutex);
        return FEEDBACK_ERROR_NONE;
 }
 
-API int feedback_deinitialize()
+API int feedback_deinitialize(void)
 {
-       int err = -1;
+       int ret;
 
-       if (feedback_handle == NOT_ASSIGNED) {
-               FEEDBACK_ERROR("Not initialized");
+       pthread_mutex_lock(&fmutex);
+       if (!init_cnt) {
+               pthread_mutex_unlock(&fmutex);
                return FEEDBACK_ERROR_NOT_INITIALIZED;
        }
 
-       err = feedback_fini(feedback_handle);
-       if (FEEDBACK_FAILED(err)) {
-               FEEDBACK_ERROR("feedback_fini is failed");
-               return FEEDBACK_ERROR_OPERATION_FAILED;
+       if (init_cnt-- > 1) {
+               pthread_mutex_unlock(&fmutex);
+               return FEEDBACK_ERROR_NONE;
        }
 
-       feedback_handle = NOT_ASSIGNED;
+       ret = unregister_signal_handler(restart_callback);
+       if (ret < 0)
+               _E("Fail to unregister signal handler: %d", ret); //LCOV_EXCL_LINE System Error
+
+       /* deinitialize device */
+       devices_exit();
+
+       /* deinitialize profile feature */
+       if (profile->exit)
+               profile->exit();
+
+       pthread_mutex_unlock(&fmutex);
        return FEEDBACK_ERROR_NONE;
 }
 
+static feedback_pattern_e check_pattern(feedback_type_e type, feedback_pattern_e pattern, const char *func)
+{
+    feedback_pattern_e switched = pattern;
+    bool result = false;
+
+    if (type < FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END)
+        type = FEEDBACK_TYPE_NONE;
+
+    /* if you need to switch pattern */
+    if (profile->get_switched_pattern)
+        result = profile->get_switched_pattern(pattern, &switched);
+
+    if (pattern != switched && result)
+        _W("pattern is changed : %s %s(%d) -> %s(%d) by %s", //LCOV_EXCL_LINE
+                profile->str_type[type],
+                profile->str_pattern(pattern), pattern , profile->str_pattern(switched), switched, func);
+    else
+        _W("pattern is : %s %s(%d) by %s", //LCOV_EXCL_LINE
+                profile->str_type[type],
+                profile->str_pattern(pattern), pattern, func);
+    return switched;
+}
+
 API int feedback_play(feedback_pattern_e pattern)
 {
-       int err = -1;
+       int err;
 
-       if (feedback_handle == NOT_ASSIGNED) {
-               FEEDBACK_ERROR("Not initialized");
+       /* check initialize */
+       pthread_mutex_lock(&fmutex);
+       if (!init_cnt) {
+               _E("Not initialized"); //LCOV_EXCL_LINE
+               pthread_mutex_unlock(&fmutex);
                return FEEDBACK_ERROR_NOT_INITIALIZED;
        }
+       pthread_mutex_unlock(&fmutex);
 
-       if (pattern < FEEDBACK_PATTERN_NONE || pattern >= FEEDBACK_PATTERN_END) {
-               FEEDBACK_ERROR("Invalid parameter : pattern(%d)", pattern);
+       if (pattern <= FEEDBACK_PATTERN_NONE ||
+           pattern >= profile->max_pattern) {
+               _E("Invalid parameter : pattern(%d)", pattern);
                return FEEDBACK_ERROR_INVALID_PARAMETER;
        }
 
-       if (pattern == FEEDBACK_PATTERN_NONE) {
-               FEEDBACK_LOG("pattern is NONE");
-               return FEEDBACK_ERROR_NONE;
+       _D("request all type with pattern %s(%d)", profile->str_pattern(pattern), pattern);
+       /* play all device */
+       err = devices_play(check_pattern(FEEDBACK_TYPE_NONE, pattern, __func__), false);
+       /**
+        * devices_play() returns error even if all devices are failed.
+        * It means if to play anything is successful,
+        * this function regards as success.
+        */
+       if (err == -ENOTSUP)
+               return FEEDBACK_ERROR_NOT_SUPPORTED;
+       else if (err < 0)
+               return FEEDBACK_ERROR_OPERATION_FAILED;
+
+       return FEEDBACK_ERROR_NONE;
+}
+
+API int feedback_play_type(feedback_type_e type, feedback_pattern_e pattern)
+{
+       const struct device_ops *dev;
+       int err;
+
+       /* check initialize */
+       pthread_mutex_lock(&fmutex);
+       if (!init_cnt) {
+               _E("Not initialized"); //LCOV_EXCL_LINE
+               pthread_mutex_unlock(&fmutex);
+               return FEEDBACK_ERROR_NOT_INITIALIZED;
        }
+       pthread_mutex_unlock(&fmutex);
 
-       err = feedback_play_sound(feedback_handle, pattern);
-       if (FEEDBACK_FAILED(err)) {
-               FEEDBACK_ERROR("feedback_play_sound is failed");
-               return FEEDBACK_ERROR_OPERATION_FAILED;
+       if (type <= FEEDBACK_TYPE_NONE ||
+           type >= profile->max_type) {
+               _E("Invalid parameter : type(%d)", type);
+               return FEEDBACK_ERROR_INVALID_PARAMETER;
        }
 
-       err = feedback_play_vibration(feedback_handle, pattern);
-       if (FEEDBACK_FAILED(err)) {
-               FEEDBACK_ERROR("feedback_play_vibration is failed");
-               return FEEDBACK_ERROR_OPERATION_FAILED;
+       if (pattern <= FEEDBACK_PATTERN_NONE ||
+           pattern >= profile->max_pattern) {
+               _E("Invalid parameter : pattern(%d)", pattern);
+               return FEEDBACK_ERROR_INVALID_PARAMETER;
+       }
+
+       /* play proper device */
+       dev = find_device(type);
+       if (!dev) {
+               _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE
+               return FEEDBACK_ERROR_NOT_SUPPORTED;
        }
 
+       err = dev->play(check_pattern(type, pattern, __func__), false);
+       if (err == -ENOTSUP)
+               return FEEDBACK_ERROR_NOT_SUPPORTED;
+       else if (err == -ECOMM || err == -EACCES)
+               return FEEDBACK_ERROR_PERMISSION_DENIED;
+       else if (err < 0)
+               return FEEDBACK_ERROR_OPERATION_FAILED;
+
        return FEEDBACK_ERROR_NONE;
 }
 
-API int feedback_play_type(feedback_type_e type, feedback_pattern_e pattern)
+API int feedback_stop(void)
 {
-       int err = -1;
+       int err;
 
-       if (feedback_handle == NOT_ASSIGNED) {
-               FEEDBACK_ERROR("Not initialized");
+       /* check initialize */
+       pthread_mutex_lock(&fmutex);
+       if (!init_cnt) {
+               _E("Not initialized"); //LCOV_EXCL_LINE
+               pthread_mutex_unlock(&fmutex);
                return FEEDBACK_ERROR_NOT_INITIALIZED;
        }
+       pthread_mutex_unlock(&fmutex);
+
+       /* stop all device */
+       err = devices_stop();
+       if (err == -ENOTSUP)
+               return FEEDBACK_ERROR_NOT_SUPPORTED;
+       else if (err == -ECOMM || err == -EACCES)
+               return FEEDBACK_ERROR_PERMISSION_DENIED;
+       else if (err < 0)
+               return FEEDBACK_ERROR_OPERATION_FAILED;
+
+       return FEEDBACK_ERROR_NONE;
+}
 
-       if (type <= FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) {
-               FEEDBACK_ERROR("Invalid parameter : type(%d)", type);
+API int feedback_is_supported_pattern(feedback_type_e type, feedback_pattern_e pattern, bool *status)
+{
+       const struct device_ops *dev;
+       bool supported;
+       int err;
+
+       /* check initialize */
+       pthread_mutex_lock(&fmutex);
+       if (!init_cnt) {
+               _E("Not initialized"); //LCOV_EXCL_LINE
+               pthread_mutex_unlock(&fmutex);
+               return FEEDBACK_ERROR_NOT_INITIALIZED;
+       }
+       pthread_mutex_unlock(&fmutex);
+
+       if (!status) {
+               _E("Invalid parameter : status(NULL)");
                return FEEDBACK_ERROR_INVALID_PARAMETER;
        }
 
-       if (pattern < FEEDBACK_PATTERN_NONE || pattern >= FEEDBACK_PATTERN_END) {
-               FEEDBACK_ERROR("Invalid parameter : pattern(%d)", pattern);
+       if (type <= FEEDBACK_TYPE_NONE ||
+           type >= profile->max_type) {
+               _E("Invalid parameter : type(%d)", type);
                return FEEDBACK_ERROR_INVALID_PARAMETER;
        }
 
-       if (pattern == FEEDBACK_PATTERN_NONE) {
-               FEEDBACK_LOG("pattern is NONE");
-               return FEEDBACK_ERROR_NONE;
+       if (pattern <= FEEDBACK_PATTERN_NONE ||
+           pattern >= profile->max_pattern) {
+               _E("Invalid parameter : pattern(%d)", pattern);
+               return FEEDBACK_ERROR_INVALID_PARAMETER;
        }
 
-       switch(type) {
-               case FEEDBACK_TYPE_SOUND:
-                       err = feedback_play_sound(feedback_handle, pattern);
-                       break;
-               case FEEDBACK_TYPE_VIBRATION:
-                       err = feedback_play_vibration(feedback_handle, pattern);
-                       break;
-               default:
-                       FEEDBACK_ERROR("Invalid parameter : type(%d)", type);
-               return FEEDBACK_ERROR_INVALID_PARAMETER;
+       /* play proper device */
+       dev = find_device(type);
+       if (!dev) {
+               _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE
+               return FEEDBACK_ERROR_NOT_SUPPORTED;
        }
 
-       if (FEEDBACK_FAILED(err)) {
-               FEEDBACK_ERROR("feedback_play(type:%d) is failed", type);
+       err = dev->is_supported(check_pattern(type, pattern, __func__), &supported);
+       if (err == -ENOTSUP)
+               return FEEDBACK_ERROR_NOT_SUPPORTED; //LCOV_EXCL_LINE System Error
+       else if (err == -ECOMM || err == -EACCES)
+               return FEEDBACK_ERROR_PERMISSION_DENIED; //LCOV_EXCL_LINE System Error
+       else if (err < 0) {
+               _E("fail to invoke is_supported() : pattern(%d)", pattern); //LCOV_EXCL_LINE
                return FEEDBACK_ERROR_OPERATION_FAILED;
        }
 
+       *status = supported;
+
        return FEEDBACK_ERROR_NONE;
 }
 
-API int feedback_get_resource_path(feedback_type_e type, feedback_pattern_e pattern, char** path)
+/* Internal APIs */
+API int feedback_play_type_by_name(char *type, char *pattern)
 {
-       int err = -1;
-       char buf[MAX_PATH_LENGTH] = {0,};
+       feedback_type_e etype;
+       feedback_pattern_e epattern;
+       int type_max;
+       int pattern_max;
 
-       if (path == NULL) {
-               FEEDBACK_ERROR("Invalid parameter : path(NULL)");
+       if (!type || !pattern) {
+               _E("Invalid parameter : type(%s), pattern(%s)", type, pattern);
                return FEEDBACK_ERROR_INVALID_PARAMETER;
        }
 
-       if (type <= FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) {
-               FEEDBACK_ERROR("Invalid parameter : type(%d)", type);
+       type_max = profile->max_type;
+       for (etype = 0; etype < type_max; ++etype) {
+               if (!strncmp(type, profile->str_type[etype], strlen(type)))
+                       break;
+       }
+
+       if (etype == type_max) {
+               _E("Invalid parameter : type(%s)", type);
                return FEEDBACK_ERROR_INVALID_PARAMETER;
        }
 
-       if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= FEEDBACK_PATTERN_END) {
-               FEEDBACK_ERROR("Invalid parameter : pattern(%d)", pattern);
+       pattern_max = profile->max_pattern;
+       for (epattern = 0; epattern < pattern_max; ++epattern) {
+               if (!strncmp(pattern, profile->str_pattern(epattern), strlen(pattern)))
+                       break;
+       }
+
+       if (epattern == pattern_max) {
+               _E("Invalid parameter : pattern(%s)", pattern);
                return FEEDBACK_ERROR_INVALID_PARAMETER;
        }
 
-       err = feedback_get_path(type, pattern, buf, MAX_PATH_LENGTH);
-       if (FEEDBACK_FAILED(err)) {
-               FEEDBACK_ERROR("feedback_get_path is failed");
-               return FEEDBACK_ERROR_OPERATION_FAILED;
+       return feedback_play_type(etype, epattern);
+}
+
+API int feedback_play_internal(feedback_pattern_internal_e pattern)
+{
+       int err;
+
+       /* check initialize */
+       pthread_mutex_lock(&fmutex);
+       if (!init_cnt) {
+               _E("Not initialized"); //LCOV_EXCL_LINE
+               pthread_mutex_unlock(&fmutex);
+               return FEEDBACK_ERROR_NOT_INITIALIZED;
+       }
+       pthread_mutex_unlock(&fmutex);
+
+       if (pattern <= FEEDBACK_PATTERN_INTERNAL_NONE ||
+           pattern >= profile->max_pattern) {
+               _E("Invalid parameter : pattern(%d)", pattern);
+               return FEEDBACK_ERROR_INVALID_PARAMETER;
        }
 
-       *path = strdup(buf);
+       _D("request all type with pattern %s(%d)", profile->str_pattern(pattern), pattern);
+       /* play all device */
+       err = devices_play(check_pattern(FEEDBACK_TYPE_NONE, pattern, __func__), true);
+       /**
+        * devices_play() returns error even if all devices are failed.
+        * It means if to play anything is successful,
+        * this function regards as success.
+        */
+       if (err == -ENOTSUP)
+               return FEEDBACK_ERROR_NOT_SUPPORTED;
+       else if (err < 0)
+               return FEEDBACK_ERROR_OPERATION_FAILED;
 
        return FEEDBACK_ERROR_NONE;
 }
 
-API int feedback_set_resource_path(feedback_type_e type, feedback_pattern_e pattern, char* path)
+API int feedback_play_type_internal(feedback_type_e type, feedback_pattern_internal_e pattern)
 {
-       int err = -1;
+       const struct device_ops *dev;
+       int err;
+
+       /* check initialize */
+       pthread_mutex_lock(&fmutex);
+       if (!init_cnt) {
+               _E("Not initialized"); //LCOV_EXCL_LINE
+               pthread_mutex_unlock(&fmutex);
+               return FEEDBACK_ERROR_NOT_INITIALIZED;
+       }
+       pthread_mutex_unlock(&fmutex);
 
-       if (path == NULL) {
-               FEEDBACK_ERROR("Invalid parameter : path(NULL)");
+       if (type <= FEEDBACK_TYPE_NONE ||
+           type >= profile->max_type) {
+               _E("Invalid parameter : type(%d)", type);
                return FEEDBACK_ERROR_INVALID_PARAMETER;
        }
 
-       if (type <= FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) {
-               FEEDBACK_ERROR("Invalid parameter : type(%d)", type);
+       if (pattern <= FEEDBACK_PATTERN_INTERNAL_NONE ||
+           pattern >= profile->max_pattern) {
+               _E("Invalid parameter : pattern(%d)", pattern);
                return FEEDBACK_ERROR_INVALID_PARAMETER;
        }
 
-       if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= FEEDBACK_PATTERN_END) {
-               FEEDBACK_ERROR("Invalid parameter : pattern(%d)", pattern);
+       /* play proper device */
+       dev = find_device(type);
+       if (!dev) {
+               _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE
+               return FEEDBACK_ERROR_NOT_SUPPORTED;
+       }
+       _D("request type %s with pattern %s(%d)", profile->str_type[type], profile->str_pattern(pattern), pattern);
+       err = dev->play(check_pattern(type, pattern, __func__), true);
+       if (err == -ENOTSUP)
+               return FEEDBACK_ERROR_NOT_SUPPORTED;
+       else if (err == -ECOMM || err == -EACCES)
+               return FEEDBACK_ERROR_PERMISSION_DENIED;
+       else if (err < 0)
+               return FEEDBACK_ERROR_OPERATION_FAILED;
+
+       return FEEDBACK_ERROR_NONE;
+}
+
+API int feedback_play_soundpath_internal(feedback_pattern_internal_e internal_pattern, const char *soundpath)
+{
+       int err;
+       feedback_pattern_e pattern = (feedback_pattern_e)internal_pattern;
+
+       /* check initialize */
+       pthread_mutex_lock(&fmutex);
+       if (!init_cnt) {
+               _E("Not initialized"); //LCOV_EXCL_LINE
+               pthread_mutex_unlock(&fmutex);
+               return FEEDBACK_ERROR_NOT_INITIALIZED;
+       }
+       pthread_mutex_unlock(&fmutex);
+
+       if (pattern <= FEEDBACK_PATTERN_NONE ||
+               pattern >= profile->max_pattern) {
+               _E("Invalid parameter : pattern(%d)", pattern);
                return FEEDBACK_ERROR_INVALID_PARAMETER;
        }
 
-       err = feedback_set_path(type, pattern, path);
-       if (FEEDBACK_FAILED(err)) {
-               FEEDBACK_ERROR("feedback_set_path is failed");
+       if (!soundpath) {
+               _E("Invalid parameter : pattern path(NULL)");
+               return FEEDBACK_ERROR_INVALID_PARAMETER;
+       }
+
+       _D("request all type with pattern %s(%d), soundpath %s", profile->str_pattern(pattern), pattern, soundpath);
+       /* play all device */
+       err = devices_play_soundpath(check_pattern(FEEDBACK_TYPE_NONE, pattern, __func__), soundpath, true);
+       /**
+        * devices_play() returns error even if all devices are failed.
+        * It means if to play anything is successful,
+        * this function regards as success.
+        */
+       if (err == -ENOTSUP)
+               return FEEDBACK_ERROR_NOT_SUPPORTED;
+       else if (err < 0)
                return FEEDBACK_ERROR_OPERATION_FAILED;
+
+       return FEEDBACK_ERROR_NONE;
+}
+
+API int feedback_play_type_soundpath_internal(feedback_type_e type, feedback_pattern_internal_e internal_pattern, const char *soundpath)
+{
+       const struct device_ops *dev;
+       int err;
+       feedback_pattern_e pattern = (feedback_pattern_e)internal_pattern;
+
+       /* check initialize */
+       pthread_mutex_lock(&fmutex);
+       if (!init_cnt) {
+               _E("Not initialized"); //LCOV_EXCL_LINE
+               pthread_mutex_unlock(&fmutex);
+               return FEEDBACK_ERROR_NOT_INITIALIZED;
        }
+       pthread_mutex_unlock(&fmutex);
+
+       if (type <= FEEDBACK_TYPE_NONE ||
+           type >= profile->max_type) {
+               _E("Invalid parameter : type(%d)", type);
+               return FEEDBACK_ERROR_INVALID_PARAMETER;
+       }
+
+       if (pattern <= FEEDBACK_PATTERN_NONE ||
+           pattern >= profile->max_pattern) {
+               _E("Invalid parameter : pattern(%d)", pattern);
+               return FEEDBACK_ERROR_INVALID_PARAMETER;
+       }
+
+       if ((type == FEEDBACK_TYPE_SOUND) && (soundpath == NULL)) {
+               _E("Invalid parameter : sound path(NULL)");
+               return FEEDBACK_ERROR_INVALID_PARAMETER;
+       }
+
+       /* play proper device */
+       dev = find_device(type);
+       if (!dev) {
+               _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE
+               return FEEDBACK_ERROR_NOT_SUPPORTED;
+       }
+       _D("request type %s with pattern(%s), soundpath(%s)", profile->str_type[type], profile->str_pattern(pattern), soundpath?soundpath:"NULL");
+       if (type == FEEDBACK_TYPE_SOUND) {
+               if (dev->play_path)
+                       err = dev->play_path(check_pattern(type, pattern, __func__), soundpath, true);
+               else
+                       err = -ENOTSUP; //LCOV_EXCL_LINE
+       } else {
+               if (dev->play)
+                       err = dev->play(check_pattern(type, pattern, __func__), true);
+               else
+                       err = -ENOTSUP; //LCOV_EXCL_LINE
+       }
+
+       if (err == -ENOTSUP)
+               return FEEDBACK_ERROR_NOT_SUPPORTED;
+       else if (err == -ECOMM || err == -EACCES)
+               return FEEDBACK_ERROR_PERMISSION_DENIED;
+       else if (err < 0)
+               return FEEDBACK_ERROR_OPERATION_FAILED;
 
        return FEEDBACK_ERROR_NONE;
 }