tizen 2.4 release
[framework/system/libfeedback.git] / src / vibrator.c
index 90464b3..5632ad7 100644 (file)
@@ -17,6 +17,7 @@
 
 
 #include <stdio.h>
+#include <stdlib.h>
 #include <stdbool.h>
 #include <string.h>
 #include <errno.h>
 #include <sys/stat.h>
 
 #include "feedback-ids.h"
-#include "common.h"
-#include "log.h"
+#include "profiles.h"
+#include "parser.h"
 #include "devices.h"
-#include "xmlparser.h"
+#include "log.h"
 #include "dbus.h"
-
-#define DEFAULT_VIB_LEVEL                      3
-#define HAPTIC_FEEDBACK_STEP           20 /**< feedback max / slider step */
+#ifdef MOBILE
+#include "feedback-ids-mobile.h"
+#endif
+#ifdef WEARABLE
+#include "feedback-ids-wearable.h"
+#endif
 
 #define HAPTIC_DEVICE                          0
 
-enum haptic_priority
-{
+enum haptic_priority {
        HAPTIC_PRIORITY_MIN = 0,
        HAPTIC_PRIORITY_MIDDLE,
        HAPTIC_PRIORITY_HIGH,
 };
 
-enum haptic_iteration
-{
+enum haptic_iteration {
        HAPTIC_ITERATION_ONCE = 1,
        HAPTIC_ITERATION_INFINITE = 256,
 };
 
-#define VIBRATION_XML                          "/usr/share/feedback/vibration.xml"
+#define VIBRATION_CONF_FILE         "/usr/share/feedback/vibration.conf"
 
-#define METHOD_OPEN                                    "OpenDevice"
-#define METHOD_CLOSE                           "CloseDevice"
-#define METHOD_VIBRATE_BUFFER          "VibrateBuffer"
-#define METHOD_STOP                                    "StopDevice"
+#define METHOD_OPEN                 "OpenDevice"
+#define METHOD_CLOSE                "CloseDevice"
+#define METHOD_VIBRATE_MONOTONE     "VibrateMonotone"
+#define METHOD_VIBRATE_BUFFER       "VibrateBuffer"
+#define METHOD_STOP                 "StopDevice"
 
-static int vibstatus;
-static int noti_vibstatus;
-static int vib_level;
-static int noti_level;
-static int feedbackstatus;
+#define DEFAULT_DURATION            100
+#define SIP_DURATION                60
 
+static int vibstatus;
 static unsigned int v_handle;
-static xmlDocPtr v_doc;
+static struct feedback_config_info vib_info = {
+       .name = "Vibration",
+};
+
+static char *get_data(feedback_pattern_e pattern)
+{
+       char *data;
+
+       if (pattern <= FEEDBACK_PATTERN_NONE ||
+           pattern >= profile->max_pattern)
+               return NULL;
+
+       if (vib_info.data[pattern].changed)
+               data = vib_info.data[pattern].changed;
+       else
+               data = vib_info.data[pattern].origin;
+
+       return data;
+}
 
-static char haptic_file[FEEDBACK_PATTERN_END][NAME_MAX];
+inline int is_vibration_mode(void)
+{
+       return vibstatus;
+}
 
 static int haptic_open(void)
 {
@@ -112,7 +134,7 @@ static int haptic_vibrate_buffer(unsigned int handle,
        arr[0] = buf_handle;
        bytes.size = size;
        bytes.data = buffer;
-       arr[2] = (char*)&bytes;
+       arr[2] = (char *)&bytes;
        snprintf(buf_iteration, sizeof(buf_iteration), "%d", iteration);
        arr[3] = buf_iteration;
        snprintf(buf_feedback, sizeof(buf_feedback), "%d", feedback);
@@ -125,6 +147,31 @@ static int haptic_vibrate_buffer(unsigned int handle,
                        "uayiii", arr);
 }
 
+static int haptic_vibrate_monotone(unsigned int handle,
+                                                               int duration,
+                                                               int feedback,
+                                                               int priority)
+{
+       char *arr[4];
+       char buf_handle[32];
+       char buf_duration[32];
+       char buf_feedback[32];
+       char buf_priority[32];
+
+       snprintf(buf_handle, sizeof(buf_handle), "%u", handle);
+       arr[0] = buf_handle;
+       snprintf(buf_duration, sizeof(buf_duration), "%d", duration);
+       arr[1] = buf_duration;
+       snprintf(buf_feedback, sizeof(buf_feedback), "%d", feedback);
+       arr[2] = buf_feedback;
+       snprintf(buf_priority, sizeof(buf_priority), "%d", priority);
+       arr[3] = buf_priority;
+
+       return dbus_method_sync(DEVICED_BUS_NAME, DEVICED_PATH_HAPTIC,
+                       DEVICED_INTERFACE_HAPTIC, METHOD_VIBRATE_MONOTONE,
+                       "uiii", arr);
+}
+
 static int haptic_vibrate_stop(unsigned int handle)
 {
        char *arr[1];
@@ -138,7 +185,7 @@ static int haptic_vibrate_stop(unsigned int handle)
                        "u", arr);
 }
 
-static unsigned charconvert_file_to_buffer(const char *file_name, int *size)
+static unsigned char *convert_file_to_buffer(const char *file_name, int *size)
 {
        FILE *pf;
        long file_size;
@@ -150,7 +197,7 @@ static unsigned char* convert_file_to_buffer(const char *file_name, int *size)
        /* Get File Stream Pointer */
        pf = fopen(file_name, "rb");
        if (!pf) {
-               _E("fopen failed : %d", errno);
+               _E("fopen failed : %s", strerror(errno));
                return NULL;
        }
 
@@ -164,7 +211,7 @@ static unsigned char* convert_file_to_buffer(const char *file_name, int *size)
        if (file_size < 0)
                goto error;
 
-       pdata = (unsigned char*)malloc(file_size);
+       pdata = (unsigned char *)malloc(file_size);
        if (!pdata)
                goto error;
 
@@ -181,30 +228,10 @@ err_free:
 error:
        fclose(pf);
 
-       _E("failed to convert file to buffer (%d)", errno);
+       _E("failed to convert file to buffer (%s)", strerror(errno));
        return NULL;
 }
 
-static void feedback_noti_vibstatus_cb(keynode_t *key, void* data)
-{
-       noti_vibstatus = vconf_keynode_get_bool(key);
-}
-
-static void feedback_vib_cb(keynode_t *key, void* data)
-{
-       vib_level = vconf_keynode_get_int(key);
-}
-
-static void feedback_noti_cb(keynode_t *key, void* data)
-{
-       noti_level = vconf_keynode_get_int(key);
-}
-
-static void feedback_feedbackstatus_cb(keynode_t *key, void* data)
-{
-       feedbackstatus = vconf_keynode_get_bool(key);
-}
-
 static int get_priority(feedback_pattern_e pattern)
 {
        if (pattern >= FEEDBACK_PATTERN_TAP && pattern <= FEEDBACK_PATTERN_HW_HOLD)
@@ -213,271 +240,130 @@ static int get_priority(feedback_pattern_e pattern)
        return HAPTIC_PRIORITY_MIDDLE;
 }
 
-static int get_haptic_level(feedback_pattern_e pattern)
+static int get_duration(feedback_pattern_e pattern)
 {
-       int level;
-
-       if (pattern >= FEEDBACK_PATTERN_MESSAGE && pattern <= FEEDBACK_PATTERN_SMART_ALERT)
-               level = noti_level * HAPTIC_FEEDBACK_STEP;
-       else
-               level = vib_level * HAPTIC_FEEDBACK_STEP;
-
-       _D("Call status : %d, pattern : %s, level : %d", callstatus, str_pattern[pattern], level);
-       if (callstatus == VCONFKEY_CALL_VOICE_ACTIVE
-           || callstatus == VCONFKEY_CALL_VIDEO_ACTIVE) {
-               // if call status is ON, vibration magnitude is 20%
-               level = 20;
-               _D("level changed : %d", level);
-       }
-
-       return level;
-}
-
-static bool get_always_alert_case(feedback_pattern_e pattern)
-{
-       switch (pattern) {
-       case FEEDBACK_PATTERN_KEY0 ... FEEDBACK_PATTERN_KEY_BACK:
-       case FEEDBACK_PATTERN_HOLD:
-               if (feedbackstatus)
-                       return true;
-               break;
-       case FEEDBACK_PATTERN_SIP:
-       case FEEDBACK_PATTERN_SIP_BACKSPACE:
-       case FEEDBACK_PATTERN_SIP_FUNCTION:
-       case FEEDBACK_PATTERN_SIP_FJKEY:
-               return true;
-       case FEEDBACK_PATTERN_TIMER:
-       case FEEDBACK_PATTERN_TIMER_ON_CALL:
-       case FEEDBACK_PATTERN_WAKEUP:
-       case FEEDBACK_PATTERN_WAKEUP_ON_CALL:
-               return true;
-       case FEEDBACK_PATTERN_MESSAGE_ON_CALL:
-       case FEEDBACK_PATTERN_EMAIL_ON_CALL:
-       case FEEDBACK_PATTERN_GENERAL_ON_CALL:
-               if (alert_callstatus)
-                       return true;
-               break;
-       case FEEDBACK_PATTERN_MESSAGE:
-       case FEEDBACK_PATTERN_EMAIL:
-               if (noti_vibstatus)
-                       return true;
-               break;
-       case FEEDBACK_PATTERN_3RD_APPLICATION:
-       case FEEDBACK_PATTERN_SMART_ALERT:
-       case FEEDBACK_PATTERN_SEND_SOS_MESSAGE:
-       case FEEDBACK_PATTERN_END_SOS_MESSAGE:
-       case FEEDBACK_PATTERN_CMAS:
-       case FEEDBACK_PATTERN_OUTGOING_CALL:
-       case FEEDBACK_PATTERN_MMS:
-       case FEEDBACK_PATTERN_HOURLY_ALERT:
-               return true;
-       case FEEDBACK_PATTERN_SPEED_UP:
-       case FEEDBACK_PATTERN_SLOW_DOWN:
-       case FEEDBACK_PATTERN_KEEP_THIS_PACE:
-       case FEEDBACK_PATTERN_GOAL_ACHIEVED:
-       case FEEDBACK_PATTERN_EXERCISE_COUNT:
-       case FEEDBACK_PATTERN_START_CUE:
-               /* except mute case */
-               if (is_sound_mode() ||  vibstatus)
-                       return true;
-               break;
-       case FEEDBACK_PATTERN_CHARGERCONN_ON_CALL:
-       case FEEDBACK_PATTERN_CHARGING_ERROR_ON_CALL:
-       case FEEDBACK_PATTERN_LOWBATT_ON_CALL:
-               /* no matter sound profile */
-               return true;
-       default:
-               break;
-       }
-       return false;
-}
-
-static bool get_always_off_case(feedback_pattern_e pattern)
-{
-       switch (pattern) {
-       case FEEDBACK_PATTERN_KEY0 ... FEEDBACK_PATTERN_KEY_BACK:
-       case FEEDBACK_PATTERN_HOLD:
-               if (!feedbackstatus)
-                       return true;
-               break;
-       default:
-               break;
-       }
-       return false;
-}
-
-static int get_xml_data(xmlDocPtr doc, feedback_pattern_e pattern, struct xmlData **data)
-{
-       xmlNodePtr cur;
-       struct xmlData *retData;
-
-       cur = xml_find(doc, VIBRATION_STR, (const xmlChar*)str_pattern[pattern]);
-       /* This pattern does not have sound file to play */
-       if (cur == NULL)
-               return -ENOENT;
-
-       retData = xml_parse(doc, cur);
-       if (retData == NULL) {
-               _E("xml_parse fail");
-               return -EPERM;
-       }
-
-       *data = retData;
-       return 0;
-}
-
-static void release_xml_data(struct xmlData *data)
-{
-       if (data == NULL)
-               return;
-
-       xml_free(data);
+       if (pattern == FEEDBACK_PATTERN_SIP)
+               return SIP_DURATION;
+#ifdef MOBILE
+       if (pattern == (feedback_pattern_e)FEEDBACK_PATTERN_MOBILE_SIP_BACKSPACE)
+               return SIP_DURATION;
+#endif
+#ifdef WEARABLE
+       if (pattern == (feedback_pattern_e)FEEDBACK_PATTERN_WEARABLE_SIP_BACKSPACE)
+               return SIP_DURATION;
+#endif
+       return DEFAULT_DURATION;
 }
 
 static void vibrator_init(void)
 {
        int ret;
 
-       /* xml Init */
-       v_doc = xml_open(VIBRATION_XML);
-       if (v_doc == NULL) {
-               _E("xml_open(%s) fail", VIBRATION_XML);
-               return;
-       }
-
        /* Vibration Init */
        ret = haptic_open();
        if (ret < 0) {
                _E("haptic_open ==> FAIL!! : %d", ret);
-               xml_close(v_doc);
-               v_doc = NULL;
+               v_handle = -ENOTSUP;
                return;
        }
 
        /* Set vibration handle */
        v_handle = (unsigned int)ret;
 
-       /* check vibration status */
-       if (vconf_get_bool(VCONFKEY_SETAPPL_VIBRATE_WHEN_NOTIFICATION_BOOL, &noti_vibstatus) < 0)
-               _W("VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL ==> FAIL!!");
-
-       /* check vib_level */
-       if (vconf_get_int(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, &vib_level) < 0)
-               _W("VCONFKEY_FEEDBACK_VIBRATION_LEVEL_INT ==> FAIL!!");
-
-       /* check noti_level */
-       if (vconf_get_int(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, &noti_level) < 0)
-               _W("VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT ==> FAIL!!");
-
-       /* feedback Init */
-       if(vconf_get_bool(VCONFKEY_SETAPPL_HAPTIC_FEEDBACK_STATUS_BOOL, &feedbackstatus) < 0)
-               _W("VCONFKEY_SETAPPL_HAPTIC_FEEDBACK_STATUS_BOOL ==> FAIL!!");
-
-       /* add watch for status value */
-       vconf_notify_key_changed(VCONFKEY_SETAPPL_VIBRATE_WHEN_NOTIFICATION_BOOL, feedback_noti_vibstatus_cb, NULL);
-       vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, feedback_vib_cb, NULL);
-       vconf_notify_key_changed(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, feedback_noti_cb, NULL);
-       vconf_notify_key_changed(VCONFKEY_SETAPPL_HAPTIC_FEEDBACK_STATUS_BOOL, feedback_feedbackstatus_cb, NULL);
+       /* get vibration data */
+       feedback_load_config(VIBRATION_CONF_FILE, &vib_info);
 }
 
 static void vibrator_exit(void)
 {
        int ret;
 
-       /* remove watch */
-       vconf_ignore_key_changed(VCONFKEY_SETAPPL_VIBRATE_WHEN_NOTIFICATION_BOOL, feedback_noti_vibstatus_cb);
-       vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, feedback_vib_cb);
-       vconf_ignore_key_changed(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, feedback_noti_cb);
-       vconf_ignore_key_changed(VCONFKEY_SETAPPL_HAPTIC_FEEDBACK_STATUS_BOOL, feedback_feedbackstatus_cb);
-
-       if (v_handle) {
+       if (v_handle > 0) {
                ret = haptic_close(v_handle);
                if (ret < 0)
                        _E("haptic_close is failed : %d", ret);
                v_handle = 0;
        }
 
-       if (v_doc) {
-               xml_close(v_doc);
-               v_doc = NULL;
-       }
+       /* free vibration data */
+       feedback_free_config(&vib_info);
 }
 
 static int vibrator_play(feedback_pattern_e pattern)
 {
-       int ret, size;
-       struct xmlData *data;
-       char *path;
-       unsigned char *buf;
+       struct stat buf;
+       char *data;
+       unsigned char *pbuf;
+       int size;
+       int ret;
+       int level;
+       int duration;
 
-       if (!v_handle || !v_doc) {
+       if (!v_handle) {
                _E("Not initialize");
                return -EPERM;
        }
 
+       if (v_handle == -ENOTSUP) {
+               _E("Not supported vibration");
+               return -ENOTSUP;
+       }
+
        if (vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &vibstatus) < 0) {
                _D("fail to get vibration status, will work as turning off");
                vibstatus = 0;
        }
 
-       if (vibstatus == 0 && !get_always_alert_case(pattern))  {
+       if (vibstatus == 0 && profile->get_always_alert_case &&
+           !profile->get_always_alert_case(FEEDBACK_TYPE_VIBRATION, pattern))  {
                _D("Vibration condition is OFF (vibstatus : %d)", vibstatus);
                return 0;
        }
 
-       if (vibstatus && get_always_off_case(pattern)) {
+       if (vibstatus && profile->get_always_off_case &&
+           profile->get_always_off_case(FEEDBACK_TYPE_VIBRATION, pattern)) {
                _D("Vibration always off condition");
                return 0;
        }
 
-       /* if there is a file path user defined */
-       path = haptic_file[pattern];
-       if (*path) {
-               buf = convert_file_to_buffer(path, &size);
-               if (!buf) {
-                       _E("convert_file_to_buffer is failed");
-                       return -EPERM;
-               }
-
-               ret = haptic_vibrate_buffer(v_handle, buf, size, HAPTIC_ITERATION_ONCE,
-                               get_haptic_level(pattern), get_priority(pattern));
-               if (ret < 0) {
-                       _E("haptic_vibrate_buffer is failed");
-                       free(buf);
-                       return -EPERM;
-               }
-
-               free(buf);
-               return 0;
-       }
+       if (profile->get_strength_type)
+               level = profile->get_strength_type(FEEDBACK_TYPE_VIBRATION, pattern);
+       else
+               level = DEFAULT_VIB_LEVEL * HAPTIC_FEEDBACK_STEP;
 
-       ret = get_xml_data(v_doc, pattern, &data);
-       if (ret == -ENOENT) {
-               _D("No vibration case(%s)", str_pattern[pattern]);
-               return 0;
+       /* get vibration data */
+       data = get_data(pattern);
+       if (!data) {
+               _E("Not supported vibration pattern");
+               return -ENOTSUP;
        }
 
-       if (ret < 0) {
-               _E("get_xml_data fail");
-               return -EPERM;
-       }
+       /* if it has a file path */
+       if (!stat(data, &buf)) {
+               pbuf = convert_file_to_buffer(data, &size);
+               if (!pbuf) {
+                       _E("fail to convert file to buffer");
+                       return -EPERM;
+               }
 
-       if (data->data == NULL) {
-               _D("No vibration case(%s)", str_pattern[pattern]);
-               release_xml_data(data);
-               return 0;
+               ret = haptic_vibrate_buffer(v_handle, pbuf, size,
+                               HAPTIC_ITERATION_ONCE,
+                               level, get_priority(pattern));
+               free(pbuf);
+       } else {
+               duration = get_duration(pattern);
+               ret = haptic_vibrate_monotone(v_handle, duration,
+                               level, get_priority(pattern));
        }
 
-       /* play haptic buffer */
-       ret = haptic_vibrate_buffer(v_handle, (unsigned char*)data->data, data->size, HAPTIC_ITERATION_ONCE,
-                                       get_haptic_level(pattern), get_priority(pattern));
        if (ret < 0) {
-               _E("haptic_vibrate_buffer is failed");
-               release_xml_data(data);
+               _E("fail to play vibration");
+               if (ret == -ECOMM)
+                       return ret;
                return -EPERM;
        }
 
-       release_xml_data(data);
+       _D("Play success! Data is %s", data);
        return 0;
 }
 
@@ -485,70 +371,124 @@ static int vibrator_stop(void)
 {
        int ret;
 
-       if (!v_handle || !v_doc) {
+       if (!v_handle) {
                _E("Not initialize");
                return -EPERM;
        }
 
+       if (v_handle == -ENOTSUP) {
+               _E("Not supported vibration");
+               return -ENOTSUP;
+       }
+
        /* stop haptic device */
        ret = haptic_vibrate_stop(v_handle);
        if (ret < 0) {
                _E("haptic_vibrate_stop is failed");
+               if (ret == -ECOMM)
+                       return ret;
                return -EPERM;
        }
 
        return 0;
 }
 
-static int vibrator_get_path(feedback_pattern_e pattern, char *buf, unsigned int buflen)
+static int vibrator_is_supported(int pattern, bool *supported)
 {
-       const char *cur_path;
+       char *data;
+       bool ret = true;
 
-       assert(buf != NULL && buflen > 0);
+       if (!supported) {
+               _E("Invalid parameter : supported(NULL)");
+               return -EINVAL;
+       }
 
-       cur_path = haptic_file[pattern];
-       if (*cur_path) {
-               _E("This pattern(%s) in vibrator type is not supported to play", str_pattern[pattern]);
-               snprintf(buf, buflen, "NULL");
-               return -ENOENT;
+       if (!v_handle) {
+               _E("Not initialize");
+               return -EPERM;
        }
 
-       snprintf(buf, buflen, "%s", cur_path);
+       if (v_handle == -ENOTSUP) {
+               _E("Not supported vibration");
+               *supported = false;
+               return 0;
+       }
+
+       /* get vibration data */
+       data = get_data(pattern);
+       if (!data) {
+               _E("Not supported vibration pattern");
+               ret = false;
+       }
+
+       *supported = ret;
        return 0;
 }
 
+static int vibrator_get_path(feedback_pattern_e pattern, char *buf, unsigned int buflen)
+{
+       char *data;
+       int ret = 0;
+
+       if (!buf || buflen <= 0)
+               return -EINVAL;
+
+       /* get vibration data */
+       data = get_data(pattern);
+       if (!data) {
+               _E("This pattern(%s) in vibrator type is not supported to play",
+                               profile->str_pattern[pattern]);
+               data = "NULL";
+               ret = -ENOENT;
+       }
+
+       snprintf(buf, buflen, "%s", data);
+       return ret;
+}
+
 static int vibrator_set_path(feedback_pattern_e pattern, char *path)
 {
        struct stat buf;
-       char *ppath;
 
        /*
         * check the path is valid
-        * if path is null, below operation is ignored
+        * if path is null, reset vibration path
         */
+       if (!path) {
+               if (vib_info.data[pattern].changed) {
+                       free(vib_info.data[pattern].changed);
+                       vib_info.data[pattern].changed = NULL;
+               }
+               return 0;
+       }
+
        if (path && stat(path, &buf)) {
                _E("%s is not presents", path);
                return -errno;
        }
 
-       ppath = haptic_file[pattern];
+       if (vib_info.data[pattern].changed) {
+               free(vib_info.data[pattern].changed);
+               vib_info.data[pattern].changed = NULL;
+       }
 
        /* if path is NULL, this pattern set to default file */
        if (path)
-               snprintf(ppath, NAME_MAX, "%s", path);
-       else
-               memset(ppath, 0, NAME_MAX);
+               vib_info.data[pattern].changed = strdup(path);
 
-       _D("The file of pattern(%s) is changed to [%s]", str_pattern[pattern], path);
+       _D("The file of pattern(%s) is changed to [%s]",
+                       profile->str_pattern[pattern], path);
        return 0;
 }
 
 static const struct device_ops vibrator_device_ops = {
        .type = FEEDBACK_TYPE_VIBRATION,
+       .name = "Vibrator",
        .init = vibrator_init,
        .exit = vibrator_exit,
        .play = vibrator_play,
        .stop = vibrator_stop,
+       .is_supported = vibrator_is_supported,
        .get_path = vibrator_get_path,
        .set_path = vibrator_set_path,
 };