--- /dev/null
+/*
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the License);
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an AS IS BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <Elementary.h>
+#include <media_content.h>
+#include <maps_service.h>
+#include <app_debug.h>
+#include <app_media.h>
+#include <vconf.h>
+
+#define MAP_LANG "en-US"
+#define MAP_MAX_RES 1
+#define MAP_MAX_REQ 100
+
+#define LOC_TAG_DEFAULT "Unknown"
+#define LOC_INVALID -200
+
+#define KEY_LOC_PLUGIN "db/app/mediahub/loc_plugin"
+#define KEY_LOC_ID "db/app/mediahub/loc_id"
+#define KEY_LOC_CODE "db/app/mediahub/loc_code"
+
+struct locmgr {
+ maps_service_h maps;
+ maps_preference_h preference;
+ bool supported;
+ int queue;
+ Eina_List *list;
+ char *plugin;
+ char *key;
+};
+
+struct _cb_data {
+ struct locmgr *m;
+ app_media *am;
+};
+
+static void _add_queue(struct locmgr *m);
+
+static void _set_location_tag(app_media *am, const char *str)
+{
+ media_info_h media;
+ int r;
+
+ if (!str)
+ return;
+
+ media = app_media_get_media_handle(am);
+ if (!media) {
+ _ERR("failed to getting media handle");
+ return;
+ }
+
+ r = media_info_set_location_tag(media, str);
+ if (r != MEDIA_CONTENT_ERROR_NONE) {
+ _ERR("failed to set location tag");
+ return;
+ }
+
+ r = media_info_update_to_db(media);
+ if (r != MEDIA_CONTENT_ERROR_NONE) {
+ _ERR("failed to update db");
+ return;
+ }
+
+ app_media_update(am);
+}
+
+static void _reverse_geocode_cb(maps_error_e result, int request_id,
+ int index, int total, maps_address_h address, void *data)
+{
+ struct _cb_data *cdata;
+ struct locmgr *m;
+ app_media *am;
+ char *country;
+ char *city;
+ char str[1024];
+ int r;
+
+ if (!data) {
+ _ERR("invalid parameter");
+ return;
+ }
+
+ cdata = data;
+
+ m = cdata->m;
+ m->queue--;
+
+ if (!m->queue)
+ _add_queue(m);
+
+ am = cdata->am;
+ if (!am) {
+ _ERR("failed to get app media");
+ goto out;
+ }
+
+ if (result != MAPS_ERROR_NONE) {
+ _ERR("failed to get reverse geocode (%d)", result);
+ goto out;
+ }
+
+ if (!address) {
+ _ERR("failed to get address");
+ goto out;
+ }
+
+ r = maps_address_get_country(address, &country);
+ if (r != MAPS_ERROR_NONE || !country) {
+ _ERR("failed to get country (%d)", r);
+ maps_address_destroy(address);
+ goto out;
+ }
+
+ r = maps_address_get_city(address, &city);
+ if (r != MAPS_ERROR_NONE || !city) {
+ _ERR("failed to get city (%d)", r);
+ maps_address_destroy(address);
+ free(country);
+ goto out;
+ }
+
+ snprintf(str, sizeof(str), "%s/%s", city, country);
+ _set_location_tag(am, str);
+
+ maps_address_destroy(address);
+
+ free(country);
+ free(city);
+
+out:
+ free(cdata);
+}
+
+static void _reverse_geocode_req(struct locmgr *m, app_media *am)
+{
+ app_media_info *mi;
+ struct _cb_data *cdata;
+ int r;
+ int id;
+
+ if (!m || !am) {
+ _ERR("invalid argument");
+ return;
+ }
+
+ mi = app_media_get_info(am);
+ if (!mi) {
+ _ERR("failed to get media info");
+ return;
+ }
+
+ if (mi->location_tag)
+ return;
+
+ if ((mi->latitude == LOC_INVALID && mi->longitude == LOC_INVALID) ||
+ (mi->latitude == 0 && mi->longitude == 0)) {
+ _set_location_tag(am, LOC_TAG_DEFAULT);
+ return;
+ }
+
+ cdata = calloc(1, sizeof(*cdata));
+ if (!cdata) {
+ _ERR("failed to allocate");
+ return;
+ }
+
+ cdata->m = m;
+ cdata->am = am;
+
+ r = maps_service_reverse_geocode(m->maps, mi->latitude, mi->longitude,
+ m->preference, _reverse_geocode_cb, cdata, &id);
+ if (r != MAPS_ERROR_NONE) {
+ _ERR("failed to get geocode");
+ return;
+ }
+
+ m->queue++;
+}
+
+static void _add_queue(struct locmgr *m)
+{
+ app_media *am;
+ Eina_List *l;
+
+ EINA_LIST_FOREACH(m->list, l, am) {
+ if (m->queue >= MAP_MAX_REQ)
+ break;
+
+ _reverse_geocode_req(m, am);
+ m->list = eina_list_remove_list(m->list, l);
+ }
+}
+
+bool locmgr_set_location(struct locmgr *m, app_media *am)
+{
+ if (!m || !am) {
+ _ERR("invalid argument");
+ return false;
+ }
+
+ if (m->queue) {
+ /* service is busy, add to the list */
+ m->list = eina_list_append(m->list, am);
+ return true;
+ }
+
+ _reverse_geocode_req(m, am);
+
+ return true;
+}
+
+bool locmgr_set_locations(struct locmgr *m, Eina_List *list)
+{
+ Eina_List *l;
+
+ if (!m || !list) {
+ _ERR("invalid argument");
+ return false;
+ }
+
+ l = eina_list_clone(list);
+
+ if (m->queue) {
+ /* service is busy, add to the list */
+ m->list = eina_list_merge(m->list, l);
+ return true;
+ }
+
+ m->list = l;
+
+ _add_queue(m);
+
+ return true;
+}
+
+static bool _maps_provider_cb(char *provider, void *data)
+{
+ struct locmgr *m;
+
+ if (!data)
+ return false;
+
+ m = data;
+
+ if (!strcmp(provider, m->plugin))
+ m->supported = true;
+
+ return true;
+}
+
+static int _set_preference(maps_preference_h *preference)
+{
+ int r;
+
+ r = maps_preference_create(preference);
+ if (r != MAPS_ERROR_NONE) {
+ _ERR("failed to create preference");
+ return r;
+ }
+
+ r = maps_preference_set_language(*preference, MAP_LANG);
+ if (r != MAPS_ERROR_NONE) {
+ _ERR("failed to set language");
+ maps_preference_destroy(*preference);
+ return r;
+ }
+
+ r = maps_preference_set_max_results(*preference, MAP_MAX_RES);
+ if (r != MAPS_ERROR_NONE) {
+ _ERR("failed to set max result");
+ maps_preference_destroy(*preference);
+ return r;
+ }
+
+ return MAPS_ERROR_NONE;
+}
+
+static bool _set_plugin(struct locmgr *m)
+{
+ char str[1024];
+ char *id;
+ char *code;
+
+ /*
+ * NOTE:
+ * map service need to set one of map providers
+ * and provider demand a security key for using it.
+ *
+ * mediahub was tested with "HERE" plugin.
+ * You can get app_id and app_code for "HERE" plugin at below website
+ * https://developer.here.com
+ *
+ * please set those 3 vconf values.
+ * plugin: db/app/mediahub/loc_plugin
+ * app_id: db/app/mediahub/loc_id
+ * app_code: db/app/mediahub/loc_code
+ */
+
+ m->plugin = vconf_get_str(KEY_LOC_PLUGIN);
+ if (!m->plugin) {
+ _ERR("Please set plugin to %s", KEY_LOC_PLUGIN);
+ return false;
+ }
+
+ id = vconf_get_str(KEY_LOC_ID);
+ if (!id) {
+ _ERR("Please set app_id to %s", KEY_LOC_ID);
+ goto err_id;
+ }
+
+ code = vconf_get_str(KEY_LOC_CODE);
+ if (!id) {
+ _ERR("Please set app_code to %s", KEY_LOC_CODE);
+ goto err_code;
+ }
+
+ snprintf(str, sizeof(str), "%s/%s", id, code);
+ m->key = strdup(str);
+
+ return true;
+
+err_code:
+ free(id);
+err_id:
+ free(m->plugin);
+ return false;
+}
+
+struct locmgr *locmgr_create(void)
+{
+ struct locmgr *m;
+ maps_service_h maps;
+ maps_preference_h preference;
+ int r;
+ bool s;
+
+ m = calloc(1, sizeof(*m));
+ if (!m) {
+ _ERR("failed to allocate");
+ return false;
+ }
+
+ s = _set_plugin(m);
+ if (!s) {
+ _ERR("can't get location information");
+ goto err;
+ }
+
+ r = maps_service_foreach_provider(_maps_provider_cb, m);
+ if (r != MAPS_ERROR_NONE) {
+ _ERR("failed to create maps service");
+ goto err_plugin;
+ }
+
+ if (!m->supported) {
+ _ERR("%s does not support", m->plugin);
+ goto err_plugin;
+ }
+
+ r = maps_service_create(m->plugin, &maps);
+ if (r != MAPS_ERROR_NONE) {
+ _ERR("failed to create maps service");
+ goto err_plugin;
+ }
+
+ r = maps_service_set_provider_key(maps, m->key);
+ if (r != MAPS_ERROR_NONE) {
+ _ERR("failed to set provider key");
+ goto err_maps;
+ }
+
+ r = maps_service_provider_is_service_supported(maps,
+ MAPS_SERVICE_REVERSE_GEOCODE, &s);
+ if (r != MAPS_ERROR_NONE || !s) {
+ _ERR("not support reverse geocode");
+ goto err_maps;
+ }
+
+ r = _set_preference(&preference);
+ if (r != MAPS_ERROR_NONE) {
+ _ERR("failed to create preference");
+ goto err_maps;
+ }
+
+ r = maps_service_set_preference(maps, preference);
+ if (r != MAPS_ERROR_NONE) {
+ _ERR("failed to set preference");
+ goto err_preference;
+ }
+
+ media_content_connect();
+
+ m->maps = maps;
+ m->preference = preference;
+ m->queue = 0;
+
+ return m;
+
+err_preference:
+ maps_preference_destroy(preference);
+err_maps:
+ maps_service_destroy(maps);
+err_plugin:
+ free(m->plugin);
+ free(m->key);
+err:
+ free(m);
+ return NULL;
+}
+
+void locmgr_destroy(struct locmgr *m)
+{
+ if (!m) {
+ _ERR("invalid argument");
+ return;
+ }
+
+ media_content_disconnect();
+
+ if (m->preference) {
+ maps_preference_destroy(m->preference);
+ m->preference = NULL;
+ }
+
+ if (m->maps) {
+ /*
+ * FIXME:
+ * because maps_service_destroy function have a problem,
+ * disable calling this function temporary
+ */
+ /*maps_service_destroy(m->maps);*/
+ m->maps = NULL;
+ }
+
+ if (m->list) {
+ eina_list_free(m->list);
+ m->list = NULL;
+ }
+
+ free(m->plugin);
+ free(m->key);
+ free(m);
+}