3 * Copyright (c) 2012 Samsung Electronics Co., Ltd.
5 * Licensed under the Apache License, Version 2.0 (the License);
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
25 #include <sys/types.h>
26 #include <mm_sound_private.h>
33 #include "feedback-internal.h"
34 #include "feedback-file.h"
35 #include "feedback-str.h"
36 #include "feedback-log.h"
37 #include "xmlparser.h"
39 #define FEEDBACK_RETRY_CNT 1
40 #define MAX_FILE_PATH 512
42 #define DEFAULT_FEEDBACK_HANDLE 0x0F
44 #define VIBRATION_XML "/usr/share/feedback/vibration.xml"
47 haptic_device_h v_handle;
52 static int touch_sndstatus;
56 static int noti_level;
57 static int callstatus;
59 static void feedback_sndstatus_cb(keynode_t *key, void* data)
61 sndstatus = vconf_keynode_get_bool(key);
64 static void feedback_touch_sndstatus_cb(keynode_t *key, void* data)
66 touch_sndstatus = vconf_keynode_get_bool(key);
69 static void feedback_soundon_cb(keynode_t *key, void* data)
71 soundon = vconf_keynode_get_int(key);
74 static void feedback_vibstatus_cb(keynode_t *key, void* data)
76 vibstatus = vconf_keynode_get_bool(key);
79 static void feedback_vib_cb(keynode_t *key, void* data)
81 vib_level = vconf_keynode_get_int(key);
84 static void feedback_noti_cb(keynode_t *key, void* data)
86 noti_level = vconf_keynode_get_int(key);
90 static void feedback_callstatus_cb(keynode_t *key, void* data)
92 callstatus = vconf_keynode_get_int(key);
95 static feedback_pattern_e feedback_get_alert_on_call_key(feedback_pattern_e pattern)
98 case FEEDBACK_PATTERN_MESSAGE:
99 case FEEDBACK_PATTERN_EMAIL:
100 case FEEDBACK_PATTERN_WAKEUP:
101 case FEEDBACK_PATTERN_SCHEDULE:
102 case FEEDBACK_PATTERN_TIMER:
103 case FEEDBACK_PATTERN_GENERAL:
104 case FEEDBACK_PATTERN_CHARGERCONN:
105 case FEEDBACK_PATTERN_FULLCHARGED:
106 case FEEDBACK_PATTERN_LOWBATT:
107 return (feedback_pattern_e)(pattern+1);
115 static haptic_priority_e feedback_get_priority(feedback_pattern_e pattern)
117 if (pattern >= FEEDBACK_PATTERN_TAP && pattern <= FEEDBACK_PATTERN_HW_HOLD)
118 return HAPTIC_PRIORITY_MIN;
120 return HAPTIC_PRIORITY_MIDDLE;
123 static volume_type_t feedback_get_volume_type(feedback_pattern_e pattern)
125 if (pattern == FEEDBACK_PATTERN_TAP)
126 return VOLUME_TYPE_SYSTEM|VOLUME_GAIN_TOUCH;
127 else if (pattern >= FEEDBACK_PATTERN_KEY0 && pattern <= FEEDBACK_PATTERN_KEY_SHARP)
128 return VOLUME_TYPE_SYSTEM|VOLUME_GAIN_DIALER;
129 else if (pattern == FEEDBACK_PATTERN_VOLUME_KEY)
130 return VOLUME_TYPE_RINGTONE;
132 return VOLUME_TYPE_SYSTEM;
135 static int feedback_get_haptic_level(feedback_pattern_e pattern)
139 if (pattern >= FEEDBACK_PATTERN_MESSAGE && pattern <= FEEDBACK_PATTERN_GENERAL_ON_CALL)
144 FEEDBACK_LOG("Call status : %d, pattern : %s, level : %d", callstatus, str_pattern[pattern], level);
145 if (callstatus != VCONFKEY_CALL_OFF) {
146 // if call status is ON, vibration magnitude is 20%
147 level = (int)(level*0.2f);
148 level = (level < 1) ? 1 : level;
149 FEEDBACK_LOG("level changed : %d", level);
156 static bool feedback_get_always_alert_case(feedback_pattern_e pattern)
159 case FEEDBACK_PATTERN_WAKEUP:
160 case FEEDBACK_PATTERN_WAKEUP_ON_CALL:
168 static int feedback_get_data(xmlDocPtr doc, feedback_pattern_e pattern, struct xmlData **data)
171 struct xmlData *retData;
173 cur = xml_find(doc, (const xmlChar*)str_pattern[pattern]);
175 FEEDBACK_ERROR("xml_find fail");
179 retData = xml_parse(doc, cur);
180 if (retData == NULL) {
181 FEEDBACK_ERROR("xml_parse fail");
189 static void feedback_release_data(struct xmlData *data)
197 static int feedback_change_symlink(const char *sym_path, const char *new_path)
201 if (sym_path == NULL || strlen(sym_path) == 0) {
202 FEEDBACK_ERROR("Invalid parameter : sym_path(NULL)");
203 return FEEDBACK_ERROR_INVALID_PARAMETER;
206 if (new_path == NULL || strlen(new_path) == 0) {
207 FEEDBACK_ERROR("Invalid paramter : new_path(NULL)");
208 return FEEDBACK_ERROR_INVALID_PARAMETER;
211 // check symbolic link file existence
212 if (stat(sym_path, &buf)) {
213 FEEDBACK_ERROR("file(%s) is not presents", sym_path);
214 return FEEDBACK_ERROR_OPERATION_FAILED;
217 if (unlink(sym_path) < 0) {
218 FEEDBACK_LOG("unlink(%s) : %s", sym_path, strerror(errno));
221 if (symlink(new_path, sym_path) < 0) {
222 FEEDBACK_ERROR("symlink(%s) : %s", sym_path, strerror(errno));
223 return FEEDBACK_ERROR_OPERATION_FAILED;
226 return FEEDBACK_ERROR_NONE;
229 static int feedback_restore_default_file(feedback_type_e type, feedback_pattern_e pattern)
231 const char *cur_path = NULL;
232 char default_path[MAX_FILE_PATH] = {0,};
236 if (type <= FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) {
237 FEEDBACK_ERROR("Invalid parameter : type(%s)", str_type[type]);
238 return FEEDBACK_ERROR_INVALID_PARAMETER;
241 if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= FEEDBACK_PATTERN_END) {
242 FEEDBACK_ERROR("Invalid parameter : pattern(%s)", str_pattern[pattern]);
243 return FEEDBACK_ERROR_INVALID_PARAMETER;
246 if (type == FEEDBACK_TYPE_SOUND) {
247 cur_path = snd_file[pattern];
249 cur_path = haptic_file[pattern];
252 // if there isn't cur_path, it already returns before calling this api
253 if (cur_path == NULL || strlen(cur_path) == 0) {
254 FEEDBACK_ERROR("Invalid parameter : cur_path(NULL)");
255 return FEEDBACK_ERROR_OPERATION_FAILED;
258 temp = strcat(default_path, FEEDBACK_ORIGIN_DATA_DIR);
259 strcat(temp, cur_path+strlen(FEEDBACK_DATA_DIR));
260 FEEDBACK_LOG("default_path : %s", default_path);
262 ret = feedback_change_symlink(cur_path, default_path);
263 if (FEEDBACK_FAILED(ret)) {
264 FEEDBACK_ERROR("change_symlink is failed");
265 return FEEDBACK_ERROR_OPERATION_FAILED;
268 return FEEDBACK_ERROR_NONE;
271 int feedback_init(feedback_h *handle)
273 FEEDBACK_HANDLE *phandle;
274 haptic_device_h v_handle;
279 if (vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &sndstatus) < 0) {
280 FEEDBACK_ERROR("vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &sndstatus) ==> FAIL!!");
281 return FEEDBACK_ERROR_OPERATION_FAILED;
284 if (vconf_get_bool(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, &touch_sndstatus) < 0) {
285 FEEDBACK_ERROR("vconf_get_bool(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, &touch_sndstatus) ==> FAIL!!");
286 return FEEDBACK_ERROR_OPERATION_FAILED;
289 if (vconf_get_int(VCONFKEY_SOUND_STATUS, &soundon) < 0) {
290 FEEDBACK_ERROR("vconf_get_int(VCONFKEY_SOUND_STATUS, &soundon) ==> FAIL!!");
291 return FEEDBACK_ERROR_OPERATION_FAILED;
294 /* check vibration status */
295 if (vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &vibstatus) < 0) {
296 FEEDBACK_ERROR("vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &vibstatus) ==> FAIL!!");
297 return FEEDBACK_ERROR_OPERATION_FAILED;
300 /* check vib_level */
301 if (vconf_get_int(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, &vib_level) < 0) {
302 FEEDBACK_ERROR("vconf_get_int(VCONFKEY_FEEDBACK_VIBRATION_LEVEL_INT, &vib_level) ==> FAIL!!");
303 return FEEDBACK_ERROR_OPERATION_FAILED;
306 /* check noti_level */
307 if (vconf_get_int(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, ¬i_level) < 0) {
308 FEEDBACK_ERROR("vconf_get_int(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, ¬i_level) ==> FAIL!!");
309 return FEEDBACK_ERROR_OPERATION_FAILED;
312 /* check call status */
313 if (vconf_get_int(VCONFKEY_CALL_STATE, &callstatus) < 0) {
314 FEEDBACK_ERROR("vconf_get_int(VCONFKEY_CALL_STATE, &callstatus) ==> FAIL!!");
315 return FEEDBACK_ERROR_OPERATION_FAILED;
319 v_doc = xml_open(VIBRATION_XML);
321 FEEDBACK_ERROR("xml_open(%s) fail", VIBRATION_XML);
322 return FEEDBACK_ERROR_OPERATION_FAILED;
326 ret = haptic_open(HAPTIC_DEVICE_ALL, &v_handle);
327 if (ret != HAPTIC_ERROR_NONE) {
328 FEEDBACK_ERROR("haptic_open(HAPTIC_DEVICE_ALL, &v_handle) ==> FAIL!! : %d", ret);
329 v_handle = (haptic_device_h)DEFAULT_FEEDBACK_HANDLE;
332 /* add watch for status value */
333 vconf_notify_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, feedback_sndstatus_cb, NULL);
334 vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, feedback_touch_sndstatus_cb, NULL);
335 vconf_notify_key_changed(VCONFKEY_SOUND_STATUS, feedback_soundon_cb, NULL);
336 vconf_notify_key_changed(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, feedback_vibstatus_cb, NULL);
337 vconf_notify_key_changed(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, feedback_vib_cb, NULL);
338 vconf_notify_key_changed(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, feedback_noti_cb, NULL);
339 vconf_notify_key_changed(VCONFKEY_CALL_STATE, feedback_callstatus_cb, NULL);
341 FEEDBACK_LOG("vconf_get_bool(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, &sndstatus) ==> %d", sndstatus);
342 FEEDBACK_LOG("vconf_get_bool(VCONFKEY_SETAPPL_....UNDS_BOOL, &touch_sndstatus) ==> %d", touch_sndstatus);
343 FEEDBACK_LOG("vconf_get_int(VCONFKEY_SOUND_STATUS, &soundon) ==> %d", soundon);
344 FEEDBACK_LOG("vconf_get_bool(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, &vibstatus) ==> %d", vibstatus);
345 FEEDBACK_LOG("vconf_get_int(VCONFKEY_FEEDBACK_VIBRATION_LEVEL_INT, &vib_level) ==> %d", vib_level);
346 FEEDBACK_LOG("vconf_get_int(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, ¬i_level) ==> %d", noti_level);
347 FEEDBACK_LOG("vconf_get_int(VCONFKEY_CALL_STATUS, &callstatus) ==> %d", callstatus);
349 phandle = (FEEDBACK_HANDLE *)malloc(sizeof(FEEDBACK_HANDLE));
350 phandle->v_handle = v_handle;
351 phandle->v_doc = v_doc;
352 *handle = (feedback_h)phandle;
353 FEEDBACK_LOG("handle value : %x", handle);
354 return FEEDBACK_ERROR_NONE;
357 int feedback_fini(feedback_h handle)
359 FEEDBACK_HANDLE *phandle = (FEEDBACK_HANDLE *)handle;
363 FEEDBACK_ERROR("Invalid parameter : handle(NULL)");
364 return FEEDBACK_ERROR_INVALID_PARAMETER;
367 if (phandle->v_handle != DEFAULT_FEEDBACK_HANDLE) {
368 ret = haptic_close(phandle->v_handle);
369 if (ret != HAPTIC_ERROR_NONE) {
370 FEEDBACK_ERROR("haptic_close is failed : %d", ret);
374 if (phandle->v_doc) {
375 xml_close(phandle->v_doc);
380 vconf_ignore_key_changed(VCONFKEY_SETAPPL_SOUND_STATUS_BOOL, feedback_sndstatus_cb);
381 vconf_ignore_key_changed(VCONFKEY_SOUND_STATUS, feedback_soundon_cb);
382 vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, feedback_touch_sndstatus_cb);
383 vconf_ignore_key_changed(VCONFKEY_SETAPPL_VIBRATION_STATUS_BOOL, feedback_vibstatus_cb);
384 vconf_ignore_key_changed(VCONFKEY_SETAPPL_TOUCH_FEEDBACK_VIBRATION_LEVEL_INT, feedback_vib_cb);
385 vconf_ignore_key_changed(VCONFKEY_SETAPPL_NOTI_VIBRATION_LEVEL_INT, feedback_noti_cb);
386 vconf_ignore_key_changed(VCONFKEY_CALL_STATE, feedback_callstatus_cb);
388 return FEEDBACK_ERROR_NONE;
391 int feedback_play_sound(feedback_h handle, feedback_pattern_e pattern)
394 int retry = FEEDBACK_RETRY_CNT;
398 FEEDBACK_ERROR("Invalid parameter : handle(NULL)");
399 return FEEDBACK_ERROR_INVALID_PARAMETER;
402 if (sndstatus == 0 && !feedback_get_always_alert_case(pattern)) {
403 FEEDBACK_LOG("Sound condition is OFF (sndstatus : %d)", sndstatus);
404 return FEEDBACK_ERROR_NONE;
407 if (soundon == 1 && pattern >= FEEDBACK_PATTERN_TAP && pattern <= FEEDBACK_PATTERN_HW_HOLD) {
408 FEEDBACK_LOG("Touch feedback sound doesn't work during playing sound");
409 return FEEDBACK_ERROR_NONE;
412 if (touch_sndstatus == 0 && pattern >= FEEDBACK_PATTERN_TAP && pattern <= FEEDBACK_PATTERN_HW_HOLD) {
413 FEEDBACK_LOG("Touch Sound condition is OFF and pattern is touch type (touch_sndstatus : %d, pattern : %s)", touch_sndstatus, str_pattern[pattern]);
414 return FEEDBACK_ERROR_NONE;
417 if (callstatus != VCONFKEY_CALL_OFF) {
418 pattern = feedback_get_alert_on_call_key(pattern);
419 FEEDBACK_LOG("Call status is connected or connecting. pattern changed : %s", str_pattern[pattern]);
422 if (snd_file[pattern] == NULL) {
423 FEEDBACK_LOG("This case(%s) does not play sound", str_pattern[pattern]);
424 return FEEDBACK_ERROR_NONE;
427 if (stat(snd_file[pattern], &buf)) {
428 FEEDBACK_ERROR("%s is not presents", snd_file[pattern]);
429 ret = feedback_restore_default_file(FEEDBACK_TYPE_SOUND, pattern);
430 if (FEEDBACK_FAILED(ret)) {
431 FEEDBACK_ERROR("feedback_restore_default_file(%s) error", str_pattern[pattern]);
432 return FEEDBACK_ERROR_OPERATION_FAILED;
434 FEEDBACK_LOG("%s is restored", snd_file[pattern]);
438 ret = mm_sound_play_keysound(snd_file[pattern], feedback_get_volume_type(pattern));
439 if (ret == MM_ERROR_NONE) {
440 FEEDBACK_LOG("Play success! SND filename is %s", snd_file[pattern]);
441 return FEEDBACK_ERROR_NONE;
443 FEEDBACK_ERROR("mm_sound_play_keysound() returned error(%d)", ret);
446 return FEEDBACK_ERROR_OPERATION_FAILED;
449 int feedback_play_vibration(feedback_h handle, feedback_pattern_e pattern)
451 FEEDBACK_HANDLE *phandle = (FEEDBACK_HANDLE *)handle;
454 struct xmlData *data;
457 FEEDBACK_ERROR("Invalid parameter : handle(NULL)");
458 return FEEDBACK_ERROR_INVALID_PARAMETER;
461 if (handle == DEFAULT_FEEDBACK_HANDLE) {
462 FEEDBACK_ERROR("haptic is not initialized");
463 return FEEDBACK_ERROR_OPERATION_FAILED;
466 if (vibstatus == 0 && !feedback_get_always_alert_case(pattern)) {
467 FEEDBACK_LOG("Vibration condition is OFF (vibstatus : %d)", vibstatus);
468 return FEEDBACK_ERROR_NONE;
471 if (callstatus != VCONFKEY_CALL_OFF) {
472 pattern = feedback_get_alert_on_call_key(pattern);
473 FEEDBACK_LOG("Call status is connected or connecting. pattern changed : %s", str_pattern[pattern]);
476 ret = feedback_get_data(phandle->v_doc, pattern, &data);
478 FEEDBACK_ERROR("feedback_get_vibration_data fail");
479 return FEEDBACK_ERROR_OPERATION_FAILED;
482 if (data->data == NULL) {
483 FEEDBACK_LOG("This case(%s) does not play vibration", str_pattern[pattern]);
484 feedback_release_data(data);
485 return FEEDBACK_ERROR_NONE;
488 /* play haptic buffer */
489 ret = haptic_vibrate_buffer_with_detail(phandle->v_handle, data->data, HAPTIC_ITERATION_ONCE,
490 feedback_get_haptic_level(pattern), feedback_get_priority(pattern), NULL);
491 if (ret != HAPTIC_ERROR_NONE) {
492 FEEDBACK_ERROR("haptic_vibrate_buffer_with_detail is failed");
493 feedback_release_data(data);
494 return FEEDBACK_ERROR_OPERATION_FAILED;
497 feedback_release_data(data);
498 return FEEDBACK_ERROR_NONE;
501 int feedback_set_path(feedback_type_e type, feedback_pattern_e pattern, char* path)
503 const char* cur_path = NULL;
506 if (type <= FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) {
507 FEEDBACK_ERROR("Invalid parameter : type(%s)", str_type[type]);
508 return FEEDBACK_ERROR_INVALID_PARAMETER;
511 if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= FEEDBACK_PATTERN_END) {
512 FEEDBACK_ERROR("Invalid parameter : pattern(%s)", str_pattern[pattern]);
513 return FEEDBACK_ERROR_INVALID_PARAMETER;
517 FEEDBACK_ERROR("Invalid parameter : path(NULL)");
518 return FEEDBACK_ERROR_INVALID_PARAMETER;
521 if (access(path, F_OK) != 0) {
522 FEEDBACK_ERROR("Invalid parameter : path does not exist");
523 return FEEDBACK_ERROR_INVALID_PARAMETER;
526 if (type == FEEDBACK_TYPE_SOUND) {
527 cur_path = snd_file[pattern];
529 cur_path = haptic_file[pattern];
532 if (cur_path == NULL) {
533 FEEDBACK_ERROR("This pattern(%s) in this type(%s) is not supported to play", str_pattern[pattern], str_type[type]);
534 return FEEDBACK_ERROR_OPERATION_FAILED;
537 ret = feedback_change_symlink(cur_path, path);
538 if (FEEDBACK_FAILED(ret)) {
539 FEEDBACK_ERROR("change_symlink is failed");
540 return FEEDBACK_ERROR_OPERATION_FAILED;
543 return FEEDBACK_ERROR_NONE;
546 int feedback_get_path(feedback_type_e type, feedback_pattern_e pattern, char* buf, unsigned int buflen)
548 const char* cur_path = NULL;
549 int retry = FEEDBACK_RETRY_CNT;
551 if (type <= FEEDBACK_TYPE_NONE || type >= FEEDBACK_TYPE_END) {
552 FEEDBACK_ERROR("Invalid parameter : type(%s)", str_type[type]);
553 return FEEDBACK_ERROR_INVALID_PARAMETER;
556 if (pattern <= FEEDBACK_PATTERN_NONE || pattern >= FEEDBACK_PATTERN_END) {
557 FEEDBACK_ERROR("Invalid parameter : pattern(%s)", str_pattern[pattern]);
558 return FEEDBACK_ERROR_INVALID_PARAMETER;
561 if (buf == NULL || buflen <= 0) {
562 FEEDBACK_ERROR("Invalid parameter : buf(NULL) or bufLen(%d)", buflen);
563 return FEEDBACK_ERROR_INVALID_PARAMETER;
566 if (type == FEEDBACK_TYPE_SOUND) {
567 cur_path = snd_file[pattern];
569 cur_path = haptic_file[pattern];
572 if (cur_path == NULL) {
573 FEEDBACK_ERROR("This pattern(%s) in this type(%s) is not supported to play", str_pattern[pattern], str_type[type]);
574 snprintf(buf, buflen, "NULL");
575 return FEEDBACK_ERROR_OPERATION_FAILED;
579 if(readlink(cur_path, buf, buflen) < 0) {
580 FEEDBACK_ERROR("readlink is failed : %s", strerror(errno));
581 return FEEDBACK_ERROR_OPERATION_FAILED;
585 return FEEDBACK_ERROR_NONE;