+# [SoundMultiTheme]
+# - As put this section, This means this conf file supports multi theme.
+# Thus if you define this section, please remove [Sound] section in this file.
+# It cannot be defined together, so put [Sound] section to another conf files alone.
+# Furthermore, this section must be located sound.conf(default file).
+# If you define this section to another file, it will be not work properly.
+# If you do not define this section in this file, then default theme number will be 0.
+# It means if you define [SoundMultiTheme], you cannot use 0 as theme index.
+# And also [Sound] will be parsed and used like the existing operation.
+# number_of_theme=int(range=1~N)
+# - Define how many conf file will be used.
+# The number_of_theme should be start with 1 to N.
+# name_of_default_theme=string
+# - Define default theme conf file as put SoundThemeN name, The N number file will be selected
+# as a default theme conf file.
+# The N number range=1~N
+# [SoundThemeN]
+# - This section determines that the file is defined as the Nth theme.
+# file_path_of_theme=string
+# - Defines the path of the corresponding number file.
+# In this file, [Sound] section and new patterns, new files should be defined.
+#
+# Example
+# [SoundMultiTheme]
+# number_of_theme=2
+# name_of_default_theme=SoundTheme2
+# [SoundTheme1]
+# file_path_of_theme=/usr/share/feedback/sound-theme1.conf
+# [SoundTheme2]
+# file_path_of_theme=/usr/share/feedback/sound-theme2.conf
+
[Sound]
FEEDBACK_PATTERN_TAP=/usr/share/feedback/sound/touch/touch.wav
FEEDBACK_PATTERN_SIP=/usr/share/feedback/sound/touch/sip.wav
int feedback_play_type_soundpath_internal(feedback_type_e type, feedback_pattern_internal_e internal_pattern, const char *soundpath);
/**
+ * @brief Gets the number of theme supported.
+ * @details This function gets the number of theme described in the config file.
+ * @since_tizen 8.0
+ * @param[in] type The feedback type
+ * @param[out] count_of_theme The number of theme supported
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #FEEDBACK_ERROR_NONE Successful
+ * @retval #FEEDBACK_ERROR_OPERATION_FAILED Operation not permitted
+ * @retval #FEEDBACK_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #FEEDBACK_ERROR_NOT_SUPPORTED Not supported device
+ * @retval #FEEDBACK_ERROR_NOT_INITIALIZED Not initialized
+ * @pre feedback_initialize()
+ */
+int feedback_get_count_of_theme_internal(feedback_type_e feedback_type, unsigned int *count_of_theme);
+
+/**
+ * @brief Gets the current index of theme selected.
+ * @details This function gets the current index of theme selected.
+ * @since_tizen 8.0
+ * @param[in] type The feedback type
+ * @param[out] index_of_theme The current index of theme selected
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #FEEDBACK_ERROR_NONE Successful
+ * @retval #FEEDBACK_ERROR_OPERATION_FAILED Operation not permitted
+ * @retval #FEEDBACK_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #FEEDBACK_ERROR_NOT_SUPPORTED Not supported device
+ */
+int feedback_get_theme_index_internal(feedback_type_e feedback_type, unsigned int *index_of_theme);
+
+/**
+ * @brief Sets the current index of theme.
+ * @details This function sets the index of theme.
+ * @since_tizen 8.0
+ * @param[in] type The feedback type
+ * @param[in] index_of_theme The index of theme will be selected
+ * @return @c 0 on success,
+ * otherwise a negative error value
+ * @retval #FEEDBACK_ERROR_NONE Successful
+ * @retval #FEEDBACK_ERROR_OPERATION_FAILED Operation not permitted
+ * @retval #FEEDBACK_ERROR_INVALID_PARAMETER Invalid parameter
+ * @retval #FEEDBACK_ERROR_NOT_SUPPORTED Not supported device
+ */
+int feedback_set_theme_index_internal(feedback_type_e feedback_type, unsigned int index_of_theme);
+
+/**
* @}
*/
return FEEDBACK_ERROR_NONE;
}
+
+API int feedback_get_count_of_theme_internal(feedback_type_e feedback_type, unsigned int *count_of_theme)
+{
+ const struct device_ops *dev = NULL;
+ int ret = 0;
+
+ 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 (feedback_type <= FEEDBACK_TYPE_NONE || feedback_type >= profile->max_type || !count_of_theme) {
+ _E("Invalid parameter : type(%d)", feedback_type);
+ return FEEDBACK_ERROR_INVALID_PARAMETER;
+ }
+
+ dev = find_device(feedback_type);
+ if (!dev) {
+ _E("Not supported device : type(%s)", profile->str_type[feedback_type]);
+ return FEEDBACK_ERROR_NOT_SUPPORTED;
+ }
+
+ if (!dev->get_count_of_theme)
+ return FEEDBACK_ERROR_NOT_SUPPORTED;
+
+ ret = dev->get_count_of_theme(count_of_theme);
+ if (ret < 0)
+ return FEEDBACK_ERROR_OPERATION_FAILED;
+
+ return FEEDBACK_ERROR_NONE;
+}
+
+API int feedback_get_theme_index_internal(feedback_type_e feedback_type, unsigned int *index_of_theme)
+{
+ const struct device_ops *dev = NULL;
+ int ret = 0;
+
+ if (feedback_type <= FEEDBACK_TYPE_NONE || feedback_type >= profile->max_type || !index_of_theme) {
+ _E("Invalid parameter : type(%d)", feedback_type);
+ return FEEDBACK_ERROR_INVALID_PARAMETER;
+ }
+
+ dev = find_device(feedback_type);
+ if (!dev) {
+ _E("Not supported device : type(%s)", profile->str_type[feedback_type]);
+ return FEEDBACK_ERROR_NOT_SUPPORTED;
+ }
+
+ if (!dev->get_theme_index)
+ return FEEDBACK_ERROR_NOT_SUPPORTED;
+
+ pthread_mutex_lock(&fmutex);
+ ret = dev->get_theme_index(index_of_theme);
+ pthread_mutex_unlock(&fmutex);
+ if (ret < 0)
+ return FEEDBACK_ERROR_OPERATION_FAILED;
+
+ return FEEDBACK_ERROR_NONE;
+}
+
+API int feedback_set_theme_index_internal(feedback_type_e feedback_type, unsigned int index_of_theme)
+{
+ const struct device_ops *dev = NULL;
+ int ret = 0;
+
+ if (feedback_type <= FEEDBACK_TYPE_NONE || feedback_type >= profile->max_type) {
+ _E("Invalid parameter : type(%d)", feedback_type);
+ return FEEDBACK_ERROR_INVALID_PARAMETER;
+ }
+
+ dev = find_device(feedback_type);
+ if (!dev) {
+ _E("Not supported device : type(%s)", profile->str_type[feedback_type]);
+ return FEEDBACK_ERROR_NOT_SUPPORTED;
+ }
+
+ if (!dev->set_theme_index)
+ return FEEDBACK_ERROR_NOT_SUPPORTED;
+
+ pthread_mutex_lock(&fmutex);
+ ret = dev->set_theme_index(index_of_theme);
+ pthread_mutex_unlock(&fmutex);
+ if (ret < 0)
+ return FEEDBACK_ERROR_OPERATION_FAILED;
+
+ return FEEDBACK_ERROR_NONE;
+}
#include <mm_sound_private.h>
#include <sound_manager.h>
#include <wav_player.h>
+#include <libsyscommon/ini-parser.h>
+#include <libsyscommon/list.h>
#include "feedback-ids.h"
#include "profiles.h"
#include "feedback-config.h"
#define SOUND_CONF_FILE FEEDBACK_SYS_RO_SHARE"/feedback/sound.conf"
-
+#define SOUND_NAME "Sound"
/* Temporary keys */
#ifndef VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL
#define VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL "db/setting/sound/button_sounds"
static int sndstatus;
static int touch_sndstatus;
static int keytone_sndstatus;
-static struct feedback_config_info sound_info = {
- .name = "Sound",
-};
+static int current_theme_index = 0;
+static int number_of_theme = 0;
+static struct feedback_config_info *sound_info;
static char *get_data(feedback_pattern_e pattern)
{
return data;
for (i = 0; i < profile->get_num_of_pattern(); i++) {
- if (pattern == sound_info.data[i].pattern) {
+ if (pattern == sound_info[current_theme_index].data[i].pattern) {
index = i;
break;
}
return NULL;
}
- if (sound_info.data[index].changed)
- data = sound_info.data[index].changed;
+ if (sound_info[current_theme_index].data[index].changed)
+ data = sound_info[current_theme_index].data[index].changed;
else
- data = sound_info.data[index].origin;
+ data = sound_info[current_theme_index].data[index].origin;
return data;
}
}
//LCOV_EXCL_STOP
+static int feedback_parse_sound_multi_theme_section(const struct parse_result *result, void *data)
+{
+ struct section_property *extracted_section_prop = NULL;
+ GList *temp_glist = NULL;
+
+ if (!result || !result->props)
+ return 0;
+
+ if (!MATCH("SoundMultiTheme", result->section))
+ return 0;
+
+ SYS_G_LIST_FOREACH(result->props, temp_glist, extracted_section_prop) {
+ if (MATCH("number_of_theme", extracted_section_prop->key)) {
+ sscanf(extracted_section_prop->value, "%d", &number_of_theme);
+ } else if (MATCH("name_of_default_theme", extracted_section_prop->key)) {
+ sscanf(extracted_section_prop->value, "SoundTheme%d", ¤t_theme_index);
+ } else {
+ _E("Failed to parse SoundMultiTheme section. Please check your config file, \
+ check the value or typo of key value");
+ return -EINVAL;
+ }
+ }
+
+ if (number_of_theme < current_theme_index) {
+ _E("Failed to parse SoundMultiTheme section. Please check your config file, \
+ default theme number cannot be greater then the number of theme");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static bool feedback_is_multi_theme_support(const char *path)
+{
+ int ret = 0;
+
+ if (!path)
+ return false;
+
+ ret = syscommon_config_parse_by_section(path, feedback_parse_sound_multi_theme_section, NULL);
+ if (ret < 0)
+ return false;
+
+ if (number_of_theme > 0)
+ return true;
+
+ return false;
+}
+
+static int feedback_parse_multi_theme_conf_path_section(const struct parse_result *result, void *data)
+{
+ struct section_property *extracted_section_prop = NULL;
+ GList *temp_glist = NULL;
+ int multi_theme_index = 0;
+ int ret = 0;
+
+ if (!result || !result->props)
+ return 0;
+
+ if (!strstr(result->section, "SoundTheme"))
+ return 0;
+
+ ret = sscanf(result->section, "SoundTheme%d", &multi_theme_index);
+ if (ret == EOF)
+ return 0;
+
+ if (multi_theme_index < 0 || multi_theme_index > number_of_theme)
+ return 0;
+
+ SYS_G_LIST_FOREACH(result->props, temp_glist, extracted_section_prop) {
+ if (MATCH("file_path_of_theme", extracted_section_prop->key)) {
+ feedback_load_config(extracted_section_prop->value, &sound_info[multi_theme_index]);
+ } else {
+ _E("Failed to parse SoundThemeN section, Please check your config file, \
+ check the value or typo of key value");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static int feedback_multi_theme_load_config(const char *path)
+{
+ int ret = 0;
+
+ if (!path)
+ return -EINVAL;
+
+ ret = syscommon_config_parse_by_section(path, feedback_parse_multi_theme_conf_path_section, NULL);
+
+ return ret;
+}
+
+static int sound_get_config(void)
+{
+ bool is_support_multi_theme = false;
+
+ is_support_multi_theme = feedback_is_multi_theme_support(SOUND_CONF_FILE);
+
+ sound_info = (struct feedback_config_info*)calloc(number_of_theme+1, sizeof(struct feedback_config_info));
+ if (!sound_info) {
+ _E("Failed to allocate memory for sound_info.");
+ return -ENOMEM;
+ }
+
+ for (int i = 0; i <= number_of_theme; i++)
+ sound_info[i].name = SOUND_NAME;
+
+ if (is_support_multi_theme) {
+ feedback_multi_theme_load_config(SOUND_CONF_FILE);
+ } else {
+ current_theme_index = 0;
+ feedback_load_config(SOUND_CONF_FILE, &sound_info[current_theme_index]);
+ }
+
+ return 0;
+}
+
static void sound_init(void)
{
- int ret;
+ int ret = 0;
- /* get sound data */
- feedback_load_config(SOUND_CONF_FILE, &sound_info);
+ ret = sound_get_config();
+ if (ret < 0)
+ _W("Failed to load configuration file(%s): %d", SOUND_CONF_FILE, ret);
/* check sound status */
if (vconf_get_bool(VCONFKEY_SETAPPL_TOUCH_SOUNDS_BOOL, &touch_sndstatus) < 0)
_W("Add watch for VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL failed"); //LCOV_EXCL_LINE
}
+static void sound_put_config(void)
+{
+ if (!sound_info)
+ return;
+
+ /* free sound data */
+ for (int i = 0; i <= number_of_theme; i++) {
+ feedback_free_config(&sound_info[i]);
+ }
+ sound_info = NULL;
+}
+
static void sound_exit(void)
{
int ret;
if (ret != 0)
_W("Remove watch for VCONFKEY_SETAPPL_BUTTON_SOUNDS_BOOL failed"); //LCOV_EXCL_LINE
- /* free sound data */
- feedback_free_config(&sound_info);
+ sound_put_config();
}
//LCOV_EXCL_START
}
for (i = 0; i < profile->get_num_of_pattern(); i++) {
- if (pattern == sound_info.data[i].pattern) {
+ if (pattern == sound_info[current_theme_index].data[i].pattern) {
index = i;
break;
}
if (index < 0) {
for (i = 0; i < profile->get_num_of_pattern(); i++) {
- if (sound_info.data[i].pattern != -1)
+ if (sound_info[current_theme_index].data[i].pattern != -1)
continue;
- sound_info.data[i].pattern = pattern;
+ sound_info[current_theme_index].data[i].pattern = pattern;
if (path)
- sound_info.data[i].changed = strdup(path);
+ sound_info[current_theme_index].data[i].changed = strdup(path);
else
- sound_info.data[i].changed = NULL;
+ sound_info[current_theme_index].data[i].changed = NULL;
_D("The file of pattern(%s) is changed to [%s]",
profile->str_pattern(pattern), path? path:"NULL");
return -EPERM;
}
- if (sound_info.data[index].changed) {
- free(sound_info.data[index].changed);
- sound_info.data[index].changed = NULL;
+ if (sound_info[current_theme_index].data[index].changed) {
+ free(sound_info[current_theme_index].data[index].changed);
+ sound_info[current_theme_index].data[index].changed = NULL;
}
/* if path is NULL, this pattern set to default file */
if (path)
- sound_info.data[index].changed = strdup(path);
+ sound_info[current_theme_index].data[index].changed = strdup(path);
_D("The file of pattern(%s) is changed to [%s]",
profile->str_pattern(pattern), path);
}
//LCOV_EXCL_STOP
+static int sound_get_count_of_theme(unsigned int *count_of_theme)
+{
+ if (!count_of_theme)
+ return -EINVAL;
+
+ *count_of_theme = number_of_theme;
+
+ return 0;
+}
+
+static int sound_get_theme_index(unsigned int *index_of_theme)
+{
+ if (!index_of_theme)
+ return -EINVAL;
+
+ *index_of_theme = current_theme_index;
+
+ return 0;
+}
+
+static int sound_set_theme_index(unsigned int index_of_theme)
+{
+ if (index_of_theme > number_of_theme)
+ return -EINVAL;
+
+ if (number_of_theme > 0 && index_of_theme == 0)
+ return -EINVAL;
+
+ current_theme_index = index_of_theme;
+
+ return 0;
+}
+
static const struct device_ops sound_device_ops = {
.type = FEEDBACK_TYPE_SOUND,
.name = "Sound",
.is_supported = sound_is_supported,
.get_path = sound_get_path,
.set_path = sound_set_path,
+ .get_count_of_theme = sound_get_count_of_theme,
+ .get_theme_index = sound_get_theme_index,
+ .set_theme_index = sound_set_theme_index,
};
DEVICE_OPS_REGISTER(&sound_device_ops);