// found in the LICENSE file.
var _callbacks = {};
-var _nextReplyId = 0;
+var _nextReplyId = 1; // 0 is reserved for events
function getNextReplyId() {
return _nextReplyId++;
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];
}
function ContentManager() {
+ this.changeListener = null;
}
ContentManager.prototype.update = function(content) {
});
};
-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();
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://");
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();
picojson::value::object& reply) {
reply["isError"] = picojson::value(false);
reply["replyId"] = picojson::value(msg.get("replyId").get<double>());
-
+ 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());
}
}
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<void*>(&folderList)) != MEDIA_CONTENT_ERROR_NONE) {
std::cerr << "media_folder_foreach_folder_from_db: error" << std::endl;
} else {
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;
}
if (media_info_foreach_media_from_db(filterHandle,
- mediaInfoCallback,
+ MediaInfoCallback,
reinterpret_cast<ContentFolderList*>(&itemList))
!= MEDIA_CONTENT_ERROR_NONE) {
std::cerr << "media_info_foreach_media_from_db: error" << std::endl;
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;
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<ContentInstance*>(user_data);
+
+ picojson::value::object om;
+ om["replyId"] = picojson::value(static_cast<double>(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<double>(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;
<button onClick="handleGetDirectories()">Get Directories</button>
<button onClick="handleFind()">Find</button>
<button onClick="handleScanFile()">Scan File</button>
+<button onClick="enableEvents()">Listener (ON)</button>
+<button onClick="disableEvents()">Listener (OFF)</button>
<div>
<h2>Attribute Filter</h2>
function(err) {
debug(err.name);
});
- }
- catch (err) {
+ } catch (err) {
debug(err.name);
}
}
function(err) {
debug('find: error');
}, null, filter);
- }
- catch (err) {
+ } catch (err) {
debug(err.name);
}
}
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);
}
}