[mediacontroller][common][webapi-plugins.spec][tizen] Implementation for search API. 66/201566/38
authorMichal Michalski <m.michalski2@partner.samsung.com>
Wed, 3 Apr 2019 10:49:20 +0000 (12:49 +0200)
committerMichal Michalski <m.michalski2@partner.samsung.com>
Tue, 6 Aug 2019 08:31:06 +0000 (10:31 +0200)
http://suprem.sec.samsung.net/jira/browse/TWDAPI-208

Implementation for search API.

[Verification] Manual API testing.
tct-mediacontroller-tizen-tests 100% pass
tct-messageport-tizen-tests 100% pass

Signed-off-by: Michal Michalski <m.michalski2@partner.samsung.com>
Change-Id: I47cb4b3234e212db77ed20c4f899f4b5bed2d662

src/mediacontroller/mediacontroller_api.js
src/mediacontroller/mediacontroller_client.cc
src/mediacontroller/mediacontroller_client.h
src/mediacontroller/mediacontroller_instance.cc
src/mediacontroller/mediacontroller_instance.h
src/mediacontroller/mediacontroller_server.cc
src/mediacontroller/mediacontroller_server.h
src/mediacontroller/mediacontroller_utils.cc
src/mediacontroller/mediacontroller_utils.h
src/tizen/tizen_api.js

index 5c9ceb1..0eec9e5 100755 (executable)
@@ -60,6 +60,8 @@ ListenerManager.prototype.addListener = function(callback) {
     return id;
 };
 
+
+
 ListenerManager.prototype.addServerInfoListener = function(callback, name) {
     var id = this.nextId;
     if (!this.nativeSet) {
@@ -298,6 +300,15 @@ var MediaControllerContentAgeRating = {
     NINETEEN: '19'
 };
 
+var MediaControllerSearchCategory = {
+  NO_CATEGORY: "NO_CATEGORY",
+  TITLE: "TITLE",
+  ARTIST: "ARTIST",
+  ALBUM: "ALBUM",
+  GENRE: "GENRE",
+  TPO: "TPO"
+};
+
 var MediaControllerContentType = {
     IMAGE: 'IMAGE',
     MUSIC: 'MUSIC',
@@ -1016,7 +1027,6 @@ MediaControllerServer.prototype.getAllPlaylists = function(
 
         native_.callIfPossible(args.successCallback, playlists);
     };
-
     var result = native_.call('MediaControllerServer_getAllPlaylists', {}, callback);
 
     if (native_.isFailure(result)) {
@@ -1024,6 +1034,74 @@ MediaControllerServer.prototype.getAllPlaylists = function(
     }
 };
 
+function RequestReply(data, code) {
+  xwalk.utils.validator.isConstructorCall(this, RequestReply);
+  this.code = xwalk.utils.converter.toLong(code);
+  if (xwalk.utils.type.isUndefined(data)) {
+    this.data = null;
+  }
+  else if (!(data instanceof tizen.Bundle)) {
+    this.data = new tizen.Bundle(data);
+  }
+  else {
+    this.data = data;
+  }
+}
+
+MediaControllerServer.prototype.setSearchRequestListener = function(listener) {
+  var args = validator_.validateArgs(arguments, [
+    {name: 'listener', type: types_.FUNCTION}
+  ]);
+
+  if (!native_.isListenerSet("SearchRequestListener")) {
+    var result = native_.callSync('MediaControllerServer_addSearchRequestListener', {
+        listenerId: "SearchRequestListener"
+    });
+    if (native_.isFailure(result)) {
+      throw native_.getErrorObject(result);
+    }
+  }
+
+  var callback = function (msg) {
+      var request = [];
+      msg.request.forEach(function (filter) {
+        request.push(new SearchFilter(
+          filter.contentType,
+          filter.category,
+          filter.keyword,
+          filter.extraData
+        ));
+      });
+
+      var reply = args.listener(msg.clientName, request);
+      if (type_.isUndefined(reply)) {
+        reply = null;
+      }
+
+      var nativeData = {
+        clientName: msg.clientName,
+        requestId: msg.requestId,
+        reply: reply,
+        replyType: "RequestReply"
+      };
+
+      var result = native_.callSync('MediaControllerServer_replyCommand', nativeData);
+      if (native_.isFailure(result)) {
+        throw native_.getErrorObject(result);
+      }
+  }
+
+  native_.addListener("SearchRequestListener", callback);
+}
+
+MediaControllerServer.prototype.unsetSearchRequestListener = function() {
+  var result = native_.callSync('MediaControllerServer_removeSearchRequestListener');
+  if (native_.isFailure(result)) {
+    throw native_.getErrorObject(result);
+  }
+  native_.removeListener("SearchRequestListener");
+}
+
 function MediaControllerClient() {}
 
 MediaControllerClient.prototype.findServers = function(successCallback, errorCallback) {
@@ -1065,6 +1143,92 @@ MediaControllerClient.prototype.getLatestServerInfo = function() {
     return serverInfo;
 };
 
+function SearchFilter(contentType, category, keyword, extraData) {
+  validator_.isConstructorCall(this, SearchFilter);
+  var args = validator_.validateArgs(arguments, [
+      {name: 'contentType', type: types_.ENUM, values: Object.values(MediaControllerContentType)},
+      {name: 'category', type: types_.ENUM, values: Object.values(MediaControllerSearchCategory), optional: true},
+      {name: 'keyword', type: types_.STRING, nullable: true, optional: true},
+  ]);
+
+  if (!args.hasOwnProperty("category")) {args.category = "NO_CATEGORY";}
+  if (!args.hasOwnProperty("keyword")) {args.keyword = null;}
+
+  extraData = xwalk.utils.type.isUndefined(extraData) ? null : extraData;
+  args.extraData = xwalk.utils.type.isNull(extraData) ? null : new tizen.Bundle(extraData);
+
+  var extraData_ = args.extraData;
+  var contentType_ = args.contentType;
+  var category_ = args.category;
+  var keyword_ = args.keyword;
+
+  // keyword can be null only when category is NO_CATEGORY
+  if (xwalk.utils.type.isNull(keyword_) && category_ != MediaControllerSearchCategory.NO_CATEGORY) {
+    throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR);
+  }
+
+  Object.defineProperties(this, {
+    contentType: {
+      enumerable: true,
+      get: function () { return contentType_; },
+      set: function (newContentType) {
+        var args = validator_.validateArgs(arguments, [{
+            name: 'newContentType',
+            type: types_.ENUM,
+            values: Object.values(MediaControllerContentType)
+        }]);
+        contentType_ = args.newContentType;
+      }
+    },
+    category: {
+      enumerable: true,
+      get: function () { return category_; },
+      set: function (newCategory) {
+        var args = validator_.validateArgs(arguments, [{
+          name: 'newCategory',
+          type: types_.ENUM,
+          values: Object.values(MediaControllerSearchCategory)
+        }]);
+
+        // Keyword can be null only if category is NO_CATEGORY.
+        if (xwalk.utils.type.isNull(keyword_) && args.newCategory != MediaControllerSearchCategory.NO_CATEGORY) {
+          throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR);
+        }
+
+        category_ = args.newCategory;
+      }
+    },
+    keyword: {
+      enumerable: true,
+      get: function () { return keyword_; },
+      set: function (newKeyword) {
+        var args = validator_.validateArgs(arguments, [{
+          name: 'newKeyword',
+          type: types_.STRING,
+          nullable: true
+        }]);
+
+        // Keyword can only be null if category is NO_CATEGORY.
+        if (xwalk.utils.type.isNull(args.newKeyword) && this.category != MediaControllerSearchCategory.NO_CATEGORY) {
+          throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR);
+        }
+
+        keyword_ = args.newKeyword;
+      }
+    },
+    extraData: {
+      enumerable: true,
+      get: function () { return extraData_ },
+      set: function (newData) {
+        if (xwalk.utils.type.isUndefined(newData)) {
+          newData = null;
+        }
+        extraData_ = xwalk.utils.type.isNull(newData) ? null : new tizen.Bundle(newData);
+      }
+    }
+  });
+}
+
 function MediaControllerServerInfo(data) {
     Object.defineProperties(this, {
         name: {
@@ -1322,6 +1486,38 @@ MediaControllerServerInfo.prototype.sendCommand = function(
     ReplyCommandListener.requestIdToListenerId[replyListenerId] = result.requestId;
 };
 
+MediaControllerServerInfo.prototype.sendSearchRequest = function(request, successCallback, errorCallback) {
+  var args = validator_.validateArgs(arguments, [
+    {name: 'request', type: types_.ARRAY, values: SearchFilter},
+    {name: 'successCallback', type: types_.FUNCTION},
+    {name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true}
+  ]);
+
+  if (args.request.length < 1 || args.request.length > 20) {
+    throw new WebAPIException(WebAPIException.INVALID_VALUES_ERR);
+  }
+
+  var callback = function(result) {
+    if (native_.isFailure(result)) {
+      native_.callIfPossible(args.errorCallback, native_.getErrorObject(result));
+      return;
+    }
+    var reply = native_.getResultObject(result);
+    native_.callIfPossible(args.successCallback, new RequestReply(reply.data, reply.code));
+  };
+
+  var nativeData = {
+    request: args.request,
+    name: this.name,
+    listenerId: ReplyCommandListener.listenerName
+  };
+
+  var replyListenerId = ReplyCommandListener.addListener(callback);
+  var result = native_.callSync('MediaControllerServerInfo_sendSearchRequest', nativeData, callback);
+
+  ReplyCommandListener.requestIdToListenerId[replyListenerId] = result.requestId;
+}
+
 MediaControllerServerInfo.prototype.addServerStatusChangeListener = function(listener) {
     var args = validator_.validateArgs(arguments, [
         { name: 'listener', type: types_.FUNCTION }
@@ -1627,3 +1823,6 @@ MediaControllerPlaylist.prototype.getItems = function(successCallback, errorCall
 };
 
 exports = new MediaControllerManager();
+exports.SearchFilter = SearchFilter;
+exports.RequestReply = RequestReply;
+
index 749ff21..7d6c20c 100644 (file)
@@ -32,6 +32,7 @@ using common::PlatformResult;
 using common::ErrorCode;
 using common::tools::ReportError;
 using common::tools::ReportSuccess;
+using common::JsonToBundle;
 
 MediaControllerClient::MediaControllerClient() : handle_(nullptr) {
   ScopeLogger();
@@ -540,6 +541,87 @@ void MediaControllerClient::OnMetadataUpdate(const char* server_name, mc_metadat
   client->playback_info_listener_(&data);
 }
 
+PlatformResult MediaControllerClient::SendSearchRequest(const std::string& server_name,
+                                                        const picojson::value& request,
+                                                        const JsonCallback& callback,
+                                                        char** request_id)
+{
+  ScopeLogger();
+  mc_search_h search_request;
+  SCOPE_EXIT {
+    mc_search_destroy(search_request);
+  };
+
+  int ret = mc_search_create(&search_request);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+      ErrorCode::UNKNOWN_ERR, "Unable to create search request.",
+      ("mc_search_create error: %d, message: %s", ret, get_error_message(ret)));
+  }
+
+  if (!request.is<picojson::array>()) {
+    return LogAndCreateResult(
+        ErrorCode::INVALID_VALUES_ERR,
+        "MediaControllerClient::SendSearchRequest request param is not an array.");
+  }
+
+  for (const auto& filter_obj: request.get<picojson::array>()) {
+    const picojson::object& filter = filter_obj.get<picojson::object>();
+
+    // contentType
+    std::string content_type_str = filter.at("contentType").get<std::string>();
+    mc_content_type_e content_type_e;
+    PlatformResult result = types::MediaControllerContentTypeEnum.getValue(content_type_str, &content_type_e);
+    if (!result) {
+        LoggerE("MediaControllerContentTypeEnum.getValue(%s) failed.", content_type_str.c_str());
+        return result;
+    }
+
+    // category
+    std::string search_category_str = filter.at("category").get<std::string>();
+    mc_search_category_e search_category_e;
+    result = types::MediaControllerSearchCategoryEnum.getValue(search_category_str, &search_category_e);
+    if (!result) {
+        LoggerE("MediaControllerSearchCategoryEnum.getValue(%s) failed.", search_category_str.c_str());
+        return result;
+    }
+
+    // extra data
+    bundle* bundle_data = nullptr;
+    SCOPE_EXIT { bundle_free(bundle_data); };
+    result = JsonToBundle(filter.at("extraData"), &bundle_data);
+    if (!result) {
+      return LogAndCreateResult(
+        ErrorCode::INVALID_VALUES_ERR, "Unable to add data to bundle",
+        ("JsonToBundle() error message: %s", result.message().c_str()));
+    }
+
+    ret = mc_search_set_condition(
+      search_request,
+      content_type_e,
+      search_category_e,
+      filter.at("keyword").get<std::string>().c_str(),
+      bundle_data);
+
+    if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+      return LogAndCreateResult(
+        ErrorCode::UNKNOWN_ERR, "Unable to set search condition.",
+        ("mc_search_set_condition error: %d, message: %s", ret, get_error_message(ret)));
+    }
+  }
+
+  ret = mc_client_send_search_cmd(handle_, server_name.c_str(), search_request, request_id);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(
+      ErrorCode::UNKNOWN_ERR, "Unable to send search request.",
+      ("mc_client_send_search_cmd error: %d, message: %s", ret, get_error_message(ret)));
+  }
+
+  command_reply_callback_ = callback;
+
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
 PlatformResult MediaControllerClient::SendCommand(const std::string& server_name,
                                                   const std::string& command,
                                                   const picojson::value& data,
@@ -593,6 +675,7 @@ void MediaControllerClient::OnCommandReply(const char* server_name, const char*
 
   reply_o["data"] = data;
   reply_o["name"] = picojson::value(server_name);
+  reply_o["code"] = picojson::value(static_cast<double>(result_code));
 
   if (nullptr == request_id) {
     LoggerE("Request id is null.");
index a07f533..f41fa79 100644 (file)
@@ -47,6 +47,11 @@ class MediaControllerClient {
   common::PlatformResult SendRepeatMode(const std::string& server_name, bool mode);
   common::PlatformResult SendRepeatState(const std::string& server_name, const std::string& state);
 
+  common::PlatformResult SendSearchRequest(const std::string& server_name,
+                                           const picojson::value& request,
+                                           const JsonCallback& callback,
+                                           char** request_id);
+
   common::PlatformResult SendCommand(const std::string& server_name, const std::string& command,
                                      const picojson::value& data, const JsonCallback& reply_cb,
                                      char** request_id);
index 2629d35..e39eab0 100644 (file)
@@ -69,6 +69,10 @@ MediaControllerInstance::MediaControllerInstance() {
                 MediaControllerServerAddChangeRequestPlaybackInfoListener);
   REGISTER_SYNC("MediaControllerServer_removeChangeRequestPlaybackInfoListener",
                 MediaControllerServerRemoveChangeRequestPlaybackInfoListener);
+  REGISTER_SYNC("MediaControllerServer_addSearchRequestListener",
+                MediaControllerServerAddSearchRequestListener);
+  REGISTER_SYNC("MediaControllerServer_removeSearchRequestListener",
+                MediaControllerServerRemoveSearchRequestListener);
   REGISTER_SYNC("MediaControllerServer_addCommandListener",
                 MediaControllerServerAddCommandListener);
   REGISTER_SYNC("MediaControllerServer_replyCommand", MediaControllerServerReplyCommand);
@@ -98,6 +102,8 @@ MediaControllerInstance::MediaControllerInstance() {
                  MediaControllerServerInfoSendRepeatState);
   REGISTER_ASYNC("MediaControllerServerInfo_sendShuffleMode",
                  MediaControllerServerInfoSendShuffleMode);
+  REGISTER_ASYNC("MediaControllerServerInfo_sendSearchRequest",
+                 MediaControllerServerInfoSendSearchRequest);
   REGISTER_ASYNC("MediaControllerServerInfo_sendCommand", MediaControllerServerInfoSendCommand);
   REGISTER_SYNC("MediaControllerServerInfo_addServerStatusChangeListener",
                 MediaControllerServerInfoAddServerStatusChangeListener);
@@ -412,6 +418,50 @@ void MediaControllerInstance::MediaControllerServerRemoveChangeRequestPlaybackIn
   }
 }
 
+void MediaControllerInstance::MediaControllerServerAddSearchRequestListener(
+    const picojson::value& args,
+    picojson::object& out) {
+  ScopeLogger();
+
+  if (!server_) {
+    LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Server not initialized."), &out,
+                      ("Failed: server_"));
+    return;
+  }
+
+  JsonCallback on_request = [this, args](picojson::value* request) -> void {
+    picojson::object& request_o = request->get<picojson::object>();
+    request_o["listenerId"] = args.get("listenerId");
+    Instance::PostMessage(this, request->serialize().c_str());
+  };
+
+  auto result = server_->SetSearchRequestListener(on_request);
+  if (!result) {
+    LogAndReportError(result, &out);
+    return;
+  }
+
+  ReportSuccess(out);
+}
+
+void MediaControllerInstance::MediaControllerServerRemoveSearchRequestListener(
+    const picojson::value& args,
+    picojson::object& out) {
+  ScopeLogger();
+
+  if (!server_) {
+    LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Server not initialized."),
+                      &out, ("Failed: server_"));
+    return;
+  }
+
+  auto result = server_->UnsetSearchRequestListener();
+  if (!result) {
+    LogAndReportError(result, &out);
+    return;
+  }
+}
+
 void MediaControllerInstance::MediaControllerServerAddCommandListener(const picojson::value& args,
                                                                       picojson::object& out) {
   ScopeLogger();
@@ -445,13 +495,27 @@ void MediaControllerInstance::MediaControllerServerReplyCommand(const picojson::
     return;
   }
 
-  CHECK_EXIST(args, "clientName", out)
-  CHECK_EXIST(args, "requestId", out)
-  CHECK_EXIST(args, "data", out)
+  CHECK_EXIST(args, "clientName", out);
+  CHECK_EXIST(args, "requestId", out);
+  CHECK_EXIST(args, "reply", out);
+  CHECK_EXIST(args, "replyType", out);
+
+  int code = 0;
+  picojson::value data;
+
+  if (args.get("replyType").get<std::string>() == "RequestReply") {
+    CHECK_EXIST(args.get("reply"), "code", out);
+    CHECK_EXIST(args.get("reply"), "data", out);
+    code = static_cast<int>(args.get("reply").get("code").get<double>());
+    data = args.get("reply").get<picojson::object>().at("data");
+  }
+  else {
+    data = args.get("reply");
+  }
 
-  picojson::value json = args.get("data");
   auto result = server_->CommandReply(args.get("clientName").get<std::string>(),
-                                      args.get("requestId").get<std::string>(), json);
+                                      args.get("requestId").get<std::string>(),
+                                      code, data);
 
   if (!result) {
     LogAndReportError(result, &out);
@@ -890,6 +954,47 @@ void MediaControllerInstance::MediaControllerServerInfoSendRepeatState(const pic
   ReportSuccess(out);
 }
 
+void MediaControllerInstance::MediaControllerServerInfoSendSearchRequest(
+    const picojson::value& args,
+    picojson::object& out) {
+  ScopeLogger();
+
+  if (!client_) {
+    LogAndReportError(PlatformResult(ErrorCode::UNKNOWN_ERR, "Client not initialized."), &out,
+                      ("Failed: client_"));
+    return;
+  }
+
+  CHECK_EXIST(args, "listenerId", out);
+  CHECK_EXIST(args, "name", out);
+  CHECK_EXIST(args, "request", out);
+
+  JsonCallback reply_cb = [this, args](picojson::value* reply) -> void {
+    picojson::object& reply_obj = reply->get<picojson::object>();
+    reply_obj["listenerId"] = args.get("listenerId");
+    Instance::PostMessage(this, reply->serialize().c_str());
+  };
+
+  char* request_id = nullptr;
+  SCOPE_EXIT {
+    free(request_id);
+  };
+
+  PlatformResult result = client_->SendSearchRequest(
+    args.get("name").get<std::string>(),
+    args.get("request"),
+    reply_cb,
+    &request_id);
+
+  if (result) {
+    ReportSuccess(out);
+    out["requestId"] = picojson::value(std::string(request_id));
+  }
+  else {
+    LogAndReportError(result, &out, ("Failed to send command."));
+  }
+}
+
 void MediaControllerInstance::MediaControllerServerInfoSendCommand(const picojson::value& args,
                                                                    picojson::object& out) {
   ScopeLogger();
index 20a7e1d..829a332 100644 (file)
@@ -49,8 +49,12 @@ class MediaControllerInstance : public common::ParsedInstance {
                                                                  picojson::object& out);
   void MediaControllerServerRemoveChangeRequestPlaybackInfoListener(const picojson::value& args,
                                                                     picojson::object& out);
-  void MediaControllerServerAddCommandListener(const picojson::value& args, picojson::object& out);
+
+  void MediaControllerServerAddSearchRequestListener(const picojson::value& args, picojson::object& out);
+  void MediaControllerServerRemoveSearchRequestListener(const picojson::value& args, picojson::object& out);
+
   void MediaControllerServerReplyCommand(const picojson::value& args, picojson::object& out);
+  void MediaControllerServerAddCommandListener(const picojson::value& args, picojson::object& out);
   void MediaControllerServerRemoveCommandListener(const picojson::value& args,
                                                   picojson::object& out);
   void MediaControllerServerCreatePlaylist(const picojson::value& args, picojson::object& out);
@@ -72,6 +76,7 @@ class MediaControllerInstance : public common::ParsedInstance {
   void MediaControllerServerInfoSendRepeatMode(const picojson::value& args, picojson::object& out);
   void MediaControllerServerInfoSendRepeatState(const picojson::value& args, picojson::object& out);
   void MediaControllerServerInfoSendShuffleMode(const picojson::value& args, picojson::object& out);
+  void MediaControllerServerInfoSendSearchRequest(const picojson::value& args, picojson::object& out);
   void MediaControllerServerInfoSendCommand(const picojson::value& args, picojson::object& out);
   void MediaControllerServerInfoAddServerStatusChangeListener(const picojson::value& args,
                                                               picojson::object& out);
index 0a2858e..266f8d7 100644 (file)
@@ -29,6 +29,7 @@ namespace mediacontroller {
 
 using common::PlatformResult;
 using common::ErrorCode;
+using common::BundleJsonIterator;
 
 MediaControllerServer::MediaControllerServer()
     : handle_(nullptr),
@@ -55,6 +56,10 @@ MediaControllerServer::~MediaControllerServer() {
     LoggerE("Failed to unset command listener");
   }
 
+  if (nullptr != search_request_listener_ && !UnsetSearchRequestListener()) {
+    LoggerE("Failed to unset search request listener");
+  }
+
   for (auto const& v : playlist_handle_map_) {
     if (MEDIA_CONTROLLER_ERROR_NONE != mc_playlist_destroy(v.second)) {
       LoggerE("Unable to destroy playlist %s", v.first.c_str());
@@ -297,6 +302,69 @@ PlatformResult MediaControllerServer::SetMetadata(const picojson::object& metada
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
+void MediaControllerServer::OnSearchRequestReceived(const char* client_name, const char* request_id,
+                                                    mc_search_h request, void* user_data) {
+  ScopeLogger();
+  MediaControllerServer* server = static_cast<MediaControllerServer*>(user_data);
+  if (nullptr == server->search_request_listener_) {
+    LoggerW("search_request_listener_ is not set");
+    return;
+  }
+
+  auto request_json = picojson::value(picojson::object());
+  auto& request_o = request_json.get<picojson::object>();
+
+  request_o["clientName"] = picojson::value(std::string(client_name));
+  request_o["requestId"] = picojson::value(std::string(request_id));
+
+  auto condition_cb = [](mc_content_type_e content_type, mc_search_category_e category,
+                         const char* keyword, bundle* data, void* user_data) -> bool {
+    LoggerD("condition callback for: %s", keyword);
+    auto filters = static_cast<picojson::array*>(user_data);
+
+    auto value = picojson::value(picojson::object());
+    auto& object = value.get<picojson::object>();
+
+    std::string temp;
+    PlatformResult result = types::MediaControllerContentTypeEnum.getName(content_type, &temp);
+    if (!result) {
+        LoggerE("MediaControllerContentTypeEnum.getName() failed with error message: %s", result.message().c_str());
+        return false;
+    }
+    object["contentType"] = picojson::value(temp);
+
+    result = types::MediaControllerSearchCategoryEnum.getName(category, &temp);
+    if (!result) {
+        LoggerE("MediaControllerSearchCategoryEnum.getName() failed with error message: %s", result.message().c_str());
+        return false;
+    }
+    object["category"] = picojson::value(temp);
+
+    object["keyword"] = picojson::value(std::string(keyword));
+
+    picojson::value data_json;
+    result = common::BundleToJson(data, &data_json);
+    if (!result) {
+        LoggerE("BundleToJson failed with error message: %s", result.message().c_str());
+        return false;
+    }
+    object["extraData"] = data_json;
+
+    filters->push_back(value);
+    return true;
+  };
+
+  picojson::array filters;
+  int ret = mc_search_foreach_condition(request, condition_cb, &filters);
+  if (ret != MEDIA_CONTROLLER_ERROR_NONE) {
+    LoggerE("mc_search_foreach_condition failed with error: %d", ret);
+    return;
+  }
+
+  request_o["request"] = picojson::value(filters);
+  server->search_request_listener_(&request_json);
+}
+
 void MediaControllerServer::OnCommandReceived(const char* client_name, const char* request_id,
                                               const char* command, bundle* bundle,
                                               void* user_data) {
@@ -323,6 +391,7 @@ void MediaControllerServer::OnCommandReceived(const char* client_name, const cha
 
 PlatformResult MediaControllerServer::CommandReply(const std::string& client_name,
                                                    const std::string& request_id,
+                                                   int code,
                                                    const picojson::value& data) {
   ScopeLogger();
 
@@ -340,7 +409,7 @@ PlatformResult MediaControllerServer::CommandReply(const std::string& client_nam
     }
   }
 
-  ret = mc_server_send_cmd_reply(handle_, client_name.c_str(), request_id.c_str(), 0, bundle);
+  ret = mc_server_send_cmd_reply(handle_, client_name.c_str(), request_id.c_str(), code, bundle);
   if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
     return LogAndCreateResult(
         ErrorCode::UNKNOWN_ERR, "Error sending command reply",
@@ -350,6 +419,32 @@ PlatformResult MediaControllerServer::CommandReply(const std::string& client_nam
   return PlatformResult(ErrorCode::NO_ERROR);
 }
 
+PlatformResult MediaControllerServer::SetSearchRequestListener(const JsonCallback& callback) {
+  ScopeLogger();
+
+  int ret = mc_server_set_search_cmd_received_cb(handle_, OnSearchRequestReceived, this);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to set search request callback.",
+             ("mc_server_set_search_cmd_received_cb() error: %d, message: %s",
+              ret, get_error_message(ret)));
+  }
+
+  search_request_listener_ = callback;
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
+PlatformResult MediaControllerServer::UnsetSearchRequestListener() {
+  ScopeLogger();
+  int ret = mc_server_unset_search_cmd_received_cb(handle_);
+  if (MEDIA_CONTROLLER_ERROR_NONE != ret) {
+    return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to unset search request callback.",
+                       ("mc_server_unset_search_cmd_received_cb() error: %d, message: %s",
+                        ret, get_error_message(ret)));
+  }
+  search_request_listener_ = nullptr;
+  return PlatformResult(ErrorCode::NO_ERROR);
+}
+
 PlatformResult MediaControllerServer::SetCommandListener(const JsonCallback& callback) {
   ScopeLogger();
 
index 6ad8be7..fc5a3bb 100644 (file)
@@ -44,8 +44,11 @@ class MediaControllerServer {
   common::PlatformResult SetChangeRequestPlaybackInfoListener(const JsonCallback& callback);
   common::PlatformResult UnsetChangeRequestPlaybackInfoListener();
 
+  common::PlatformResult SetSearchRequestListener(const JsonCallback& callback);
+  common::PlatformResult UnsetSearchRequestListener();
+
   common::PlatformResult CommandReply(const std::string& client_name, const std::string& request_id,
-                                      const picojson::value& data);
+                                      int code, const picojson::value& data);
 
   common::PlatformResult SetCommandListener(const JsonCallback& callback);
   common::PlatformResult UnsetCommandListener();
@@ -77,6 +80,7 @@ class MediaControllerServer {
 
   JsonCallback command_listener_;
   std::map<std::string, mc_playlist_h> playlist_handle_map_;
+  JsonCallback search_request_listener_;
 
   static void OnPlaybackActionCommand(const char* client_name, const char* request_id,
                                       mc_playback_action_e action, void* user_data);
@@ -91,6 +95,8 @@ class MediaControllerServer {
                                     mc_playback_action_e action, unsigned long long position,
                                     void* user_data);
 
+  static void OnSearchRequestReceived(const char* client_name, const char* request_id,
+                                      mc_search_h request, void* user_data);
   static void OnCommandReceived(const char* client_name, const char* request_id,
                                 const char* command, bundle* data, void* user_data);
 };
index 0814bc8..ebe070c 100644 (file)
@@ -85,7 +85,18 @@ const common::PlatformEnum<mc_content_type_e> MediaControllerContentTypeEnum{
     {"MUSIC", MC_CONTENT_TYPE_MUSIC},
     {"VIDEO", MC_CONTENT_TYPE_VIDEO},
     {"OTHER", MC_CONTENT_TYPE_OTHER},
-    {"UNDECIDED", MC_CONTENT_TYPE_UNDECIDED}};
+    {"UNDECIDED", MC_CONTENT_TYPE_UNDECIDED}
+};
+
+const common::PlatformEnum<mc_search_category_e> MediaControllerSearchCategoryEnum {
+    {"NONE", MC_SEARCH_NO_CATEGORY},
+    {"TITLE", MC_SEARCH_TITLE},
+    {"ARTIST", MC_SEARCH_ARTIST},
+    {"ALBUM", MC_SEARCH_ALBUM},
+    {"GENRE", MC_SEARCH_GENRE},
+    {"TPO", MC_SEARCH_TPO}
+};
+
 
 PlatformResult ConvertPlaybackState(mc_playback_h playback_h, std::string* state) {
   ScopeLogger();
index 80947a5..18fe21b 100644 (file)
@@ -45,6 +45,7 @@ extern const common::PlatformEnum<mc_meta_e> MediaControllerMetadataAttributeEnu
 extern const common::PlatformEnum<mc_repeat_mode_e> MediaControllerRepeatModeEnum;
 extern const common::PlatformEnum<mc_content_age_rating_e> MediaControllerContentAgeRatingEnum;
 extern const common::PlatformEnum<mc_content_type_e> MediaControllerContentTypeEnum;
+extern const common::PlatformEnum<mc_search_category_e> MediaControllerSearchCategoryEnum;
 
 }  // namespace types
 
index 691514e..7b96118 100644 (file)
@@ -514,11 +514,10 @@ function Bundle(arg) {
 
     // copy constructor
     if (arg instanceof tizen.Bundle) {
-      // perform deep copy of the other bundle.
       json = JSON.parse(arg.toString());
     }
     // json to bundle conversion
-    else if (xwalk.utils.type.isObject(json)) {
+    else if (xwalk.utils.type.isObject(arg)) {
       json = arg;
     }