9b46159c77ac82e31463fd4169d84abc185424fa
[platform/core/api/webapi-plugins.git] / src / content / content_instance.cc
1 /*
2  * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16
17 #include "content/content_instance.h"
18
19 #include <glib.h>
20 #include <media_content.h>
21 #include <functional>
22 #include <memory>
23 #include <string>
24
25 #include "common/logger.h"
26 #include "common/picojson.h"
27 #include "common/platform_result.h"
28 #include "common/task-queue.h"
29 #include "common/tools.h"
30
31 #include "common/filesystem/filesystem_provider.h"
32 #include "content/content_manager.h"
33
34 using namespace common;
35
36 namespace extension {
37 namespace content {
38
39 namespace {
40 // The privileges that required in Content API
41 const std::string kPrivilegeContentRead = "http://tizen.org/privilege/content.read";
42 const std::string kPrivilegeContentWrite = "http://tizen.org/privilege/content.write";
43
44 }  // namespace
45
46 using common::tools::ReportSuccess;
47 using common::tools::ReportError;
48 using common::PlatformResult;
49
50 ContentInstance::ContentInstance()
51     : noti_handle_(nullptr),
52       listener_handle_(nullptr),
53       listener_data_(nullptr),
54       callback_data_(nullptr) {
55   ScopeLogger();
56   using std::placeholders::_1;
57   using std::placeholders::_2;
58
59 #define REGISTER_METHOD(M) RegisterSyncHandler(#M, std::bind(&ContentInstance::M, this, _1, _2))
60
61   REGISTER_METHOD(ContentManagerFind);
62   REGISTER_METHOD(ContentManagerUpdate);
63   REGISTER_METHOD(ContentManagerScanfile);
64   REGISTER_METHOD(ContentManagerScanDirectory);
65   REGISTER_METHOD(ContentManagerCancelScanDirectory);
66   REGISTER_METHOD(ContentManagerAddChangeListener);
67   REGISTER_METHOD(ContentManagerRemoveChangeListener);
68   REGISTER_METHOD(ContentManagerUnsetchangelistener);
69   REGISTER_METHOD(ContentManagerSetchangelistener);
70   REGISTER_METHOD(ContentManagerGetdirectories);
71   REGISTER_METHOD(ContentManagerUpdatebatch);
72   REGISTER_METHOD(ContentManagerRemoveplaylist);
73   REGISTER_METHOD(ContentManagerCreateplaylist);
74   REGISTER_METHOD(ContentManagerGetplaylists);
75   REGISTER_METHOD(ContentManagerPlaylistAdd);
76   REGISTER_METHOD(ContentManagerPlaylistAddbatch);
77   REGISTER_METHOD(ContentManagerPlaylistGet);
78   REGISTER_METHOD(ContentManagerPlaylistRemove);
79   REGISTER_METHOD(ContentManagerPlaylistRemovebatch);
80   REGISTER_METHOD(ContentManagerPlaylistSetorder);
81   REGISTER_METHOD(ContentManagerPlaylistMove);
82   REGISTER_METHOD(ContentManagerAudioGetLyrics);
83
84   REGISTER_METHOD(PlaylistGetName);
85   REGISTER_METHOD(PlaylistSetName);
86   REGISTER_METHOD(PlaylistGetThumbnailUri);
87   REGISTER_METHOD(PlaylistSetThumbnailUri);
88   REGISTER_METHOD(PlaylistGetNumberOfTracks);
89   REGISTER_METHOD(ContentManagerCreateThumbnail);
90
91 #undef REGISTER_METHOD
92
93   ContentManager::getInstance()->setContentInstance(this);
94 }
95
96 ContentInstance::~ContentInstance() {
97   ScopeLogger();
98
99   if (noti_handle_) {
100     media_content_remove_db_updated_cb(noti_handle_);
101     noti_handle_ = nullptr;
102   }
103
104   if (listener_handle_) {
105     media_content_remove_db_updated_cb(listener_handle_);
106     listener_handle_ = nullptr;
107   }
108
109   if (listener_data_) {
110     delete listener_data_;
111     listener_data_ = nullptr;
112   }
113
114   if (callback_data_) {
115     delete callback_data_;
116     callback_data_ = nullptr;
117   }
118
119   ContentManager::getInstance()->setContentInstance(nullptr);
120 }
121
122 static gboolean CompletedCallback(const std::shared_ptr<ReplyCallbackData>& user_data) {
123   ScopeLogger();
124
125   picojson::object out;
126   out["callbackId"] = picojson::value(user_data->callbackId);
127
128   if (user_data->isSuccess) {
129     ReportSuccess(user_data->result, out);
130   } else {
131     LogAndReportError(user_data->isSuccess, &out, ("Failed: user_data->isSuccess"));
132   }
133
134   common::Instance::PostMessage(user_data->instance, picojson::value(out).serialize().c_str());
135
136   return false;
137 }
138
139 static void* WorkThread(const std::shared_ptr<ReplyCallbackData>& user_data) {
140   ScopeLogger();
141
142   int ret = MEDIA_CONTENT_ERROR_NONE;
143   ContentCallbacks cbType = user_data->cbType;
144   switch (cbType) {
145     case ContentManagerUpdatebatchCallback: {
146       ret = ContentManager::getInstance()->updateBatch(user_data->args);
147       if (ret != MEDIA_CONTENT_ERROR_NONE) {
148         LoggerD("UpdateBatch Failed");
149         user_data->isSuccess = ContentManager::getInstance()->convertError(ret);
150       }
151       break;
152     }
153     case ContentManagerGetdirectoriesCallback: {
154       ContentManager::getInstance()->getDirectories(user_data);
155       break;
156     }
157     case ContentManagerFindCallback: {
158       ContentManager::getInstance()->find(user_data);
159       break;
160     }
161     case ContentManagerScanfileCallback: {
162       std::string contentURI = user_data->args.get("contentURI").get<std::string>();
163       std::string real_path = common::FilesystemProvider::Create().GetRealPath(contentURI);
164       ret = ContentManager::getInstance()->scanFile(real_path);
165       if (ret != MEDIA_CONTENT_ERROR_NONE) {
166         PlatformResult err =
167             LogAndCreateResult(common::ErrorCode::UNKNOWN_ERR, "Scan file failed.",
168                                ("Scan file failed, error: %d (%s)", ret, get_error_message(ret)));
169         user_data->isSuccess = err;
170       }
171       break;
172     }
173     case ContentManagerGetplaylistsCallback: {
174       ContentManager::getInstance()->getPlaylists(user_data);
175       break;
176     }
177     case ContentManagerCreateplaylistCallback: {
178       if (user_data->args.contains("sourcePlaylist")) {
179         picojson::object playlist = user_data->args.get("sourcePlaylist").get<picojson::object>();
180         user_data->result = picojson::value(playlist);
181       } else {
182         std::string name = user_data->args.get("name").get<std::string>();
183         ContentManager::getInstance()->createPlaylist(name, user_data);
184       }
185       break;
186     }
187     case ContentManagerRemoveplaylistCallback: {
188       std::string id = user_data->args.get("id").get<std::string>();
189       ContentManager::getInstance()->removePlaylist(id, user_data);
190       // do something...
191       break;
192     }
193     case ContentManagerPlaylistAddbatchCallback: {
194       ContentManager::getInstance()->playlistAddbatch(user_data);
195       break;
196     }
197     case ContentManagerPlaylistGetCallback: {
198       ContentManager::getInstance()->playlistGet(user_data);
199       break;
200     }
201     case ContentManagerPlaylistRemovebatchCallback: {
202       ContentManager::getInstance()->playlistRemovebatch(user_data);
203       break;
204     }
205     case ContentManagerPlaylistSetOrderCallback: {
206       ContentManager::getInstance()->playlistSetOrder(user_data);
207       break;
208       // ContentManagerPlaylistSetOrderCallback
209     }
210     case ContentManagerPlaylistMoveCallback: {
211       ContentManager::getInstance()->playlistMove(user_data);
212       break;
213     }
214     case ContentManagerErrorCallback: {
215       common::PlatformResult err =
216           LogAndCreateResult(common::ErrorCode::UNKNOWN_ERR, "DB Connection is failed.");
217       user_data->isSuccess = err;
218       break;
219     }
220     default: {
221       LoggerE("Invalid Callback Type");
222       return NULL;
223     }
224   }
225   return NULL;
226 }
227
228 static void ScanDirectoryCallback(media_content_error_e error, void* user_data) {
229   ScopeLogger();
230
231   ReplyCallbackData* cbData = (ReplyCallbackData*)user_data;
232
233   picojson::object out;
234   out["callbackId"] = picojson::value(cbData->callbackId);
235
236   if (error == MEDIA_CONTENT_ERROR_NONE) {
237     ReportSuccess(out);
238   } else {
239     LoggerE("Scanning directory failed error: %d (%s)", error, get_error_message(error));
240     ReportError(out);
241   }
242
243   common::Instance::PostMessage(cbData->instance, picojson::value(out).serialize().c_str());
244 }
245
246 static void changedContentCallback(media_content_error_e error, int pid,
247                                    media_content_db_update_item_type_e update_item,
248                                    media_content_db_update_type_e update_type,
249                                    media_content_type_e media_type, char* uuid, char* path,
250                                    char* mime_type, void* user_data) {
251   ScopeLogger("Directory change callback");
252
253   if (error != MEDIA_CONTENT_ERROR_NONE) {
254     LoggerE("Media content changed v2 callback error: %d", (int)error);
255     return;
256   }
257
258   if (update_item == MEDIA_ITEM_DIRECTORY) {
259     if (!uuid) {
260       LoggerE("Provided uuid is NULL, ignoring");
261       return;
262     }
263
264     ReplyCallbackData* cbData = static_cast<ReplyCallbackData*>(user_data);
265
266     int ret;
267     picojson::value result = picojson::value(picojson::object());
268     picojson::object& obj = result.get<picojson::object>();
269
270     if (update_type == MEDIA_CONTENT_INSERT || update_type == MEDIA_CONTENT_UPDATE) {
271       media_folder_h folder = NULL;
272       ret = media_folder_get_folder_from_db(uuid, &folder);
273       if (ret == MEDIA_CONTENT_ERROR_NONE && folder != NULL) {
274         picojson::object o;
275
276         ContentDirToJson(folder, o);
277         ReportSuccess(picojson::value(o), obj);
278
279         if (update_type == MEDIA_CONTENT_INSERT) {
280           obj["state"] = picojson::value("oncontentdiradded");
281         } else {
282           obj["state"] = picojson::value("oncontentdirupdated");
283         }
284
285         media_folder_destroy(folder);
286       }
287     } else {
288       ReportSuccess(picojson::value(std::string(uuid)), obj);
289       obj["state"] = picojson::value("oncontentdirremoved");
290     }
291
292     obj["listenerId"] = cbData->args.get("listenerId");
293     common::Instance::PostMessage(cbData->instance, result.serialize().c_str());
294   } else {
295     LoggerD("Media item is not directory, skipping.");
296     return;
297   }
298 }
299
300 static PlatformResult prepareDirectoryChangeResponse(media_content_db_update_type_e update_type,
301                                                      char* uuid, picojson::object& obj) {
302   ScopeLogger("Media item is a directory");
303
304   if (MEDIA_CONTENT_DELETE == update_type) {
305     ReportSuccess(picojson::value(std::string(uuid)), obj);
306     obj["state"] = picojson::value("oncontentdirremoved");
307     return PlatformResult(ErrorCode::NO_ERROR);
308   }
309
310   media_folder_h folder = nullptr;
311   int ret = media_folder_get_folder_from_db(uuid, &folder);
312
313   if (MEDIA_CONTENT_ERROR_NONE != ret || nullptr == folder) {
314     LoggerE("Failed to get media item (media_folder_get_folder_from_db): %d", ret);
315     return PlatformResult(ErrorCode::ABORT_ERR);
316   }
317
318   picojson::object o;
319   ContentDirToJson(folder, o);
320
321   ret = media_folder_destroy(folder);
322
323   if (MEDIA_CONTENT_ERROR_NONE != ret) {
324     LoggerE("Failed to destroy media folder (media_folder_destroy): %d", ret);
325     return PlatformResult(ErrorCode::ABORT_ERR);
326   }
327
328   ReportSuccess(picojson::value(o), obj);
329
330   if (MEDIA_CONTENT_INSERT == update_type) {
331     obj["state"] = picojson::value("oncontentdiradded");
332   } else if (MEDIA_CONTENT_UPDATE == update_type) {
333     obj["state"] = picojson::value("oncontentdirupdated");
334   }
335
336   return PlatformResult(ErrorCode::NO_ERROR);
337 }
338
339 static PlatformResult prepareFileChangeResponse(media_content_db_update_type_e update_type,
340                                                 char* uuid, picojson::object& obj) {
341   ScopeLogger("Media item is a file");
342
343   if (MEDIA_CONTENT_DELETE == update_type) {
344     ReportSuccess(picojson::value(std::string(uuid)), obj);
345     obj["state"] = picojson::value("oncontentremoved");
346     return PlatformResult(ErrorCode::NO_ERROR);
347   }
348
349   media_info_h media = nullptr;
350   int ret = media_info_get_media_from_db(uuid, &media);
351
352   if (MEDIA_CONTENT_ERROR_NONE != ret || nullptr == media) {
353     LoggerE("Failed to get media item (media_info_get_media_from_db): %d", ret);
354     return PlatformResult(ErrorCode::ABORT_ERR);
355   }
356
357   picojson::object o;
358   ContentToJson(media, o);
359
360   ret = media_info_destroy(media);
361
362   if (MEDIA_CONTENT_ERROR_NONE != ret) {
363     LoggerE("Failed to destroy media info (media_info_destroy): %d", ret);
364     return PlatformResult(ErrorCode::ABORT_ERR);
365   }
366
367   ReportSuccess(picojson::value(o), obj);
368
369   if (MEDIA_CONTENT_INSERT == update_type) {
370     obj["state"] = picojson::value("oncontentadded");
371   } else if (MEDIA_CONTENT_UPDATE == update_type) {
372     obj["state"] = picojson::value("oncontentupdated");
373   }
374
375   return PlatformResult(ErrorCode::NO_ERROR);
376 }
377
378 static void contentChangeCallback(media_content_error_e error, int pid,
379                                   media_content_db_update_item_type_e update_item,
380                                   media_content_db_update_type_e update_type,
381                                   media_content_type_e media_type, char* uuid, char* path,
382                                   char* mime_type, void* user_data) {
383   ScopeLogger("directory and file change callback");
384
385   if (MEDIA_CONTENT_ERROR_NONE != error) {
386     LoggerE("Failed to perform contentChangeCallback: %d", error);
387     return;
388   }
389
390   if (!uuid) {
391     LoggerE("Provided uuid is NULL, ignoring");
392     return;
393   }
394
395   if (nullptr == user_data) {
396     LoggerE("Provided user data is NULL, ignoring");
397     return;
398   }
399
400   if (MEDIA_ITEM_DIRECTORY != update_item && MEDIA_ITEM_FILE != update_item) {
401     LoggerD("Media item is not a directory nor a file, skipping");
402     return;
403   }
404
405   ReplyCallbackData* cbData = static_cast<ReplyCallbackData*>(user_data);
406
407   picojson::value result = picojson::value(picojson::object());
408   picojson::object& obj = result.get<picojson::object>();
409
410   PlatformResult ret(ErrorCode::NO_ERROR);
411   if (MEDIA_ITEM_DIRECTORY == update_item) {
412     ret = prepareDirectoryChangeResponse(update_type, uuid, obj);
413   } else if (MEDIA_ITEM_FILE == update_item) {
414     ret = prepareFileChangeResponse(update_type, uuid, obj);
415   }
416
417   if (ret.IsSuccess()) {
418     obj["listenerId"] = picojson::value("ContentManagerChangeCallback");
419     Instance::PostMessage(cbData->instance, result.serialize().c_str());
420   } else {
421     LoggerD("Failed to prepare content change callback, ignoring");
422   }
423 }
424
425 #define CHECK_EXIST(args, name, out)                                               \
426   if (!args.contains(name)) {                                                      \
427     LogAndReportError(common::PlatformResult(common::ErrorCode::TYPE_MISMATCH_ERR, \
428                                              (name " is required argument")),      \
429                       &out);                                                       \
430     return;                                                                        \
431   }
432
433 void ContentInstance::ContentManagerUpdate(const picojson::value& args, picojson::object& out) {
434   ScopeLogger();
435   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
436
437   if (ContentManager::getInstance()->isConnected()) {
438     int ret = ContentManager::getInstance()->update(args);
439     if (ret != 0) {
440       LogAndReportError(ContentManager::getInstance()->convertError(ret), &out);
441     }
442   } else {
443     LogAndReportError(
444         common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, "DB connection is failed."), &out);
445   }
446 }
447
448 void ContentInstance::ContentManagerUpdatebatch(const picojson::value& args,
449                                                 picojson::object& out) {
450   ScopeLogger();
451   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
452   double callbackId = args.get("callbackId").get<double>();
453
454   auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
455   cbData->callbackId = callbackId;
456   cbData->instance = this;
457   cbData->args = args;
458
459   if (ContentManager::getInstance()->isConnected()) {
460     cbData->cbType = ContentManagerUpdatebatchCallback;
461   } else {
462     cbData->cbType = ContentManagerErrorCallback;
463   }
464   common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
465 }
466 void ContentInstance::ContentManagerGetdirectories(const picojson::value& args,
467                                                    picojson::object& out) {
468   ScopeLogger();
469   CHECK_EXIST(args, "callbackId", out)
470
471   double callbackId = args.get("callbackId").get<double>();
472   // implement it
473
474   auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
475   cbData->callbackId = callbackId;
476   cbData->instance = this;
477
478   if (ContentManager::getInstance()->isConnected()) {
479     cbData->cbType = ContentManagerGetdirectoriesCallback;
480   } else {
481     cbData->cbType = ContentManagerErrorCallback;
482   }
483   common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
484 }
485 void ContentInstance::ContentManagerFind(const picojson::value& args, picojson::object& out) {
486   ScopeLogger();
487   // CHECK_PRIVILEGE_ACCESS(kPrivilegeContentRead, &out);
488   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
489
490   CHECK_EXIST(args, "callbackId", out)
491
492   double callbackId = args.get("callbackId").get<double>();
493
494   auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
495   cbData->callbackId = callbackId;
496   cbData->instance = this;
497   cbData->args = args;
498   if (ContentManager::getInstance()->isConnected()) {
499     cbData->cbType = ContentManagerFindCallback;
500   } else {
501     cbData->cbType = ContentManagerErrorCallback;
502   }
503
504   common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
505 }
506
507 void ContentInstance::ContentManagerScanfile(const picojson::value& args, picojson::object& out) {
508   ScopeLogger();
509   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
510
511   CHECK_EXIST(args, "callbackId", out)
512   CHECK_EXIST(args, "contentURI", out)
513
514   const std::string& contentURI = args.get("contentURI").get<std::string>();
515   const std::string& real_path = common::FilesystemProvider::Create().GetRealPath(contentURI);
516
517   CHECK_STORAGE_ACCESS(real_path, &out);
518
519   double callbackId = args.get("callbackId").get<double>();
520   auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
521   cbData->callbackId = callbackId;
522   cbData->instance = this;
523   cbData->args = args;
524   if (ContentManager::getInstance()->isConnected()) {
525     cbData->cbType = ContentManagerScanfileCallback;
526   } else {
527     cbData->cbType = ContentManagerErrorCallback;
528   }
529   common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
530 }
531
532 void ContentInstance::ContentManagerScanDirectory(const picojson::value& args,
533                                                   picojson::object& out) {
534   ScopeLogger();
535   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
536
537   CHECK_EXIST(args, "callbackId", out)
538   CHECK_EXIST(args, "contentDirURI", out)
539   CHECK_EXIST(args, "recursive", out)
540
541   const std::string& contentURI = args.get("contentDirURI").get<std::string>();
542   const std::string& real_path = common::FilesystemProvider::Create().GetRealPath(contentURI);
543
544   CHECK_STORAGE_ACCESS(real_path, &out);
545
546   ReplyCallbackData* cbData = new ReplyCallbackData;
547   cbData->callbackId = args.get("callbackId").get<double>();
548   cbData->instance = this;
549   cbData->args = args;
550
551   common::PlatformResult result =
552       ContentManager::getInstance()->scanDirectory(ScanDirectoryCallback, cbData);
553   if (result.IsError()) {
554     LogAndReportError(result, &out);
555   }
556 }
557
558 void ContentInstance::ContentManagerCancelScanDirectory(const picojson::value& args,
559                                                         picojson::object& out) {
560   ScopeLogger();
561   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
562
563   CHECK_EXIST(args, "contentDirURI", out)
564   const std::string& content_dir_uri = args.get("contentDirURI").get<std::string>();
565
566   if (ContentManager::getInstance()->cancelScanDirectory(content_dir_uri).IsError()) {
567     LogAndReportError(
568         common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, "Cancel scan directory failed"),
569         &out);
570   }
571 }
572
573 void ContentInstance::ContentManagerAddChangeListener(const picojson::value& args,
574                                                       picojson::object& out) {
575   ScopeLogger();
576
577   callback_data_ = new ReplyCallbackData();
578   callback_data_->instance = this;
579   callback_data_->args = args;
580
581   if (ContentManager::getInstance()->isConnected()) {
582     callback_data_->cbType = ContentManagerAddChangeListenerCallback;
583   } else {
584     callback_data_->cbType = ContentManagerErrorCallback;
585   }
586
587   PlatformResult result = ContentManager::getInstance()->addChangeListener(
588       &listener_handle_, contentChangeCallback, static_cast<void*>(callback_data_));
589
590   if (result.IsError()) {
591     delete callback_data_;
592     callback_data_ = nullptr;
593     LogAndReportError(result, &out);
594   }
595 }
596
597 void ContentInstance::ContentManagerRemoveChangeListener(const picojson::value& args,
598                                                          picojson::object& out) {
599   ScopeLogger();
600
601   PlatformResult result = ContentManager::getInstance()->removeChangeListener(listener_handle_);
602
603   if (result.IsSuccess()) {
604     listener_handle_ = nullptr;
605     delete callback_data_;
606     callback_data_ = nullptr;
607   } else {
608     LogAndReportError(result, &out);
609   }
610 }
611
612 void ContentInstance::ContentManagerSetchangelistener(const picojson::value& args,
613                                                       picojson::object& out) {
614   ScopeLogger();
615   DEPRECATION_WARN(
616       "setChangeListener() is deprecated and will be removed from next "
617       "release. Use addChangeListener() instead.",
618       "3.0");
619   // CHECK_PRIVILEGE_ACCESS(kPrivilegeContentRead, &out);
620   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
621
622   CHECK_EXIST(args, "listenerId", out)
623
624   if (!listener_data_) {
625     listener_data_ = new ReplyCallbackData();
626   }
627
628   listener_data_->instance = this;
629   listener_data_->args = args;
630   if (ContentManager::getInstance()->isConnected()) {
631     listener_data_->cbType = ContentManagerSetchangelistenerCallback;
632   } else {
633     listener_data_->cbType = ContentManagerErrorCallback;
634   }
635
636   if (nullptr == noti_handle_) {  // To remain consistency with the previous implementation
637     if (ContentManager::getInstance()
638             ->addChangeListener(&noti_handle_, changedContentCallback,
639                                 static_cast<void*>(listener_data_))
640             .IsError()) {
641       LogAndReportError(common::PlatformResult(common::ErrorCode::UNKNOWN_ERR,
642                                                "The callback did not register properly"),
643                         &out);
644     }
645   }
646 }
647
648 void ContentInstance::ContentManagerUnsetchangelistener(const picojson::value& args,
649                                                         picojson::object& out) {
650   ScopeLogger();
651   DEPRECATION_WARN(
652       "unsetChangeListener() is deprecated and will be removed from next "
653       "release. Use removeChangeListener() instead.",
654       "3.0");
655   // CHECK_PRIVILEGE_ACCESS(kPrivilegeContentRead, &out);
656   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
657
658   if (ContentManager::getInstance()->removeChangeListener(noti_handle_).IsError()) {
659     LoggerD("unsuccesfull deregistering of callback");
660   } else {
661     noti_handle_ = nullptr;  // To remain consistency with the previous implementation
662   }
663 }
664
665 void ContentInstance::ContentManagerGetplaylists(const picojson::value& args,
666                                                  picojson::object& out) {
667   ScopeLogger();
668   // CHECK_PRIVILEGE_ACCESS(kPrivilegeContentRead, &out);
669   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
670
671   CHECK_EXIST(args, "callbackId", out)
672
673   double callbackId = args.get("callbackId").get<double>();
674
675   // implement it
676   std::shared_ptr<ReplyCallbackData> cbData(new ReplyCallbackData);
677
678   cbData->callbackId = callbackId;
679   cbData->instance = this;
680   cbData->args = args;
681   if (ContentManager::getInstance()->isConnected()) {
682     cbData->cbType = ContentManagerGetplaylistsCallback;
683   } else {
684     cbData->cbType = ContentManagerErrorCallback;
685   }
686
687   common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
688 }
689 void ContentInstance::ContentManagerCreateplaylist(const picojson::value& args,
690                                                    picojson::object& out) {
691   ScopeLogger();
692   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
693
694   CHECK_EXIST(args, "callbackId", out)
695   CHECK_EXIST(args, "name", out)
696
697   double callbackId = args.get("callbackId").get<double>();
698
699   auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
700   cbData->callbackId = callbackId;
701   cbData->instance = this;
702   cbData->args = args;
703
704   if (ContentManager::getInstance()->isConnected()) {
705     cbData->cbType = ContentManagerCreateplaylistCallback;
706   } else {
707     cbData->cbType = ContentManagerErrorCallback;
708   }
709
710   common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
711 }
712 void ContentInstance::ContentManagerRemoveplaylist(const picojson::value& args,
713                                                    picojson::object& out) {
714   ScopeLogger();
715   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
716
717   double callbackId = args.get("callbackId").get<double>();
718
719   auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
720   cbData->callbackId = callbackId;
721   cbData->instance = this;
722   cbData->args = args;
723
724   if (ContentManager::getInstance()->isConnected()) {
725     cbData->cbType = ContentManagerRemoveplaylistCallback;
726   } else {
727     cbData->cbType = ContentManagerErrorCallback;
728   }
729
730   // implement it
731   common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
732 }
733
734 void ContentInstance::ContentManagerCreateThumbnail(const picojson::value& args,
735                                                     picojson::object& out) {
736   ScopeLogger();
737   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
738   double callback_id = args.get("callbackId").get<double>();
739
740   if (not ContentManager::getInstance()->isConnected()) {
741     TaskQueue::GetInstance().Async([this, callback_id]() {
742       PlatformResult result =
743           LogAndCreateResult(common::ErrorCode::ABORT_ERR, "DB Connection is not established.");
744       picojson::value response = picojson::value(picojson::object());
745       picojson::object& obj = response.get<picojson::object>();
746       obj.emplace("callbackId", picojson::value(callback_id));
747       LogAndReportError(result, &obj, ("DB Connection is not established."));
748       Instance::PostMessage(this, response.serialize().c_str());
749     });
750     return;
751   }
752
753   const std::string& id = args.get("id").get<std::string>();
754   auto work = [this, id, callback_id]() {
755     ScopeLogger();
756     picojson::value response = picojson::value(picojson::object());
757     picojson::object& obj = response.get<picojson::object>();
758     obj.emplace("callbackId", picojson::value(callback_id));
759     auto result = ContentManager::getInstance()->createThumbnail(id, &obj);
760     if (result) {
761       ReportSuccess(obj);
762     } else {
763       LogAndReportError(result, &obj);
764     }
765     Instance::PostMessage(this, response.serialize().c_str());
766   };
767   TaskQueue::GetInstance().Async(work);
768   ReportSuccess(out);
769 }
770
771 void ContentInstance::ContentManagerPlaylistAdd(const picojson::value& args,
772                                                 picojson::object& out) {
773   ScopeLogger();
774   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
775
776   if (ContentManager::getInstance()->isConnected()) {
777     std::string playlist_id = args.get("playlistId").get<std::string>();
778     std::string content_id = args.get("contentId").get<std::string>();
779     int ret = ContentManager::getInstance()->playlistAdd(playlist_id, content_id);
780     if (ret != MEDIA_CONTENT_ERROR_NONE) {
781       LogAndReportError(ContentManager::getInstance()->convertError(ret), &out);
782     }
783   } else {
784     LogAndReportError(
785         common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, "DB connection is failed."), &out);
786   }
787 }
788
789 void ContentInstance::ContentManagerPlaylistAddbatch(const picojson::value& args,
790                                                      picojson::object& out) {
791   ScopeLogger();
792   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
793
794   double callbackId = args.get("callbackId").get<double>();
795
796   auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
797   cbData->callbackId = callbackId;
798   cbData->instance = this;
799   cbData->args = args;
800
801   if (ContentManager::getInstance()->isConnected()) {
802     cbData->cbType = ContentManagerPlaylistAddbatchCallback;
803   } else {
804     cbData->cbType = ContentManagerErrorCallback;
805   }
806   common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
807 }
808
809 void ContentInstance::ContentManagerPlaylistGet(const picojson::value& args,
810                                                 picojson::object& out) {
811   ScopeLogger();
812   // CHECK_PRIVILEGE_ACCESS(kPrivilegeContentRead, &out);
813   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
814
815   double callbackId = args.get("callbackId").get<double>();
816
817   auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
818   cbData->callbackId = callbackId;
819   cbData->instance = this;
820   cbData->args = args;
821
822   if (ContentManager::getInstance()->isConnected()) {
823     cbData->cbType = ContentManagerPlaylistGetCallback;
824   } else {
825     cbData->cbType = ContentManagerErrorCallback;
826   }
827   common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
828 }
829
830 void ContentInstance::ContentManagerPlaylistRemove(const picojson::value& args,
831                                                    picojson::object& out) {
832   ScopeLogger();
833   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
834
835   if (ContentManager::getInstance()->isConnected()) {
836     std::string playlist_id = args.get("playlistId").get<std::string>();
837     int member_id = args.get("memberId").get<double>();
838     int ret = ContentManager::getInstance()->playlistRemove(playlist_id, member_id);
839     if (ret != MEDIA_CONTENT_ERROR_NONE) {
840       LogAndReportError(ContentManager::getInstance()->convertError(ret), &out);
841     }
842   } else {
843     LogAndReportError(
844         common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, "DB connection is failed."), &out);
845   }
846 }
847
848 void ContentInstance::ContentManagerPlaylistRemovebatch(const picojson::value& args,
849                                                         picojson::object& out) {
850   ScopeLogger();
851   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
852
853   double callbackId = args.get("callbackId").get<double>();
854
855   auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
856   cbData->callbackId = callbackId;
857   cbData->instance = this;
858   cbData->args = args;
859
860   if (ContentManager::getInstance()->isConnected()) {
861     cbData->cbType = ContentManagerPlaylistRemovebatchCallback;
862   } else {
863     cbData->cbType = ContentManagerErrorCallback;
864   }
865   common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
866 }
867
868 void ContentInstance::ContentManagerPlaylistSetorder(const picojson::value& args,
869                                                      picojson::object& out) {
870   ScopeLogger();
871   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
872
873   double callbackId = args.get("callbackId").get<double>();
874
875   auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
876   cbData->callbackId = callbackId;
877   cbData->instance = this;
878   cbData->args = args;
879
880   if (ContentManager::getInstance()->isConnected()) {
881     cbData->cbType = ContentManagerPlaylistSetOrderCallback;
882   } else {
883     cbData->cbType = ContentManagerErrorCallback;
884   }
885   common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
886 }
887
888 void ContentInstance::ContentManagerPlaylistMove(const picojson::value& args,
889                                                  picojson::object& out) {
890   ScopeLogger();
891   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
892
893   double callbackId = args.get("callbackId").get<double>();
894
895   auto cbData = std::shared_ptr<ReplyCallbackData>(new ReplyCallbackData);
896   cbData->callbackId = callbackId;
897   cbData->instance = this;
898   cbData->args = args;
899
900   if (ContentManager::getInstance()->isConnected()) {
901     cbData->cbType = ContentManagerPlaylistMoveCallback;
902   } else {
903     cbData->cbType = ContentManagerErrorCallback;
904   }
905   common::TaskQueue::GetInstance().Queue<ReplyCallbackData>(WorkThread, CompletedCallback, cbData);
906 }
907
908 void ContentInstance::ContentManagerAudioGetLyrics(const picojson::value& args,
909                                                    picojson::object& out) {
910   ScopeLogger();
911
912   const std::string& contentURI = args.get("contentURI").get<std::string>();
913   const std::string& real_path = common::FilesystemProvider::Create().GetRealPath(contentURI);
914
915   CHECK_STORAGE_ACCESS(real_path, &out);
916
917   picojson::object lyrics;
918   if (ContentManager::getInstance()->isConnected()) {
919     int ret = ContentManager::getInstance()->getLyrics(args, lyrics);
920     if (ret != MEDIA_CONTENT_ERROR_NONE) {
921       LogAndReportError(ContentManager::getInstance()->convertError(ret), &out);
922     } else {
923       ReportSuccess(picojson::value(lyrics), out);
924     }
925   } else {
926     LogAndReportError(
927         common::PlatformResult(common::ErrorCode::UNKNOWN_ERR, "DB connection is failed."), &out);
928   }
929 }
930
931 void ContentInstance::PlaylistGetName(const picojson::value& args, picojson::object& out) {
932   ScopeLogger();
933   int ret;
934   CHECK_EXIST(args, "id", out)
935   int id = static_cast<int>(args.get("id").get<double>());
936   std::string name;
937   ret = ContentManager::getInstance()->getPlaylistName(id, &name);
938   if (ret != MEDIA_CONTENT_ERROR_NONE) {
939     LogAndReportError(ContentManager::getInstance()->convertError(ret), &out);
940   } else {
941     ReportSuccess(picojson::value(name), out);
942   }
943 }
944
945 void ContentInstance::PlaylistSetName(const picojson::value& args, picojson::object& out) {
946   ScopeLogger();
947   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
948
949   int ret;
950   CHECK_EXIST(args, "id", out)
951   CHECK_EXIST(args, "name", out)
952   int id = static_cast<int>(args.get("id").get<double>());
953   std::string name = args.get("name").get<std::string>();
954   ret = ContentManager::getInstance()->setPlaylistName(id, name);
955   if (ret != MEDIA_CONTENT_ERROR_NONE) {
956     LogAndReportError(ContentManager::getInstance()->convertError(ret), &out);
957   } else {
958     ReportSuccess(out);
959   }
960 }
961
962 void ContentInstance::PlaylistGetThumbnailUri(const picojson::value& args, picojson::object& out) {
963   ScopeLogger();
964   int ret;
965   CHECK_EXIST(args, "id", out)
966   int id = static_cast<int>(args.get("id").get<double>());
967   std::string uri;
968   ret = ContentManager::getInstance()->getThumbnailUri(id, &uri);
969   if (ret != MEDIA_CONTENT_ERROR_NONE) {
970     LogAndReportError(ContentManager::getInstance()->convertError(ret), &out);
971   } else {
972     ReportSuccess(picojson::value(uri), out);
973   }
974 }
975
976 void ContentInstance::PlaylistSetThumbnailUri(const picojson::value& args, picojson::object& out) {
977   ScopeLogger();
978   CHECK_PRIVILEGE_ACCESS(kPrivilegeContentWrite, &out);
979
980   int ret;
981   CHECK_EXIST(args, "id", out)
982   CHECK_EXIST(args, "uri", out)
983   int id = static_cast<int>(args.get("id").get<double>());
984   std::string uri = args.get("uri").get<std::string>();
985   const std::string& real_path = common::FilesystemProvider::Create().GetRealPath(uri);
986
987   CHECK_STORAGE_ACCESS(real_path, &out);
988
989   ret = ContentManager::getInstance()->setThumbnailUri(id, uri);
990   if (ret != MEDIA_CONTENT_ERROR_NONE) {
991     LogAndReportError(ContentManager::getInstance()->convertError(ret), &out);
992   } else {
993     ReportSuccess(out);
994   }
995 }
996
997 void ContentInstance::PlaylistGetNumberOfTracks(const picojson::value& args,
998                                                 picojson::object& out) {
999   ScopeLogger();
1000   CHECK_EXIST(args, "id", out)
1001   int id = static_cast<int>(args.get("id").get<double>());
1002   int count = 0;
1003   int ret = ContentManager::getInstance()->getNumberOfTracks(id, &count);
1004   if (ret != MEDIA_CONTENT_ERROR_NONE) {
1005     LogAndReportError(ContentManager::getInstance()->convertError(ret), &out);
1006   } else {
1007     ReportSuccess(picojson::value(static_cast<double>(count)), out);
1008   }
1009 }
1010
1011 #undef CHECK_EXIST
1012
1013 }  // namespace content
1014 }  // namespace extension