From: Sakari Poussa Date: Fri, 13 Jun 2014 07:01:38 +0000 (+0300) Subject: [Content] Add listeners and events support X-Git-Tag: accepted/tizen/common/20140630.080101~2^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8566cd33aec1c354d957054a35bf9814f75519ca;p=platform%2Fframework%2Fweb%2Ftizen-extensions-crosswalk.git [Content] Add listeners and events support Add support for subscribing to media content change events via setChangeListeners and unsetChangeListeners methods. Also, some debug macro tunings. --- diff --git a/content/content_api.js b/content/content_api.js index 0491f93..a702533 100644 --- a/content/content_api.js +++ b/content/content_api.js @@ -3,7 +3,7 @@ // found in the LICENSE file. var _callbacks = {}; -var _nextReplyId = 0; +var _nextReplyId = 1; // 0 is reserved for events function getNextReplyId() { return _nextReplyId++; @@ -25,7 +25,16 @@ extension.setMessageListener(function(msg) { var replyId = m.replyId; var callback = _callbacks[replyId]; - if (typeof(callback) === 'function') { + if (replyId == 0) { // replyId zero is for events + if (exports.changeListener != null) { + if (m.eventType == 'INSERT') + exports.changeListener.oncontentadded(m.value); + else if (m.eventType == 'DELETE') + exports.changeListener.oncontentremoved(m.value.id); + else if (m.eventType == 'UPDATE') + exports.changeListener.oncontentupdated(m.value); + } + } else if (typeof(callback) === 'function') { callback(m); delete m.replyId; delete _callbacks[replyId]; @@ -94,6 +103,7 @@ function ContentVideo(obj, album, artists, duration, width, height) { } function ContentManager() { + this.changeListener = null; } ContentManager.prototype.update = function(content) { @@ -216,13 +226,23 @@ ContentManager.prototype.scanFile = function(contentURI, onsuccess, onerror) { }); }; -ContentManager.prototype.setChangeListener = function(onchange) { - if (!xwalk.utils.validateArguments('f', arguments)) { +ContentManager.prototype.setChangeListener = function(listener) { + if (!xwalk.utils.validateArguments('o', arguments)) { + throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR); + } + + if (!xwalk.utils.validateObject(listener, 'fff', + ['oncontentadded', 'oncontentupdated', 'oncontentremoved'])) { throw new tizen.WebAPIException(tizen.WebAPIException.TYPE_MISMATCH_ERR); } + + this.changeListener = listener; + sendSyncMessage({cmd: 'ContentManager.setChangeListener'}); }; -ContentManager.prototype.unsetChangeLIstener = function() { +ContentManager.prototype.unsetChangeListener = function() { + this.changeListener = null; + sendSyncMessage({cmd: 'ContentManager.unsetChangeListener'}); }; exports = new ContentManager(); diff --git a/content/content_instance.cc b/content/content_instance.cc index 38518ee..67ccf50 100644 --- a/content/content_instance.cc +++ b/content/content_instance.cc @@ -18,6 +18,7 @@ namespace { const std::string STR_FILTER("filter"); const std::string STR_CONTENT_URI("contentURI"); +const std::string STR_EVENT_TYPE("eventType"); std::string createUriFromLocalPath(const std::string path) { static std::string fileScheme("file://"); @@ -64,7 +65,7 @@ void ContentInstance::HandleMessage(const char* message) { std::cerr << "Ignoring message.\n"; return; } -#ifdef DEBUG_JSON +#ifdef DEBUG_JSON_CMD std::cout << "HandleMessage: " << message << std::endl; #endif std::string cmd = v.get("cmd").to_str(); @@ -94,7 +95,11 @@ void ContentInstance::PostAsyncSuccessReply(const picojson::value& msg, picojson::value::object& reply) { reply["isError"] = picojson::value(false); reply["replyId"] = picojson::value(msg.get("replyId").get()); - + if (msg.contains(STR_EVENT_TYPE)) + reply[STR_EVENT_TYPE] = picojson::value(msg.get(STR_EVENT_TYPE)); +#ifdef DEBUG_JSON_CMD + std::cout << "reply: " << msg.serialize().c_str() << std::endl; +#endif picojson::value v(reply); PostMessage(v.serialize().c_str()); } @@ -112,12 +117,42 @@ void ContentInstance::PostAsyncSuccessReply(const picojson::value& msg, } void ContentInstance::HandleSyncMessage(const char* message) { + picojson::value v; + picojson::value::object o; + + std::string err; + picojson::parse(v, message, message + strlen(message), &err); + if (!err.empty()) { + std::cerr << "Ignoring message.\n"; + return; + } +#ifdef DEBUG_JSON_CMD + std::cout << "HandleSyncMessage: " << message << std::endl; +#endif + std::string cmd = v.get("cmd").to_str(); + int rc = MEDIA_CONTENT_ERROR_INVALID_OPERATION; + + if (cmd == "ContentManager.setChangeListener") { + rc = media_content_set_db_updated_cb(MediaContentChangeCallback, this); + } else if (cmd == "ContentManager.unsetChangeListener") { + rc = media_content_unset_db_updated_cb(); + } else { + std::cerr << "Message " + cmd + " is not supported.\n"; + } + + if (rc != MEDIA_CONTENT_ERROR_NONE) + std::cerr << "error " << cmd << std::endl; + +#ifdef DEBUG_JSON_CMD + std::cout << "Reply: " << v.serialize().c_str() << std::endl; +#endif + SendSyncReply(v.serialize().c_str()); } void ContentInstance::HandleGetDirectoriesRequest(const picojson::value& msg) { ContentFolderList folderList; if (media_folder_foreach_folder_from_db(NULL, - mediaFolderCallback, + MediaFolderCallback, reinterpret_cast(&folderList)) != MEDIA_CONTENT_ERROR_NONE) { std::cerr << "media_folder_foreach_folder_from_db: error" << std::endl; } else { @@ -147,7 +182,7 @@ void ContentInstance::HandleGetDirectoriesReply(const picojson::value& msg, PostAsyncSuccessReply(msg, value); } -bool ContentInstance::mediaFolderCallback(media_folder_h handle, +bool ContentInstance::MediaFolderCallback(media_folder_h handle, void* user_data) { if (!user_data) return false; @@ -181,7 +216,7 @@ void ContentInstance::HandleFindRequest(const picojson::value& msg) { } if (media_info_foreach_media_from_db(filterHandle, - mediaInfoCallback, + MediaInfoCallback, reinterpret_cast(&itemList)) != MEDIA_CONTENT_ERROR_NONE) { std::cerr << "media_info_foreach_media_from_db: error" << std::endl; @@ -257,14 +292,14 @@ void ContentInstance::HandleFindReply( items.push_back(picojson::value(o)); } picojson::value value(items); -#ifdef DEBUG_JSON +#ifdef DEBUG_JSON_REPLY std::cout << "JSON reply: " << std::endl << value.serialize().c_str() << std::endl; #endif PostAsyncSuccessReply(msg, value); } -bool ContentInstance::mediaInfoCallback(media_info_h handle, void* user_data) { +bool ContentInstance::MediaInfoCallback(media_info_h handle, void* user_data) { if (!user_data) return false; @@ -279,6 +314,54 @@ bool ContentInstance::mediaInfoCallback(media_info_h handle, void* user_data) { return true; } +void ContentInstance::MediaContentChangeCallback( + media_content_error_e error, + int pid, + media_content_db_update_item_type_e update_item, + media_content_db_update_type_e update_type, + media_content_type_e media_type, + char* uuid, + char* path, + char* mime_type, + void* user_data) { +#ifdef DEBUG_ITEM + std::cout << "MediaContentChangeCallback: error=" << error << + ", item=" << update_item << ", type=" << update_type << ", " << + uuid << ", " << path << std::endl; +#endif + if (!user_data) + return; + + ContentInstance* self = + reinterpret_cast(user_data); + + picojson::value::object om; + om["replyId"] = picojson::value(static_cast(0)); + const std::string type = (update_type == MEDIA_CONTENT_INSERT ? + "INSERT" : (update_type == MEDIA_CONTENT_DELETE ? "DELETE" : "UPDATE")); + om[STR_EVENT_TYPE] = picojson::value(type); + picojson::value::object ov; + ov["type"] = picojson::value(static_cast(media_type)); + + if (uuid) + ov["id"] = picojson::value(uuid); + + if (path) + ov["contentURI"] = picojson::value(path); + + if (mime_type) + ov["mimeType"] = picojson::value(mime_type); + + picojson::value msg(om); + picojson::value value(ov); +#ifdef DEBUG_JSON_REPLY + std::cout << "JSON event msg: " << msg.serialize().c_str() << std::endl; + std::cout << "JSON event val: " << value.serialize().c_str() << std::endl; +#endif + + self->PostAsyncSuccessReply(msg, value); +} + void ContentFolder::init(media_folder_h handle) { char* str = NULL; time_t date; diff --git a/content/content_instance.h b/content/content_instance.h index a38eaef..8285455 100644 --- a/content/content_instance.h +++ b/content/content_instance.h @@ -48,8 +48,18 @@ class ContentInstance : public common::Instance { void PostAsyncSuccessReply(const picojson::value&); // Tizen CAPI helpers - static bool mediaFolderCallback(media_folder_h handle, void *user_data); - static bool mediaInfoCallback(media_info_h handle, void *user_data); + static bool MediaFolderCallback(media_folder_h handle, void *user_data); + static bool MediaInfoCallback(media_info_h handle, void *user_data); + static void MediaContentChangeCallback( + media_content_error_e error, + int pid, + media_content_db_update_item_type_e update_item, + media_content_db_update_type_e update_type, + media_content_type_e media_type, + char* uuid, + char* path, + char* mime_type, + void* user_data); static unsigned m_instanceCount; }; diff --git a/examples/content.html b/examples/content.html index 93bc419..369c06f 100644 --- a/examples/content.html +++ b/examples/content.html @@ -9,6 +9,8 @@ + +

Attribute Filter

@@ -60,8 +62,7 @@ function handleGetDirectories() function(err) { debug(err.name); }); - } - catch (err) { + } catch (err) { debug(err.name); } } @@ -89,8 +90,7 @@ function handleFind() function(err) { debug('find: error'); }, null, filter); - } - catch (err) { + } catch (err) { debug(err.name); } } @@ -105,8 +105,36 @@ function handleScanFile() function(err) { debug("scan ERR: ") }); + } catch (err) { + debug(err.name); } - catch (err) { +} +var listener = { + oncontentadded: function(content) { + debug("Event ADD: " + content.contentURI); + }, + oncontentupdated: function(content) { + debug("Event UPDATE: " + content.contentURI); + }, + oncontentremoved: function(id) { + debug("Event REMOVE: " + id); + } + }; + +function enableEvents() { + try { + debug('tizen.content.setChangeListener:'); + tizen.content.setChangeListener(listener); + } catch (err) { + debug(err.name); + } +} + +function disableEvents() { + try { + debug('tizen.content.unsetChangeListener:'); + tizen.content.unsetChangeListener(); + } catch (err) { debug(err.name); } }