Sync internal API behavior with product code
[platform/core/system/libsvi.git] / src / feedback.c
index 5243924..02e083a 100644 (file)
 #include <stdbool.h>
 #include <string.h>
 #include <limits.h>
-#include <vconf.h>
 
 #include "feedback.h"
-#include "common.h"
-#include "log.h"
+#include "feedback-internal.h"
+#include "profiles.h"
 #include "devices.h"
+#include "log.h"
+#include "dbus.h"
 
 #ifndef API
 #define API __attribute__ ((visibility("default")))
 #endif
 
-int callstatus;
+static unsigned int init_cnt;
+static pthread_mutex_t fmutex = PTHREAD_MUTEX_INITIALIZER;
 
-static bool binit;
-
-static void feedback_callstatus_cb(keynode_t *key, void* data)
+//LCOV_EXCL_START Not called Callback
+static int restart_callback()
 {
-       callstatus = vconf_keynode_get_int(key);
-}
+       const struct device_ops *dev;
 
-static feedback_pattern_e get_alert_on_call_key(feedback_pattern_e pattern)
-{
-       switch(pattern) {
-       case FEEDBACK_PATTERN_MESSAGE:
-       case FEEDBACK_PATTERN_EMAIL:
-       case FEEDBACK_PATTERN_WAKEUP:
-       case FEEDBACK_PATTERN_SCHEDULE:
-       case FEEDBACK_PATTERN_TIMER:
-       case FEEDBACK_PATTERN_GENERAL:
-       case FEEDBACK_PATTERN_CHARGERCONN:
-       case FEEDBACK_PATTERN_FULLCHARGED:
-       case FEEDBACK_PATTERN_LOWBATT:
-               return (feedback_pattern_e)(pattern+1);
-       default:
-               break;
-       }
-
-       return pattern;
+       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
 
-API int feedback_initialize()
+API int feedback_initialize(void)
 {
-       if (binit)
-               return FEEDBACK_ERROR_NONE;
+       int ret;
 
-       /* check call status */
-       if (vconf_get_int(VCONFKEY_CALL_STATE, &callstatus) < 0)
-               FEEDBACK_ERROR("vconf_get_int(VCONFKEY_CALL_STATE, &callstatus) ==> FAIL!!");
+       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;
+       }
 
-       /* add watch for status value */
-       vconf_notify_key_changed(VCONFKEY_CALL_STATE, feedback_callstatus_cb, NULL);
+       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();
 
-       binit = true;
+       /* 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)
 {
-       if (!binit)
+       int ret;
+
+       pthread_mutex_lock(&fmutex);
+       if (!init_cnt) {
+               pthread_mutex_unlock(&fmutex);
                return FEEDBACK_ERROR_NOT_INITIALIZED;
+       }
+
+       if (init_cnt-- > 1) {
+               pthread_mutex_unlock(&fmutex);
+               return FEEDBACK_ERROR_NONE;
+       }
 
-       vconf_ignore_key_changed(VCONFKEY_CALL_STATE, feedback_callstatus_cb);
+       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();
 
-       binit = false;
+       /* 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;
+
        /* check initialize */
-       if (!binit) {
-               FEEDBACK_ERROR("Not initialized");
+       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;
-       }
-
-       /* in case of call connected or connecting */
-       if (callstatus != VCONFKEY_CALL_OFF) {
-               pattern = get_alert_on_call_key(pattern);
-               FEEDBACK_LOG("Call status is connected or connecting. pattern changed : %s", str_pattern[pattern]);
-       }
-
+       _D("request all type with pattern %s(%d)", profile->str_pattern(pattern), pattern);
        /* play all device */
-       devices_play(pattern);
+       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;
 }
@@ -129,103 +176,338 @@ API int feedback_play_type(feedback_type_e type, feedback_pattern_e pattern)
        int err;
 
        /* check initialize */
-       if (!binit) {
-               FEEDBACK_ERROR("Not initialized");
+       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 >= FEEDBACK_TYPE_END) {
-               FEEDBACK_ERROR("Invalid parameter : type(%d)", type);
+       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 >= 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;
+       /* 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;
        }
 
-       /* in case of call connected or connecting */
-       if (callstatus != VCONFKEY_CALL_OFF) {
-               pattern = get_alert_on_call_key(pattern);
-               FEEDBACK_LOG("Call status is connected or connecting. pattern changed : %s", str_pattern[pattern]);
+       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_stop(void)
+{
+       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);
+
+       /* 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;
+}
+
+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 (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;
        }
 
        /* play proper device */
        dev = find_device(type);
-       if (dev) {
-               err = dev->play(pattern);
-               if (err < 0)
-                       FEEDBACK_ERROR("fail to play sound");
+       if (!dev) {
+               _E("Not supported device : type(%s)", profile->str_type[type]); //LCOV_EXCL_LINE
+               return FEEDBACK_ERROR_NOT_SUPPORTED;
+       }
+
+       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)
+{
+       feedback_type_e etype;
+       feedback_pattern_e epattern;
+       int type_max;
+       int pattern_max;
+
+       if (!type || !pattern) {
+               _E("Invalid parameter : type(%s), pattern(%s)", type, pattern);
+               return FEEDBACK_ERROR_INVALID_PARAMETER;
+       }
+
+       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;
+       }
+
+       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;
+       }
+
+       return feedback_play_type(etype, epattern);
+}
+
+API int feedback_play_internal(feedback_pattern_internal_e pattern)
 {
-       const struct device_ops *dev;
-       char buf[PATH_MAX] = {0,};
        int err;
 
-       if (path == NULL) {
-               FEEDBACK_ERROR("Invalid parameter : path(NULL)");
+       /* 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;
        }
 
-       if (type <= FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) {
-               FEEDBACK_ERROR("Invalid parameter : type(%d)", type);
+       _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_play_type_internal(feedback_type_e type, feedback_pattern_internal_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);
+
+       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 >= FEEDBACK_PATTERN_END) {
-               FEEDBACK_ERROR("Invalid parameter : pattern(%d)", pattern);
+       if (pattern <= FEEDBACK_PATTERN_INTERNAL_NONE ||
+           pattern >= profile->max_pattern) {
+               _E("Invalid parameter : pattern(%d)", pattern);
                return FEEDBACK_ERROR_INVALID_PARAMETER;
        }
 
-       /* proper device get path */
+       /* play proper device */
        dev = find_device(type);
-       if (dev) {
-               err = dev->get_path(pattern, buf, sizeof(buf));
-               if (err < 0)
-                       return FEEDBACK_ERROR_OPERATION_FAILED;
+       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;
 
-       *path = strdup(buf);
        return FEEDBACK_ERROR_NONE;
 }
 
-API int feedback_set_resource_path(feedback_type_e type, feedback_pattern_e pattern, char *path)
+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;
+       }
+
+       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;
 
-       if (path == NULL) {
-               FEEDBACK_ERROR("Invalid parameter : path(NULL)");
+       /* 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 (type <= FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) {
-               FEEDBACK_ERROR("Invalid parameter : type(%d)", type);
+       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 || pattern >= FEEDBACK_PATTERN_END) {
-               FEEDBACK_ERROR("Invalid parameter : pattern(%d)", pattern);
+       if ((type == FEEDBACK_TYPE_SOUND) && (soundpath == NULL)) {
+               _E("Invalid parameter : sound path(NULL)");
                return FEEDBACK_ERROR_INVALID_PARAMETER;
        }
 
-       /* proper device set path */
+       /* play proper device */
        dev = find_device(type);
-       if (dev) {
-               err = dev->set_path(pattern, path);
-               if (err < 0)
-                       return FEEDBACK_ERROR_OPERATION_FAILED;
+       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;
 }